From 4c4f7599c93717c7e71302a433be993283932a2a Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Thu, 18 Apr 2024 17:16:33 +0200 Subject: [PATCH] replace the docs! --- docs/.buildinfo | 4 + docs/.nojekyll | 0 docs/CONTRIBUTING.html | 653 + docs/README.html | 747 ++ .../4_adding_a_dataset.py | 174 + .../noplot_phmd_ml_spectrum.ipynb | 108 + .../auto_examples_python.zip | Bin 0 -> 125174 bytes .../plot_within_session_ssvep.py | 113 + .../plot_braindecode.ipynb | 133 + .../plot_benchmark_DL.py | 128 + .../plot_disk_cache.ipynb | 263 + .../noplot_bids_conversion.ipynb | 169 + .../plot_learning_curve_p300_external.py | 149 + .../example_codecarbon.py | 122 + .../plot_benchmark.ipynb | 126 + .../plot_benchmark_braindecode.py | 122 + .../plot_fixed_interval_windows.ipynb | 180 + .../plot_within_session_p300.ipynb | 144 + .../plot_statistical_analysis.ipynb | 180 + .../plot_learning_curve_p300.ipynb | 126 + .../plot_cross_subject_ssvep.ipynb | 234 + .../plot_within_session_p300.py | 117 + .../plot_mne_and_scikit_estimators.py | 199 + ...oplot_tutorial_5_build_a_custom_dataset.py | 122 + ...plot_cross_session_multiple_datasets.ipynb | 162 + .../plot_benchmark_grid_search.ipynb | 90 + ...ot_tutorial_5_build_a_custom_dataset.ipynb | 126 + .../plot_filterbank_csp_vs_csp.py | 129 + .../tutorial_2_using_mulitple_datasets.ipynb | 108 + .../plot_benchmark_DL.ipynb | 97 + .../noplot_vr_pc_p300_different_epoch_size.py | 149 + .../plot_cross_subject_ssvep.py | 180 + .../plot_Getting_Started.py | 119 + .../plot_benchmark.py | 102 + .../plot_learning_curve_motor_imagery.ipynb | 108 + ...al_3_benchmarking_multiple_pipelines.ipynb | 115 + .../plot_select_electrodes_resample.ipynb | 144 + .../auto_examples_jupyter.zip | Bin 0 -> 179505 bytes ...plot_vr_pc_p300_different_epoch_size.ipynb | 108 + .../load_model.ipynb | 126 + .../plot_benchmark_braindecode.ipynb | 97 + .../plot_cross_session_motor_imagery.py | 127 + .../plot_learning_curve_motor_imagery.py | 121 + .../plot_select_electrodes_resample.py | 90 + .../load_model.py | 111 + .../changing_download_directory.py | 37 + .../auto_tutorials_jupyter.zip | Bin 0 -> 41030 bytes .../noplot_bids_conversion.py | 134 + .../plot_explore_paradigm.py | 147 + ...orial_1_simple_example_motor_imagery.ipynb | 288 + .../plot_learning_curve_p300.py | 126 + .../tutorial_2_using_mulitple_datasets.py | 76 + .../plot_benchmark_grid_search.py | 67 + .../plot_grid_search_withinsession.py | 175 + ...tutorial_1_simple_example_motor_imagery.py | 171 + .../noplot_phmd_ml_spectrum.py | 71 + .../plot_mne_and_scikit_estimators.ipynb | 216 + .../plot_grid_search_withinsession.ipynb | 144 + .../plot_explore_paradigm.ipynb | 288 + .../changing_download_directory.ipynb | 108 + .../plot_Getting_Started.ipynb | 234 + .../plot_braindecode.py | 152 + .../auto_tutorials_python.zip | Bin 0 -> 27850 bytes .../plot_filterbank_csp_vs_csp.ipynb | 126 + .../plot_disk_cache.py | 264 + .../plot_learning_curve_p300_external.ipynb | 108 + .../plot_cross_session_motor_imagery.ipynb | 108 + .../4_adding_a_dataset.ipynb | 133 + .../plot_within_session_ssvep.ipynb | 180 + .../example_codecarbon.ipynb | 151 + .../plot_cross_session_multiple_datasets.py | 118 + .../plot_fixed_interval_windows.py | 128 + .../plot_statistical_analysis.py | 138 + ...orial_3_benchmarking_multiple_pipelines.py | 93 + docs/_images/architecture.png | Bin 0 -> 159821 bytes docs/_images/example_codecarbon.png | Bin 0 -> 35627 bytes docs/_images/moabb_install.png | Bin 0 -> 59980 bytes .../sphx_glr_4_adding_a_dataset_thumb.png | Bin 0 -> 10252 bytes ..._glr_changing_download_directory_thumb.png | Bin 0 -> 10252 bytes .../sphx_glr_example_codecarbon_thumb.png | Bin 0 -> 10252 bytes docs/_images/sphx_glr_load_model_thumb.png | Bin 0 -> 10252 bytes .../sphx_glr_noplot_bids_conversion_thumb.png | Bin 0 -> 10252 bytes ...sphx_glr_noplot_phmd_ml_spectrum_thumb.png | Bin 0 -> 10252 bytes ...utorial_5_build_a_custom_dataset_thumb.png | Bin 0 -> 10252 bytes ..._vr_pc_p300_different_epoch_size_thumb.png | Bin 0 -> 10252 bytes .../sphx_glr_plot_Getting_Started_thumb.png | Bin 0 -> 10252 bytes docs/_images/sphx_glr_plot_benchmark_001.png | Bin 0 -> 26587 bytes .../sphx_glr_plot_benchmark_DL_001.png | Bin 0 -> 38917 bytes .../sphx_glr_plot_benchmark_DL_thumb.png | Bin 0 -> 12822 bytes ...phx_glr_plot_benchmark_braindecode_001.png | Bin 0 -> 35883 bytes ...x_glr_plot_benchmark_braindecode_thumb.png | Bin 0 -> 12282 bytes ...phx_glr_plot_benchmark_grid_search_001.png | Bin 0 -> 26565 bytes ...x_glr_plot_benchmark_grid_search_thumb.png | Bin 0 -> 9476 bytes .../_images/sphx_glr_plot_benchmark_thumb.png | Bin 0 -> 9353 bytes .../_images/sphx_glr_plot_braindecode_001.png | Bin 0 -> 8761 bytes .../sphx_glr_plot_braindecode_thumb.png | Bin 0 -> 6081 bytes ...r_plot_cross_session_motor_imagery_001.png | Bin 0 -> 23598 bytes ...plot_cross_session_motor_imagery_thumb.png | Bin 0 -> 12811 bytes ...ot_cross_session_multiple_datasets_001.png | Bin 0 -> 17676 bytes ..._cross_session_multiple_datasets_thumb.png | Bin 0 -> 9705 bytes .../sphx_glr_plot_cross_subject_ssvep_001.png | Bin 0 -> 14978 bytes ...phx_glr_plot_cross_subject_ssvep_thumb.png | Bin 0 -> 9142 bytes .../sphx_glr_plot_disk_cache_thumb.png | Bin 0 -> 10252 bytes .../sphx_glr_plot_explore_paradigm_thumb.png | Bin 0 -> 10252 bytes ...phx_glr_plot_filterbank_csp_vs_csp_001.png | Bin 0 -> 24975 bytes ...x_glr_plot_filterbank_csp_vs_csp_thumb.png | Bin 0 -> 13519 bytes ...hx_glr_plot_fixed_interval_windows_001.png | Bin 0 -> 18776 bytes ..._glr_plot_fixed_interval_windows_thumb.png | Bin 0 -> 18870 bytes ...glr_plot_grid_search_withinsession_001.png | Bin 0 -> 17116 bytes ...r_plot_grid_search_withinsession_thumb.png | Bin 0 -> 9276 bytes ..._plot_learning_curve_motor_imagery_001.png | Bin 0 -> 35136 bytes ...lot_learning_curve_motor_imagery_thumb.png | Bin 0 -> 21333 bytes .../sphx_glr_plot_learning_curve_p300_001.png | Bin 0 -> 39868 bytes ..._plot_learning_curve_p300_external_001.png | Bin 0 -> 48265 bytes ...lot_learning_curve_p300_external_thumb.png | Bin 0 -> 28685 bytes ...phx_glr_plot_learning_curve_p300_thumb.png | Bin 0 -> 22177 bytes ...glr_plot_mne_and_scikit_estimators_001.png | Bin 0 -> 32074 bytes ...glr_plot_mne_and_scikit_estimators_002.png | Bin 0 -> 20676 bytes ...r_plot_mne_and_scikit_estimators_thumb.png | Bin 0 -> 13324 bytes ...lr_plot_select_electrodes_resample_001.png | Bin 0 -> 31498 bytes ..._plot_select_electrodes_resample_thumb.png | Bin 0 -> 8474 bytes ...sphx_glr_plot_statistical_analysis_001.png | Bin 0 -> 29601 bytes ...sphx_glr_plot_statistical_analysis_002.png | Bin 0 -> 32200 bytes ...sphx_glr_plot_statistical_analysis_003.png | Bin 0 -> 19563 bytes ...sphx_glr_plot_statistical_analysis_004.png | Bin 0 -> 27804 bytes ...hx_glr_plot_statistical_analysis_thumb.png | Bin 0 -> 14925 bytes .../sphx_glr_plot_within_session_p300_001.png | Bin 0 -> 12924 bytes ...phx_glr_plot_within_session_p300_thumb.png | Bin 0 -> 7224 bytes ...sphx_glr_plot_within_session_ssvep_001.png | Bin 0 -> 11613 bytes ...sphx_glr_plot_within_session_ssvep_002.png | Bin 0 -> 12031 bytes ...hx_glr_plot_within_session_ssvep_thumb.png | Bin 0 -> 7749 bytes ...ial_1_simple_example_motor_imagery_001.png | Bin 0 -> 12108 bytes ...l_1_simple_example_motor_imagery_thumb.png | Bin 0 -> 5876 bytes ...tutorial_2_using_mulitple_datasets_001.png | Bin 0 -> 13843 bytes ...torial_2_using_mulitple_datasets_thumb.png | Bin 0 -> 7751 bytes ..._3_benchmarking_multiple_pipelines_001.png | Bin 0 -> 25204 bytes ..._benchmarking_multiple_pipelines_thumb.png | Bin 0 -> 8993 bytes ...e.4045f2051d55cab465a707391d5b2007.min.css | 1 + docs/_sphinx_design_static/design-tabs.js | 27 + docs/_static/M.png | Bin 0 -> 13411 bytes .../_sphinx_javascript_frameworks_compat.js | 134 + docs/_static/basic.css | 900 ++ docs/_static/binder_badge_logo.svg | 1 + docs/_static/broken_example.png | Bin 0 -> 21404 bytes docs/_static/check-solid.svg | 4 + docs/_static/clipboard.min.js | 7 + docs/_static/copy-button.svg | 5 + docs/_static/copybutton.css | 81 + docs/_static/copybutton.js | 197 + docs/_static/copybutton_funcs.js | 58 + docs/_static/css/custom.css | 10 + ...e.4045f2051d55cab465a707391d5b2007.min.css | 1 + docs/_static/design-tabs.js | 27 + docs/_static/doctools.js | 156 + docs/_static/documentation_options.js | 14 + docs/_static/file.png | Bin 0 -> 286 bytes docs/_static/jquery-3.6.0.js | 10881 ++++++++++++++++ docs/_static/jquery.js | 2 + docs/_static/language_data.js | 199 + docs/_static/minus.png | Bin 0 -> 90 bytes docs/_static/moabb_install.png | Bin 0 -> 59980 bytes docs/_static/moabb_logo.png | Bin 0 -> 13411 bytes docs/_static/moabb_logo.svg | 77 + docs/_static/no_image.png | Bin 0 -> 4315 bytes docs/_static/placeholder.css | 0 docs/_static/plus.png | Bin 0 -> 90 bytes docs/_static/pygments.css | 151 + docs/_static/scripts/bootstrap.js | 3 + docs/_static/scripts/bootstrap.js.LICENSE.txt | 5 + docs/_static/scripts/bootstrap.js.map | 1 + docs/_static/scripts/pydata-sphinx-theme.js | 2 + .../scripts/pydata-sphinx-theme.js.map | 1 + docs/_static/searchtools.js | 566 + docs/_static/sg_gallery-binder.css | 6 + docs/_static/sg_gallery-dataframe.css | 46 + docs/_static/sg_gallery-rendered-html.css | 224 + docs/_static/sg_gallery.css | 342 + docs/_static/sphinx_highlight.js | 144 + docs/_static/styles/bootstrap.css | 6 + docs/_static/styles/pydata-sphinx-theme.css | 1 + docs/_static/styles/theme.css | 2 + docs/_static/underscore-1.13.1.js | 2042 +++ docs/_static/underscore.js | 6 + .../vendor/fontawesome/6.1.2/LICENSE.txt | 165 + .../vendor/fontawesome/6.1.2/css/all.min.css | 5 + .../6.1.2/webfonts/fa-brands-400.ttf | Bin 0 -> 181264 bytes .../6.1.2/webfonts/fa-brands-400.woff2 | Bin 0 -> 105112 bytes .../6.1.2/webfonts/fa-regular-400.ttf | Bin 0 -> 60236 bytes .../6.1.2/webfonts/fa-regular-400.woff2 | Bin 0 -> 24028 bytes .../6.1.2/webfonts/fa-solid-900.ttf | Bin 0 -> 389948 bytes .../6.1.2/webfonts/fa-solid-900.woff2 | Bin 0 -> 154840 bytes .../6.1.2/webfonts/fa-v4compatibility.ttf | Bin 0 -> 10084 bytes .../6.1.2/webfonts/fa-v4compatibility.woff2 | Bin 0 -> 4776 bytes docs/_static/webpack-macros.html | 30 + docs/analysis.html | 581 + docs/api.html | 1343 ++ .../advanced_examples/index.html | 745 ++ .../plot_filterbank_csp_vs_csp.html | 886 ++ .../plot_grid_search_withinsession.html | 993 ++ .../plot_mne_and_scikit_estimators.html | 1102 ++ .../plot_select_electrodes_resample.html | 1211 ++ .../plot_statistical_analysis.html | 1090 ++ .../advanced_examples/sg_execution_times.html | 546 + .../changing_download_directory.html | 766 ++ docs/auto_examples/example_codecarbon.html | 863 ++ docs/auto_examples/external/index.html | 728 ++ .../plot_learning_curve_p300_external.html | 1105 ++ .../external/sg_execution_times.html | 530 + docs/auto_examples/index.html | 865 ++ docs/auto_examples/learning_curve/index.html | 735 ++ .../plot_learning_curve_motor_imagery.html | 931 ++ .../plot_learning_curve_p300.html | 1032 ++ .../learning_curve/sg_execution_times.html | 534 + docs/auto_examples/load_model.html | 839 ++ .../auto_examples/noplot_bids_conversion.html | 884 ++ .../noplot_phmd_ml_spectrum.html | 823 ++ ...oplot_vr_pc_p300_different_epoch_size.html | 897 ++ docs/auto_examples/plot_benchmark.html | 1158 ++ docs/auto_examples/plot_benchmark_DL.html | 1486 +++ .../plot_benchmark_braindecode.html | 1456 +++ .../plot_benchmark_grid_search.html | 1047 ++ docs/auto_examples/plot_braindecode.html | 1137 ++ .../plot_cross_session_motor_imagery.html | 1032 ++ .../plot_cross_session_multiple_datasets.html | 1028 ++ .../plot_cross_subject_ssvep.html | 924 ++ docs/auto_examples/plot_disk_cache.html | 1090 ++ docs/auto_examples/plot_explore_paradigm.html | 1449 ++ .../plot_fixed_interval_windows.html | 907 ++ .../plot_within_session_p300.html | 902 ++ .../plot_within_session_ssvep.html | 975 ++ docs/auto_examples/sg_execution_times.html | 602 + docs/auto_tutorials/4_adding_a_dataset.html | 917 ++ docs/auto_tutorials/index.html | 746 ++ ...lot_tutorial_5_build_a_custom_dataset.html | 870 ++ docs/auto_tutorials/plot_Getting_Started.html | 979 ++ docs/auto_tutorials/sg_execution_times.html | 550 + ...torial_1_simple_example_motor_imagery.html | 931 ++ .../tutorial_2_using_mulitple_datasets.html | 843 ++ ...ial_3_benchmarking_multiple_pipelines.html | 882 ++ docs/cite.html | 561 + docs/dataset_summary.html | 1193 ++ docs/datasets.html | 811 ++ docs/evaluations.html | 570 + ...meta_analysis.collapse_session_scores.html | 756 ++ ...nalysis.meta_analysis.combine_effects.html | 760 ++ ...nalysis.meta_analysis.combine_pvalues.html | 760 ++ ...a_analysis.compute_dataset_statistics.html | 758 ++ ...analysis.find_significant_differences.html | 763 ++ ....analysis.plotting.meta_analysis_plot.html | 769 ++ .../moabb.analysis.plotting.paired_plot.html | 772 ++ .../moabb.analysis.plotting.score_plot.html | 779 ++ .../moabb.analysis.plotting.summary_plot.html | 770 ++ docs/generated/moabb.benchmark.html | 641 + docs/generated/moabb.datasets.AlexMI.html | 660 + docs/generated/moabb.datasets.BI2012.html | 646 + docs/generated/moabb.datasets.BI2013a.html | 709 + docs/generated/moabb.datasets.BI2014a.html | 649 + docs/generated/moabb.datasets.BI2014b.html | 643 + docs/generated/moabb.datasets.BI2015a.html | 644 + docs/generated/moabb.datasets.BI2015b.html | 649 + .../moabb.datasets.BNCI2014_001.html | 667 + .../moabb.datasets.BNCI2014_002.html | 615 + .../moabb.datasets.BNCI2014_004.html | 638 + .../moabb.datasets.BNCI2014_008.html | 624 + .../moabb.datasets.BNCI2014_009.html | 629 + .../moabb.datasets.BNCI2015_001.html | 607 + .../moabb.datasets.BNCI2015_003.html | 597 + .../moabb.datasets.BNCI2015_004.html | 625 + .../moabb.datasets.CastillosBurstVEP100.html | 645 + .../moabb.datasets.CastillosBurstVEP40.html | 645 + .../moabb.datasets.CastillosCVEP100.html | 645 + .../moabb.datasets.CastillosCVEP40.html | 610 + .../moabb.datasets.Cattan2019_PHMD.html | 650 + .../moabb.datasets.Cattan2019_VR.html | 694 + docs/generated/moabb.datasets.Cho2017.html | 664 + docs/generated/moabb.datasets.DemonsP300.html | 697 + docs/generated/moabb.datasets.EPFLP300.html | 669 + .../moabb.datasets.GrosseWentrup2009.html | 675 + .../generated/moabb.datasets.Huebner2017.html | 638 + .../generated/moabb.datasets.Huebner2018.html | 630 + .../generated/moabb.datasets.Kalunga2016.html | 675 + .../generated/moabb.datasets.Lee2019_ERP.html | 665 + docs/generated/moabb.datasets.Lee2019_MI.html | 646 + .../moabb.datasets.Lee2019_SSVEP.html | 648 + docs/generated/moabb.datasets.MAMEM1.html | 698 + docs/generated/moabb.datasets.MAMEM2.html | 665 + docs/generated/moabb.datasets.MAMEM3.html | 679 + .../moabb.datasets.Nakanishi2015.html | 647 + docs/generated/moabb.datasets.Ofner2017.html | 671 + .../generated/moabb.datasets.PhysionetMI.html | 682 + .../moabb.datasets.Schirrmeister2017.html | 667 + docs/generated/moabb.datasets.Shin2017A.html | 693 + docs/generated/moabb.datasets.Shin2017B.html | 688 + .../moabb.datasets.Sosulski2019.html | 683 + .../generated/moabb.datasets.Thielen2015.html | 663 + .../generated/moabb.datasets.Thielen2021.html | 660 + docs/generated/moabb.datasets.Wang2016.html | 685 + docs/generated/moabb.datasets.Weibo2014.html | 664 + docs/generated/moabb.datasets.Zhou2016.html | 684 + .../moabb.datasets.base.BaseDataset.html | 786 ++ .../moabb.datasets.base.CacheConfig.html | 623 + ....datasets.compound_dataset.BI2014a_Il.html | 577 + ....datasets.compound_dataset.BI2014b_Il.html | 577 + ....datasets.compound_dataset.BI2015a_Il.html | 577 + ....datasets.compound_dataset.BI2015b_Il.html | 577 + ...moabb.datasets.compound_dataset.BI_Il.html | 577 + ...ets.compound_dataset.Cattan2019_VR_Il.html | 577 + .../moabb.datasets.download.data_dl.html | 603 + .../moabb.datasets.download.data_path.html | 597 + ...bb.datasets.download.fs_get_file_hash.html | 582 + ...oabb.datasets.download.fs_get_file_id.html | 582 + ...bb.datasets.download.fs_get_file_list.html | 585 + ...bb.datasets.download.fs_get_file_name.html | 582 + ...bb.datasets.download.fs_issue_request.html | 588 + .../moabb.datasets.fake.FakeDataset.html | 628 + ...tasets.fake.FakeVirtualRealityDataset.html | 611 + .../moabb.datasets.utils.dataset_search.html | 593 + ...sets.utils.find_intersecting_channels.html | 580 + ...bb.evaluations.CrossSessionEvaluation.html | 659 + ...bb.evaluations.CrossSubjectEvaluation.html | 642 + ...b.evaluations.WithinSessionEvaluation.html | 688 + ...moabb.evaluations.base.BaseEvaluation.html | 721 + .../moabb.make_process_pipelines.html | 571 + ...ms.BaseFixedIntervalWindowsProcessing.html | 633 + docs/generated/moabb.paradigms.CVEP.html | 607 + .../moabb.paradigms.FilterBankCVEP.html | 606 + ...terBankFixedIntervalWindowsProcessing.html | 603 + ....paradigms.FilterBankLeftRightImagery.html | 590 + ...oabb.paradigms.FilterBankMotorImagery.html | 625 + .../moabb.paradigms.FilterBankSSVEP.html | 610 + ...adigms.FixedIntervalWindowsProcessing.html | 613 + .../moabb.paradigms.LeftRightImagery.html | 632 + .../moabb.paradigms.MotorImagery.html | 652 + docs/generated/moabb.paradigms.P300.html | 605 + docs/generated/moabb.paradigms.SSVEP.html | 610 + .../generated/moabb.paradigms.SinglePass.html | 662 + .../moabb.paradigms.base.BaseParadigm.html | 588 + .../moabb.paradigms.base.BaseProcessing.html | 729 ++ ...adigms.motor_imagery.BaseMotorImagery.html | 633 + ...bb.paradigms.motor_imagery.FilterBank.html | 571 + ...bb.paradigms.motor_imagery.SinglePass.html | 650 + .../moabb.paradigms.p300.BaseP300.html | 633 + .../moabb.paradigms.ssvep.BaseSSVEP.html | 642 + ...bb.pipelines.classification.SSVEP_CCA.html | 704 + ...ipelines.classification.SSVEP_MsetCCA.html | 708 + ...b.pipelines.classification.SSVEP_TRCA.html | 821 ++ docs/generated/moabb.pipelines.csp.TRCSP.html | 582 + ...elines.deep_learning.KerasDeepConvNet.html | 719 + ...pipelines.deep_learning.KerasEEGITNet.html | 717 + ...b.pipelines.deep_learning.KerasEEGNeX.html | 717 + ...pelines.deep_learning.KerasEEGNet_8_2.html | 718 + ...pipelines.deep_learning.KerasEEGTCNet.html | 718 + ...nes.deep_learning.KerasShallowConvNet.html | 719 + ...b.pipelines.features.AugmentedDataset.html | 582 + ...ipelines.features.ExtendedSSVEPSignal.html | 594 + .../moabb.pipelines.features.FM.html | 587 + .../moabb.pipelines.features.LogVariance.html | 587 + ...pelines.features.StandardScaler_Epoch.html | 578 + .../moabb.pipelines.utils.FilterBank.html | 587 + ...nes.utils.create_pipeline_from_config.html | 584 + ...abb.pipelines.utils_deep_model.EEGNet.html | 586 + ....pipelines.utils_deep_model.EEGNet_TC.html | 570 + ....pipelines.utils_deep_model.TCN_block.html | 583 + ...tils_pytorch.BraindecodeDatasetLoader.html | 572 + ...nes.utils_pytorch.InputShapeSetterEEG.html | 591 + docs/generated/moabb.set_download_dir.html | 593 + docs/generated/moabb.set_log_level.html | 649 + docs/generated/moabb.setup_seed.html | 595 + docs/genindex.html | 1271 ++ docs/index.html | 745 ++ docs/install/install.html | 614 + docs/install/install_pip.html | 585 + docs/install/install_source.html | 663 + docs/install/using_docker.html | 621 + docs/main_concepts.html | 608 + docs/objects.inv | Bin 0 -> 9036 bytes docs/overview.html | 755 ++ docs/paper_results.html | 743 ++ docs/paradigms.html | 651 + docs/pipelines.html | 623 + docs/py-modindex.html | 542 + docs/search.html | 521 + docs/searchindex.js | 1 + docs/utils.html | 569 + docs/whats_new.html | 1072 ++ 385 files changed, 163785 insertions(+) create mode 100644 docs/.buildinfo create mode 100644 docs/.nojekyll create mode 100644 docs/CONTRIBUTING.html create mode 100644 docs/README.html create mode 100644 docs/_downloads/004be3e9d1a7fe3f376ebea76a062f80/4_adding_a_dataset.py create mode 100644 docs/_downloads/0621540f2a81072e792d3fe5436855e1/noplot_phmd_ml_spectrum.ipynb create mode 100644 docs/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip create mode 100644 docs/_downloads/09c597e028c1574e907e103b3db53254/plot_within_session_ssvep.py create mode 100644 docs/_downloads/11d7e3106c779d2d16f2ad6e45bde649/plot_braindecode.ipynb create mode 100644 docs/_downloads/14eea0f23180ed6c51f0ac41b2f0162e/plot_benchmark_DL.py create mode 100644 docs/_downloads/1cb0649d22103248d85dfccb151aabae/plot_disk_cache.ipynb create mode 100644 docs/_downloads/1e19389137690794e1345c2b750ca301/noplot_bids_conversion.ipynb create mode 100644 docs/_downloads/1eb996e21dc5546952cdf5d77959e6ad/plot_learning_curve_p300_external.py create mode 100644 docs/_downloads/1fae02a0d2f8a8b38412328b11979e03/example_codecarbon.py create mode 100644 docs/_downloads/225d2b2bd0960a1fa6a57be5e1838af9/plot_benchmark.ipynb create mode 100644 docs/_downloads/284aff1e2748c45a1efdc5d7071c4a77/plot_benchmark_braindecode.py create mode 100644 docs/_downloads/2a0ca02a0f1b91ece5afbc9bdeceffe4/plot_fixed_interval_windows.ipynb create mode 100644 docs/_downloads/321fdb18266d890de5e5f577f03c2c73/plot_within_session_p300.ipynb create mode 100644 docs/_downloads/33bee7d7204a7cb56293bd1d838b63f8/plot_statistical_analysis.ipynb create mode 100644 docs/_downloads/3492da53de2fcbbc267c5e45e1d04fb9/plot_learning_curve_p300.ipynb create mode 100644 docs/_downloads/38abfe5b8b42dcb9de08824fd90d346b/plot_cross_subject_ssvep.ipynb create mode 100644 docs/_downloads/39844aaaee383c2803c6ac93e64037d5/plot_within_session_p300.py create mode 100644 docs/_downloads/3bb6d35e266c94de44c44ec75aa9d550/plot_mne_and_scikit_estimators.py create mode 100644 docs/_downloads/3f1909c085169067146e835f0f34191d/noplot_tutorial_5_build_a_custom_dataset.py create mode 100644 docs/_downloads/45332a7ce05680b6eb2282c04cab7d5b/plot_cross_session_multiple_datasets.ipynb create mode 100644 docs/_downloads/47ae966f3ab36fc8884cda73c38e648d/plot_benchmark_grid_search.ipynb create mode 100644 docs/_downloads/4819137c12db5666618aa0e7e8603bce/noplot_tutorial_5_build_a_custom_dataset.ipynb create mode 100644 docs/_downloads/4c45605b7f9e2012cf86c10fa0f2ed72/plot_filterbank_csp_vs_csp.py create mode 100644 docs/_downloads/4ecaaa7a22e7ba0d94b874867e072727/tutorial_2_using_mulitple_datasets.ipynb create mode 100644 docs/_downloads/51a1867bba0844057530c56f925fbc95/plot_benchmark_DL.ipynb create mode 100644 docs/_downloads/5303bff802560c798e898bab8eb895a3/noplot_vr_pc_p300_different_epoch_size.py create mode 100644 docs/_downloads/5459b5c2be76a529eb282ae496a50415/plot_cross_subject_ssvep.py create mode 100644 docs/_downloads/55cdcc1a57595324be0a4f77a5294187/plot_Getting_Started.py create mode 100644 docs/_downloads/5657e54b8c692376a881117a99de998e/plot_benchmark.py create mode 100644 docs/_downloads/5b1f506cd53838de0dd70e569a36f198/plot_learning_curve_motor_imagery.ipynb create mode 100644 docs/_downloads/5c05a4e8c08dd8d574a1e608b6e51c83/tutorial_3_benchmarking_multiple_pipelines.ipynb create mode 100644 docs/_downloads/657e87726c4d308a5b176dbb4277773e/plot_select_electrodes_resample.ipynb create mode 100644 docs/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip create mode 100644 docs/_downloads/73deabcc8228302a2b46b9595661aedc/noplot_vr_pc_p300_different_epoch_size.ipynb create mode 100644 docs/_downloads/744775bda3ec8d62d828dcc3cff768f5/load_model.ipynb create mode 100644 docs/_downloads/7f676ecf06fb47e9238e23dd03876176/plot_benchmark_braindecode.ipynb create mode 100644 docs/_downloads/82e3e6cb009bb9a9c444c6cff254cea8/plot_cross_session_motor_imagery.py create mode 100644 docs/_downloads/833e0bb5b511f838d653ea6df7213ca7/plot_learning_curve_motor_imagery.py create mode 100644 docs/_downloads/83c876b60654b8a0b9ebaf6714ef3607/plot_select_electrodes_resample.py create mode 100644 docs/_downloads/8fed52c2a57f02454c33ebb464a390de/load_model.py create mode 100644 docs/_downloads/93f59072dcc594921985afeb50d4cf2b/changing_download_directory.py create mode 100644 docs/_downloads/97a1de59bce682890841bb846e3dd09c/auto_tutorials_jupyter.zip create mode 100644 docs/_downloads/9ab89018120aed26b30f3efdfdef47fe/noplot_bids_conversion.py create mode 100644 docs/_downloads/9b872d163c45f60eb451b1869667203a/plot_explore_paradigm.py create mode 100644 docs/_downloads/9bb96dc7985cb9e3189360966fe90306/tutorial_1_simple_example_motor_imagery.ipynb create mode 100644 docs/_downloads/9d4b12baed30d0e2fe09c8116ace859d/plot_learning_curve_p300.py create mode 100644 docs/_downloads/a1721df1b7d19e3e027162c49fa733d4/tutorial_2_using_mulitple_datasets.py create mode 100644 docs/_downloads/b129d24bc810ae3a961d5bdcb7413828/plot_benchmark_grid_search.py create mode 100644 docs/_downloads/b298e4b36adf2bb5cb6f65682eec852f/plot_grid_search_withinsession.py create mode 100644 docs/_downloads/b446bb6bcfa12c42d029c4259163f668/tutorial_1_simple_example_motor_imagery.py create mode 100644 docs/_downloads/b766ff8fcb1665a3edb7ffee945fcb2d/noplot_phmd_ml_spectrum.py create mode 100644 docs/_downloads/b9f56e19f2500dad10214cc29a2a24e4/plot_mne_and_scikit_estimators.ipynb create mode 100644 docs/_downloads/c0d5130414c37580257e7e0b7de777e2/plot_grid_search_withinsession.ipynb create mode 100644 docs/_downloads/c0e8dffad0e66be84b9a762a9f24a516/plot_explore_paradigm.ipynb create mode 100644 docs/_downloads/c231a2e535b6091b8fee66bcebfa041c/changing_download_directory.ipynb create mode 100644 docs/_downloads/c82f3928cb70181ccb714f9ce973e8e7/plot_Getting_Started.ipynb create mode 100644 docs/_downloads/c9b0437022c98a63476dd3cad6cb69c7/plot_braindecode.py create mode 100644 docs/_downloads/cab7a090c4183ca69dc0cd84d3b04413/auto_tutorials_python.zip create mode 100644 docs/_downloads/cd325bfe64e15ce23db3b200e83ba9a2/plot_filterbank_csp_vs_csp.ipynb create mode 100644 docs/_downloads/de620aa43eea2fc28a9b3587adf0d1f8/plot_disk_cache.py create mode 100644 docs/_downloads/e34acbbaad3fb8832beb7fa8e4557c94/plot_learning_curve_p300_external.ipynb create mode 100644 docs/_downloads/f1e72fecd296ad91b914eb3562c881ee/plot_cross_session_motor_imagery.ipynb create mode 100644 docs/_downloads/f2d00b929c914067772799fd6f99fb75/4_adding_a_dataset.ipynb create mode 100644 docs/_downloads/f3215cecaa532ec823443b1b0630d3fb/plot_within_session_ssvep.ipynb create mode 100644 docs/_downloads/f4558bdb453cb198095be347c0f12fe0/example_codecarbon.ipynb create mode 100644 docs/_downloads/fa1ca889a5b6c6678d3af932651fcf7f/plot_cross_session_multiple_datasets.py create mode 100644 docs/_downloads/fb557f4e0ac4b423b8911acc0958ae76/plot_fixed_interval_windows.py create mode 100644 docs/_downloads/fc103af82bd37a6a36f57f863e9fd4aa/plot_statistical_analysis.py create mode 100644 docs/_downloads/fe7c33d68ac9fa4d60c0efbc341f93f3/tutorial_3_benchmarking_multiple_pipelines.py create mode 100644 docs/_images/architecture.png create mode 100644 docs/_images/example_codecarbon.png create mode 100644 docs/_images/moabb_install.png create mode 100644 docs/_images/sphx_glr_4_adding_a_dataset_thumb.png create mode 100644 docs/_images/sphx_glr_changing_download_directory_thumb.png create mode 100644 docs/_images/sphx_glr_example_codecarbon_thumb.png create mode 100644 docs/_images/sphx_glr_load_model_thumb.png create mode 100644 docs/_images/sphx_glr_noplot_bids_conversion_thumb.png create mode 100644 docs/_images/sphx_glr_noplot_phmd_ml_spectrum_thumb.png create mode 100644 docs/_images/sphx_glr_noplot_tutorial_5_build_a_custom_dataset_thumb.png create mode 100644 docs/_images/sphx_glr_noplot_vr_pc_p300_different_epoch_size_thumb.png create mode 100644 docs/_images/sphx_glr_plot_Getting_Started_thumb.png create mode 100644 docs/_images/sphx_glr_plot_benchmark_001.png create mode 100644 docs/_images/sphx_glr_plot_benchmark_DL_001.png create mode 100644 docs/_images/sphx_glr_plot_benchmark_DL_thumb.png create mode 100644 docs/_images/sphx_glr_plot_benchmark_braindecode_001.png create mode 100644 docs/_images/sphx_glr_plot_benchmark_braindecode_thumb.png create mode 100644 docs/_images/sphx_glr_plot_benchmark_grid_search_001.png create mode 100644 docs/_images/sphx_glr_plot_benchmark_grid_search_thumb.png create mode 100644 docs/_images/sphx_glr_plot_benchmark_thumb.png create mode 100644 docs/_images/sphx_glr_plot_braindecode_001.png create mode 100644 docs/_images/sphx_glr_plot_braindecode_thumb.png create mode 100644 docs/_images/sphx_glr_plot_cross_session_motor_imagery_001.png create mode 100644 docs/_images/sphx_glr_plot_cross_session_motor_imagery_thumb.png create mode 100644 docs/_images/sphx_glr_plot_cross_session_multiple_datasets_001.png create mode 100644 docs/_images/sphx_glr_plot_cross_session_multiple_datasets_thumb.png create mode 100644 docs/_images/sphx_glr_plot_cross_subject_ssvep_001.png create mode 100644 docs/_images/sphx_glr_plot_cross_subject_ssvep_thumb.png create mode 100644 docs/_images/sphx_glr_plot_disk_cache_thumb.png create mode 100644 docs/_images/sphx_glr_plot_explore_paradigm_thumb.png create mode 100644 docs/_images/sphx_glr_plot_filterbank_csp_vs_csp_001.png create mode 100644 docs/_images/sphx_glr_plot_filterbank_csp_vs_csp_thumb.png create mode 100644 docs/_images/sphx_glr_plot_fixed_interval_windows_001.png create mode 100644 docs/_images/sphx_glr_plot_fixed_interval_windows_thumb.png create mode 100644 docs/_images/sphx_glr_plot_grid_search_withinsession_001.png create mode 100644 docs/_images/sphx_glr_plot_grid_search_withinsession_thumb.png create mode 100644 docs/_images/sphx_glr_plot_learning_curve_motor_imagery_001.png create mode 100644 docs/_images/sphx_glr_plot_learning_curve_motor_imagery_thumb.png create mode 100644 docs/_images/sphx_glr_plot_learning_curve_p300_001.png create mode 100644 docs/_images/sphx_glr_plot_learning_curve_p300_external_001.png create mode 100644 docs/_images/sphx_glr_plot_learning_curve_p300_external_thumb.png create mode 100644 docs/_images/sphx_glr_plot_learning_curve_p300_thumb.png create mode 100644 docs/_images/sphx_glr_plot_mne_and_scikit_estimators_001.png create mode 100644 docs/_images/sphx_glr_plot_mne_and_scikit_estimators_002.png create mode 100644 docs/_images/sphx_glr_plot_mne_and_scikit_estimators_thumb.png create mode 100644 docs/_images/sphx_glr_plot_select_electrodes_resample_001.png create mode 100644 docs/_images/sphx_glr_plot_select_electrodes_resample_thumb.png create mode 100644 docs/_images/sphx_glr_plot_statistical_analysis_001.png create mode 100644 docs/_images/sphx_glr_plot_statistical_analysis_002.png create mode 100644 docs/_images/sphx_glr_plot_statistical_analysis_003.png create mode 100644 docs/_images/sphx_glr_plot_statistical_analysis_004.png create mode 100644 docs/_images/sphx_glr_plot_statistical_analysis_thumb.png create mode 100644 docs/_images/sphx_glr_plot_within_session_p300_001.png create mode 100644 docs/_images/sphx_glr_plot_within_session_p300_thumb.png create mode 100644 docs/_images/sphx_glr_plot_within_session_ssvep_001.png create mode 100644 docs/_images/sphx_glr_plot_within_session_ssvep_002.png create mode 100644 docs/_images/sphx_glr_plot_within_session_ssvep_thumb.png create mode 100644 docs/_images/sphx_glr_tutorial_1_simple_example_motor_imagery_001.png create mode 100644 docs/_images/sphx_glr_tutorial_1_simple_example_motor_imagery_thumb.png create mode 100644 docs/_images/sphx_glr_tutorial_2_using_mulitple_datasets_001.png create mode 100644 docs/_images/sphx_glr_tutorial_2_using_mulitple_datasets_thumb.png create mode 100644 docs/_images/sphx_glr_tutorial_3_benchmarking_multiple_pipelines_001.png create mode 100644 docs/_images/sphx_glr_tutorial_3_benchmarking_multiple_pipelines_thumb.png create mode 100644 docs/_sphinx_design_static/design-style.4045f2051d55cab465a707391d5b2007.min.css create mode 100644 docs/_sphinx_design_static/design-tabs.js create mode 100644 docs/_static/M.png create mode 100644 docs/_static/_sphinx_javascript_frameworks_compat.js create mode 100644 docs/_static/basic.css create mode 100644 docs/_static/binder_badge_logo.svg create mode 100644 docs/_static/broken_example.png create mode 100644 docs/_static/check-solid.svg create mode 100644 docs/_static/clipboard.min.js create mode 100644 docs/_static/copy-button.svg create mode 100644 docs/_static/copybutton.css create mode 100644 docs/_static/copybutton.js create mode 100644 docs/_static/copybutton_funcs.js create mode 100644 docs/_static/css/custom.css create mode 100644 docs/_static/design-style.4045f2051d55cab465a707391d5b2007.min.css create mode 100644 docs/_static/design-tabs.js create mode 100644 docs/_static/doctools.js create mode 100644 docs/_static/documentation_options.js create mode 100644 docs/_static/file.png create mode 100644 docs/_static/jquery-3.6.0.js create mode 100644 docs/_static/jquery.js create mode 100644 docs/_static/language_data.js create mode 100644 docs/_static/minus.png create mode 100644 docs/_static/moabb_install.png create mode 100644 docs/_static/moabb_logo.png create mode 100644 docs/_static/moabb_logo.svg create mode 100644 docs/_static/no_image.png create mode 100644 docs/_static/placeholder.css create mode 100644 docs/_static/plus.png create mode 100644 docs/_static/pygments.css create mode 100644 docs/_static/scripts/bootstrap.js create mode 100644 docs/_static/scripts/bootstrap.js.LICENSE.txt create mode 100644 docs/_static/scripts/bootstrap.js.map create mode 100644 docs/_static/scripts/pydata-sphinx-theme.js create mode 100644 docs/_static/scripts/pydata-sphinx-theme.js.map create mode 100644 docs/_static/searchtools.js create mode 100644 docs/_static/sg_gallery-binder.css create mode 100644 docs/_static/sg_gallery-dataframe.css create mode 100644 docs/_static/sg_gallery-rendered-html.css create mode 100644 docs/_static/sg_gallery.css create mode 100644 docs/_static/sphinx_highlight.js create mode 100644 docs/_static/styles/bootstrap.css create mode 100644 docs/_static/styles/pydata-sphinx-theme.css create mode 100644 docs/_static/styles/theme.css create mode 100644 docs/_static/underscore-1.13.1.js create mode 100644 docs/_static/underscore.js create mode 100644 docs/_static/vendor/fontawesome/6.1.2/LICENSE.txt create mode 100644 docs/_static/vendor/fontawesome/6.1.2/css/all.min.css create mode 100644 docs/_static/vendor/fontawesome/6.1.2/webfonts/fa-brands-400.ttf create mode 100644 docs/_static/vendor/fontawesome/6.1.2/webfonts/fa-brands-400.woff2 create mode 100644 docs/_static/vendor/fontawesome/6.1.2/webfonts/fa-regular-400.ttf create mode 100644 docs/_static/vendor/fontawesome/6.1.2/webfonts/fa-regular-400.woff2 create mode 100644 docs/_static/vendor/fontawesome/6.1.2/webfonts/fa-solid-900.ttf create mode 100644 docs/_static/vendor/fontawesome/6.1.2/webfonts/fa-solid-900.woff2 create mode 100644 docs/_static/vendor/fontawesome/6.1.2/webfonts/fa-v4compatibility.ttf create mode 100644 docs/_static/vendor/fontawesome/6.1.2/webfonts/fa-v4compatibility.woff2 create mode 100644 docs/_static/webpack-macros.html create mode 100644 docs/analysis.html create mode 100644 docs/api.html create mode 100644 docs/auto_examples/advanced_examples/index.html create mode 100644 docs/auto_examples/advanced_examples/plot_filterbank_csp_vs_csp.html create mode 100644 docs/auto_examples/advanced_examples/plot_grid_search_withinsession.html create mode 100644 docs/auto_examples/advanced_examples/plot_mne_and_scikit_estimators.html create mode 100644 docs/auto_examples/advanced_examples/plot_select_electrodes_resample.html create mode 100644 docs/auto_examples/advanced_examples/plot_statistical_analysis.html create mode 100644 docs/auto_examples/advanced_examples/sg_execution_times.html create mode 100644 docs/auto_examples/changing_download_directory.html create mode 100644 docs/auto_examples/example_codecarbon.html create mode 100644 docs/auto_examples/external/index.html create mode 100644 docs/auto_examples/external/plot_learning_curve_p300_external.html create mode 100644 docs/auto_examples/external/sg_execution_times.html create mode 100644 docs/auto_examples/index.html create mode 100644 docs/auto_examples/learning_curve/index.html create mode 100644 docs/auto_examples/learning_curve/plot_learning_curve_motor_imagery.html create mode 100644 docs/auto_examples/learning_curve/plot_learning_curve_p300.html create mode 100644 docs/auto_examples/learning_curve/sg_execution_times.html create mode 100644 docs/auto_examples/load_model.html create mode 100644 docs/auto_examples/noplot_bids_conversion.html create mode 100644 docs/auto_examples/noplot_phmd_ml_spectrum.html create mode 100644 docs/auto_examples/noplot_vr_pc_p300_different_epoch_size.html create mode 100644 docs/auto_examples/plot_benchmark.html create mode 100644 docs/auto_examples/plot_benchmark_DL.html create mode 100644 docs/auto_examples/plot_benchmark_braindecode.html create mode 100644 docs/auto_examples/plot_benchmark_grid_search.html create mode 100644 docs/auto_examples/plot_braindecode.html create mode 100644 docs/auto_examples/plot_cross_session_motor_imagery.html create mode 100644 docs/auto_examples/plot_cross_session_multiple_datasets.html create mode 100644 docs/auto_examples/plot_cross_subject_ssvep.html create mode 100644 docs/auto_examples/plot_disk_cache.html create mode 100644 docs/auto_examples/plot_explore_paradigm.html create mode 100644 docs/auto_examples/plot_fixed_interval_windows.html create mode 100644 docs/auto_examples/plot_within_session_p300.html create mode 100644 docs/auto_examples/plot_within_session_ssvep.html create mode 100644 docs/auto_examples/sg_execution_times.html create mode 100644 docs/auto_tutorials/4_adding_a_dataset.html create mode 100644 docs/auto_tutorials/index.html create mode 100644 docs/auto_tutorials/noplot_tutorial_5_build_a_custom_dataset.html create mode 100644 docs/auto_tutorials/plot_Getting_Started.html create mode 100644 docs/auto_tutorials/sg_execution_times.html create mode 100644 docs/auto_tutorials/tutorial_1_simple_example_motor_imagery.html create mode 100644 docs/auto_tutorials/tutorial_2_using_mulitple_datasets.html create mode 100644 docs/auto_tutorials/tutorial_3_benchmarking_multiple_pipelines.html create mode 100644 docs/cite.html create mode 100644 docs/dataset_summary.html create mode 100644 docs/datasets.html create mode 100644 docs/evaluations.html create mode 100644 docs/generated/moabb.analysis.meta_analysis.collapse_session_scores.html create mode 100644 docs/generated/moabb.analysis.meta_analysis.combine_effects.html create mode 100644 docs/generated/moabb.analysis.meta_analysis.combine_pvalues.html create mode 100644 docs/generated/moabb.analysis.meta_analysis.compute_dataset_statistics.html create mode 100644 docs/generated/moabb.analysis.meta_analysis.find_significant_differences.html create mode 100644 docs/generated/moabb.analysis.plotting.meta_analysis_plot.html create mode 100644 docs/generated/moabb.analysis.plotting.paired_plot.html create mode 100644 docs/generated/moabb.analysis.plotting.score_plot.html create mode 100644 docs/generated/moabb.analysis.plotting.summary_plot.html create mode 100644 docs/generated/moabb.benchmark.html create mode 100644 docs/generated/moabb.datasets.AlexMI.html create mode 100644 docs/generated/moabb.datasets.BI2012.html create mode 100644 docs/generated/moabb.datasets.BI2013a.html create mode 100644 docs/generated/moabb.datasets.BI2014a.html create mode 100644 docs/generated/moabb.datasets.BI2014b.html create mode 100644 docs/generated/moabb.datasets.BI2015a.html create mode 100644 docs/generated/moabb.datasets.BI2015b.html create mode 100644 docs/generated/moabb.datasets.BNCI2014_001.html create mode 100644 docs/generated/moabb.datasets.BNCI2014_002.html create mode 100644 docs/generated/moabb.datasets.BNCI2014_004.html create mode 100644 docs/generated/moabb.datasets.BNCI2014_008.html create mode 100644 docs/generated/moabb.datasets.BNCI2014_009.html create mode 100644 docs/generated/moabb.datasets.BNCI2015_001.html create mode 100644 docs/generated/moabb.datasets.BNCI2015_003.html create mode 100644 docs/generated/moabb.datasets.BNCI2015_004.html create mode 100644 docs/generated/moabb.datasets.CastillosBurstVEP100.html create mode 100644 docs/generated/moabb.datasets.CastillosBurstVEP40.html create mode 100644 docs/generated/moabb.datasets.CastillosCVEP100.html create mode 100644 docs/generated/moabb.datasets.CastillosCVEP40.html create mode 100644 docs/generated/moabb.datasets.Cattan2019_PHMD.html create mode 100644 docs/generated/moabb.datasets.Cattan2019_VR.html create mode 100644 docs/generated/moabb.datasets.Cho2017.html create mode 100644 docs/generated/moabb.datasets.DemonsP300.html create mode 100644 docs/generated/moabb.datasets.EPFLP300.html create mode 100644 docs/generated/moabb.datasets.GrosseWentrup2009.html create mode 100644 docs/generated/moabb.datasets.Huebner2017.html create mode 100644 docs/generated/moabb.datasets.Huebner2018.html create mode 100644 docs/generated/moabb.datasets.Kalunga2016.html create mode 100644 docs/generated/moabb.datasets.Lee2019_ERP.html create mode 100644 docs/generated/moabb.datasets.Lee2019_MI.html create mode 100644 docs/generated/moabb.datasets.Lee2019_SSVEP.html create mode 100644 docs/generated/moabb.datasets.MAMEM1.html create mode 100644 docs/generated/moabb.datasets.MAMEM2.html create mode 100644 docs/generated/moabb.datasets.MAMEM3.html create mode 100644 docs/generated/moabb.datasets.Nakanishi2015.html create mode 100644 docs/generated/moabb.datasets.Ofner2017.html create mode 100644 docs/generated/moabb.datasets.PhysionetMI.html create mode 100644 docs/generated/moabb.datasets.Schirrmeister2017.html create mode 100644 docs/generated/moabb.datasets.Shin2017A.html create mode 100644 docs/generated/moabb.datasets.Shin2017B.html create mode 100644 docs/generated/moabb.datasets.Sosulski2019.html create mode 100644 docs/generated/moabb.datasets.Thielen2015.html create mode 100644 docs/generated/moabb.datasets.Thielen2021.html create mode 100644 docs/generated/moabb.datasets.Wang2016.html create mode 100644 docs/generated/moabb.datasets.Weibo2014.html create mode 100644 docs/generated/moabb.datasets.Zhou2016.html create mode 100644 docs/generated/moabb.datasets.base.BaseDataset.html create mode 100644 docs/generated/moabb.datasets.base.CacheConfig.html create mode 100644 docs/generated/moabb.datasets.compound_dataset.BI2014a_Il.html create mode 100644 docs/generated/moabb.datasets.compound_dataset.BI2014b_Il.html create mode 100644 docs/generated/moabb.datasets.compound_dataset.BI2015a_Il.html create mode 100644 docs/generated/moabb.datasets.compound_dataset.BI2015b_Il.html create mode 100644 docs/generated/moabb.datasets.compound_dataset.BI_Il.html create mode 100644 docs/generated/moabb.datasets.compound_dataset.Cattan2019_VR_Il.html create mode 100644 docs/generated/moabb.datasets.download.data_dl.html create mode 100644 docs/generated/moabb.datasets.download.data_path.html create mode 100644 docs/generated/moabb.datasets.download.fs_get_file_hash.html create mode 100644 docs/generated/moabb.datasets.download.fs_get_file_id.html create mode 100644 docs/generated/moabb.datasets.download.fs_get_file_list.html create mode 100644 docs/generated/moabb.datasets.download.fs_get_file_name.html create mode 100644 docs/generated/moabb.datasets.download.fs_issue_request.html create mode 100644 docs/generated/moabb.datasets.fake.FakeDataset.html create mode 100644 docs/generated/moabb.datasets.fake.FakeVirtualRealityDataset.html create mode 100644 docs/generated/moabb.datasets.utils.dataset_search.html create mode 100644 docs/generated/moabb.datasets.utils.find_intersecting_channels.html create mode 100644 docs/generated/moabb.evaluations.CrossSessionEvaluation.html create mode 100644 docs/generated/moabb.evaluations.CrossSubjectEvaluation.html create mode 100644 docs/generated/moabb.evaluations.WithinSessionEvaluation.html create mode 100644 docs/generated/moabb.evaluations.base.BaseEvaluation.html create mode 100644 docs/generated/moabb.make_process_pipelines.html create mode 100644 docs/generated/moabb.paradigms.BaseFixedIntervalWindowsProcessing.html create mode 100644 docs/generated/moabb.paradigms.CVEP.html create mode 100644 docs/generated/moabb.paradigms.FilterBankCVEP.html create mode 100644 docs/generated/moabb.paradigms.FilterBankFixedIntervalWindowsProcessing.html create mode 100644 docs/generated/moabb.paradigms.FilterBankLeftRightImagery.html create mode 100644 docs/generated/moabb.paradigms.FilterBankMotorImagery.html create mode 100644 docs/generated/moabb.paradigms.FilterBankSSVEP.html create mode 100644 docs/generated/moabb.paradigms.FixedIntervalWindowsProcessing.html create mode 100644 docs/generated/moabb.paradigms.LeftRightImagery.html create mode 100644 docs/generated/moabb.paradigms.MotorImagery.html create mode 100644 docs/generated/moabb.paradigms.P300.html create mode 100644 docs/generated/moabb.paradigms.SSVEP.html create mode 100644 docs/generated/moabb.paradigms.SinglePass.html create mode 100644 docs/generated/moabb.paradigms.base.BaseParadigm.html create mode 100644 docs/generated/moabb.paradigms.base.BaseProcessing.html create mode 100644 docs/generated/moabb.paradigms.motor_imagery.BaseMotorImagery.html create mode 100644 docs/generated/moabb.paradigms.motor_imagery.FilterBank.html create mode 100644 docs/generated/moabb.paradigms.motor_imagery.SinglePass.html create mode 100644 docs/generated/moabb.paradigms.p300.BaseP300.html create mode 100644 docs/generated/moabb.paradigms.ssvep.BaseSSVEP.html create mode 100644 docs/generated/moabb.pipelines.classification.SSVEP_CCA.html create mode 100644 docs/generated/moabb.pipelines.classification.SSVEP_MsetCCA.html create mode 100644 docs/generated/moabb.pipelines.classification.SSVEP_TRCA.html create mode 100644 docs/generated/moabb.pipelines.csp.TRCSP.html create mode 100644 docs/generated/moabb.pipelines.deep_learning.KerasDeepConvNet.html create mode 100644 docs/generated/moabb.pipelines.deep_learning.KerasEEGITNet.html create mode 100644 docs/generated/moabb.pipelines.deep_learning.KerasEEGNeX.html create mode 100644 docs/generated/moabb.pipelines.deep_learning.KerasEEGNet_8_2.html create mode 100644 docs/generated/moabb.pipelines.deep_learning.KerasEEGTCNet.html create mode 100644 docs/generated/moabb.pipelines.deep_learning.KerasShallowConvNet.html create mode 100644 docs/generated/moabb.pipelines.features.AugmentedDataset.html create mode 100644 docs/generated/moabb.pipelines.features.ExtendedSSVEPSignal.html create mode 100644 docs/generated/moabb.pipelines.features.FM.html create mode 100644 docs/generated/moabb.pipelines.features.LogVariance.html create mode 100644 docs/generated/moabb.pipelines.features.StandardScaler_Epoch.html create mode 100644 docs/generated/moabb.pipelines.utils.FilterBank.html create mode 100644 docs/generated/moabb.pipelines.utils.create_pipeline_from_config.html create mode 100644 docs/generated/moabb.pipelines.utils_deep_model.EEGNet.html create mode 100644 docs/generated/moabb.pipelines.utils_deep_model.EEGNet_TC.html create mode 100644 docs/generated/moabb.pipelines.utils_deep_model.TCN_block.html create mode 100644 docs/generated/moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader.html create mode 100644 docs/generated/moabb.pipelines.utils_pytorch.InputShapeSetterEEG.html create mode 100644 docs/generated/moabb.set_download_dir.html create mode 100644 docs/generated/moabb.set_log_level.html create mode 100644 docs/generated/moabb.setup_seed.html create mode 100644 docs/genindex.html create mode 100644 docs/index.html create mode 100644 docs/install/install.html create mode 100644 docs/install/install_pip.html create mode 100644 docs/install/install_source.html create mode 100644 docs/install/using_docker.html create mode 100644 docs/main_concepts.html create mode 100644 docs/objects.inv create mode 100644 docs/overview.html create mode 100644 docs/paper_results.html create mode 100644 docs/paradigms.html create mode 100644 docs/pipelines.html create mode 100644 docs/py-modindex.html create mode 100644 docs/search.html create mode 100644 docs/searchindex.js create mode 100644 docs/utils.html create mode 100644 docs/whats_new.html diff --git a/docs/.buildinfo b/docs/.buildinfo new file mode 100644 index 00000000..36c97cf7 --- /dev/null +++ b/docs/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 33a3e3dcf3d3dcbcf64fafe3131470e7 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/CONTRIBUTING.html b/docs/CONTRIBUTING.html new file mode 100644 index 00000000..6f231e8b --- /dev/null +++ b/docs/CONTRIBUTING.html @@ -0,0 +1,653 @@ + + + + + + + + + + + + Contributing — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Contributing#

+

Contributions are always welcome, no matter how small!

+

If you think you can help in any of the areas of MOABB (and we bet you can) or in any of +the many areas that we haven’t yet thought of (and here we’re sure you can) then please +check out our roadmap.

+

Please note that it’s very important to us that we maintain a positive and supportive +environment for everyone who wants to participate. When you join us we ask that you follow +our code of conduct +in all interactions both on and offline.

+

The following is a small set of guidelines for how to contribute to the project

+
+

Where to start#

+
+

Code of Conduct#

+

This project adheres to the Contributor Covenant Code of Conduct. By +participating you are expected to adhere to these expectations. Please report unacceptable +behavior to hi@pushtheworld.us

+
+
+

Contributing on Github#

+

If you’re new to Git and want to learn how to fork this repo, make your own additions, and +include those additions in the master version of this project, check out this +great tutorial.

+
+
+

Community#

+

This project is maintained by the NeuroTechX community. Join the +Gitter, where discussions about MOABB takes +place.

+
+
+
+

How can I contribute?#

+

If there’s a feature you’d be interested in building or you find a bug or have a +suggestion on how to improve the project, go ahead! Let us know on the +Gitter or open an issue so others +can follow along and we’ll support you as much as we can. When you’re finished submit a +pull request to the master branch referencing the specific issue you addressed.

+
+

Steps to Contribute#

+
    +
  1. Look for open issues or open one

  2. +
  3. Discuss the problem and or propose a solution

  4. +
  5. Fork it! (and clone fork locally)

  6. +
  7. Branch from develop: git checkout --track develop

  8. +
  9. Setup development environment

  10. +
  11. Create your feature branch: git checkout -b my-new-feature

  12. +
  13. Make changes

  14. +
  15. Commit your changes: git commit -m 'Add some feature'

  16. +
  17. Don’t forget to fix issues from pre-commit pipeline (either add changes made by hooks +or fix them manually in case of flake8)

  18. +
  19. Push to the branch: git push origin my-new-feature

  20. +
  21. Submit a pull request. Make sure it is based on the develop branch when submitting! +:D

  22. +
  23. Don’t forget to update the +what’s new and +documentation pages if needed

  24. +
+
+
+
+

Setup development environment#

+
    +
  1. install poetry (only once per machine):curl -sSL https://install.python-poetry.org | python3 -or checkout installation instruction or +use conda forge version

  2. +
  3. (Optional, skip if not sure) Disable automatic environment creation:poetry config virtualenvs.create false

  4. +
  5. install all dependencies in one command (have to be run in thibe project directory):poetry install --extras [deeplearning, codecarbon]

  6. +
  7. install pre-commit hooks to git repo:pre-commit install

  8. +
  9. you are ready to code!

  10. +
+

Note 1:Your first commit will trigger pre-commit to download Code Quality tools. +That’s OK and it is intended behavior. This will be done once per machine automatically.

+

Note 2:By default poetry creates separate Python virtual environment for every project (more details in documentation). +If you use conda or any other way to manage different environments by hand - you need to +disable poetry environment creation. Also in this case be careful with version of Python +in your environment - it has to satisfy requirements stated in pyproject.toml. In case you +disable poetry you are in charge of this.

+
+

Tools used#

+

MOABB uses poetry for dependency management. This tool +enables one to have a reproducible environment on all popular OS (Linux, MacOS and +Windows) and provides easy publishing pipeline.

+

Another tool that makes development more stable is pre-commit. +It automatically runs variety of Code Quality instruments against the code you produced.

+

For Code Quality verification, we use:

+
    +
  • black - Python code formatting

  • +
  • isort - imports sorting and grouping

  • +
  • flake8 - code style checking

  • +
  • prettier - .yml and .md files formatting

  • +
+
+
+

Generate the documentation#

+

To generate a local version of the documentation:

+
cd docs
+make html
+
+
+
+
+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/README.html b/docs/README.html new file mode 100644 index 00000000..259b5835 --- /dev/null +++ b/docs/README.html @@ -0,0 +1,747 @@ + + + + + + + + + + + + Mother of all BCI Benchmarks — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Mother of all BCI Benchmarks

#

+

+ + Build a comprehensive benchmark of popular Brain-Computer Interface (BCI) algorithms applied on an extensive list of freely available EEG datasets. +

+

Disclaimer#

+

This is an open science project that may evolve depending on the need of the +community.

+DOI +Build Status +Code style: black +codecov +PyPI +Downloads +
+
+

Welcome!#

+

Thank you for visiting the Mother of all BCI Benchmark documentation and associated +GitHub repository

+

This document is a hub to give you some information about the project. Jump straight to +one of the sections below, or just scroll down to find out more.

+
+

The problem#

+

Brain-Computer Interfaces +allow to interact with a computer using brain signals. In this project, we focus mostly on +electroencephalographic signals +(EEG), that is a very active +research domain, with worldwide scientific contributions. Still:

+
    +
  • Reproducible Research in BCI has a long way to go.

  • +
  • While many BCI datasets are made freely available, researchers do not publish code, and +reproducing results required to benchmark new algorithms turns out to be trickier than +it should be.

  • +
  • Performances can be significantly impacted by parameters of the preprocessing steps, +toolboxes used and implementation “tricks” that are almost never reported in the +literature.

  • +
+

As a result, there is no comprehensive benchmark of BCI algorithms, and newcomers are +spending a tremendous amount of time browsing literature to find out what algorithm works +best and on which dataset.

+
+
+

The solution#

+

The Mother of all BCI Benchmarks allows to:

+
    +
  • Build a comprehensive benchmark of popular BCI algorithms applied on an extensive list +of freely available EEG datasets.

  • +
  • The code is available on GitHub, serving as a reference point for the future algorithmic +developments.

  • +
  • Algorithms can be ranked and promoted on a website, providing a clear picture of the +different solutions available in the field.

  • +
+

This project will be successful when we read in an abstract “ … the proposed method +obtained a score of 89% on the MOABB (Mother of All BCI Benchmarks), outperforming the +state of the art by 5% …”.

+
+
+

Use MOABB#

+

First, you could take a look at our tutorials that cover +the most important concepts and use cases. Also, we have a gallery of +examples available.

+
+
+
+

Core Team#

+

This project is under the umbrella of NeuroTechX, the international +community for NeuroTech enthusiasts.

+

The project is currently maintained by:

+ + + + + + + + + + + + + + + + + + + +
Sylvain ChevallierBruno AristimunhaIgor CarraraPierre GuetschelSara Sedlar
Sylvain ChevallierBruno AristimunhaIgor CarraraPierre GuetschelSara Sedlar

The Mother of all BCI Benchmarks was founded by Alexander Barachant and Vinay Jayaram, who +are experts in the field of Brain-Computer Interfaces (BCI). At moment, both works as +Research Scientist

+ + + + + + + + + + + + +
Alexander BarachantVinay Jayaram
Alexander BarachantVinay Jayaram
+
+

Contributors#

+

The MOABB is a community project, and we are always thankful for all the contributors!

+

Special acknowledge for the extra MOABB contributors:

+ + + + + + + + + + +
Pedro Rodrigues
 Pedro L. C. Rodrigues
+

What do we need?#

+

You! In whatever way you can help.

+

We need expertise in programming, user experience, software sustainability, documentation +and technical writing and project management.

+

We’d love your feedback along the way.

+

Our primary goal is to build a comprehensive benchmark of popular BCI algorithms applied +on an extensive list of freely available EEG datasets, and we’re excited to support the +professional development of any and all of our contributors. If you’re looking to learn to +code, try out working collaboratively, or translate your skills to the digital domain, +we’re here to help.

+
+
+ +
+

Contact us#

+

If you want to report a problem or suggest an enhancement, we’d love for you to +open an issue at this GitHub repository +because then we can get right on it.

+

For a less formal discussion or exchanging ideas, you can also reach us on the Gitter +channel or join our weekly office hours! This an open video meeting +happening on a regular basis, please ask +the link on the gitter channel. We are also on NeuroTechX Slack channel +#moabb.

+
+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_downloads/004be3e9d1a7fe3f376ebea76a062f80/4_adding_a_dataset.py b/docs/_downloads/004be3e9d1a7fe3f376ebea76a062f80/4_adding_a_dataset.py new file mode 100644 index 00000000..43714356 --- /dev/null +++ b/docs/_downloads/004be3e9d1a7fe3f376ebea76a062f80/4_adding_a_dataset.py @@ -0,0 +1,174 @@ +""" +==================================== +Tutorial 4: Creating a dataset class +==================================== +""" + +# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier +# +# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019 + +import mne +import numpy as np +from pyriemann.classification import MDM +from pyriemann.estimation import Covariances +from scipy.io import loadmat, savemat +from sklearn.pipeline import make_pipeline + +from moabb.datasets import download as dl +from moabb.datasets.base import BaseDataset +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import LeftRightImagery + + +############################################################################## +# Creating some Data +# ------------------ +# +# To illustrate the creation of a dataset class in MOABB, we first create an +# example dataset saved in .mat file. It contains a single fake recording on +# 8 channels lasting for 150 seconds (sampling frequency 256 Hz). We have +# included the script that creates this dataset and have uploaded it online. +# The fake dataset is available on the +# `Zenodo website `_ + + +def create_example_dataset(): + """Create a fake example for a dataset.""" + sfreq = 256 + t_recording = 150 + t_trial = 1 # duration of a trial + intertrial = 2 # time between end of a trial and the next one + n_chan = 8 + + x = np.zeros((n_chan + 1, t_recording * sfreq)) # electrodes + stimulus + stim = np.zeros(t_recording * sfreq) + t_offset = 1.0 # offset where the trials start + n_trials = 40 + + rep = np.linspace(0, 4 * t_trial, t_trial * sfreq) + signal = np.sin(2 * np.pi / t_trial * rep) + for n in range(n_trials): + label = n % 2 + 1 # alternate between class 0 and class 1 + tn = int(t_offset * sfreq + n * (t_trial + intertrial) * sfreq) + stim[tn] = label + noise = 0.1 * np.random.randn(n_chan, len(signal)) + x[:-1, tn : (tn + t_trial * sfreq)] = label * signal + noise + x[-1, :] = stim + return x, sfreq + + +# Create the fake data +for subject in [1, 2, 3]: + x, fs = create_example_dataset() + filename = "subject_" + str(subject).zfill(2) + ".mat" + mdict = {} + mdict["x"] = x + mdict["fs"] = fs + savemat(filename, mdict) + +############################################################################## +# Creating a Dataset Class +# ------------------------ +# +# We will create now a dataset class using the fake data simulated with the +# code from above. For this, we first need to import the right classes from +# MOABB: +# +# - ``dl`` is a very useful script that downloads automatically a dataset online +# if it is not yet available in the user's computer. The script knows where +# to download the files because we create a global variable telling the URL +# where to fetch the data. +# - ``BaseDataset`` is the basic class that we overload to create our dataset. +# +# The global variable with the dataset's URL should specify an online +# repository where all the files are stored. + +ExampleDataset_URL = "https://sandbox.zenodo.org/record/369543/files/" + + +############################################################################## +# The ``ExampleDataset`` needs to implement only 3 functions: +# +# - ``__init__`` for indicating the parameter of the dataset +# - ``_get_single_subject_data`` to define how to process the data once they +# have been downloaded +# - ``data_path`` to define how the data are downloaded. + + +class ExampleDataset(BaseDataset): + """Dataset used to exemplify the creation of a dataset class in MOABB. + + The data samples have been simulated and has no physiological + meaning whatsoever. + """ + + def __init__(self): + super().__init__( + subjects=[1, 2, 3], + sessions_per_subject=1, + events={"left_hand": 1, "right_hand": 2}, + code="ExampleDataset", + interval=[0, 0.75], + paradigm="imagery", + doi="", + ) + + def _get_single_subject_data(self, subject): + """Return data for a single subject.""" + file_path_list = self.data_path(subject) + + data = loadmat(file_path_list[0]) + x = data["x"] + fs = data["fs"] + ch_names = ["ch" + str(i) for i in range(8)] + ["stim"] + ch_types = ["eeg" for i in range(8)] + ["stim"] + info = mne.create_info(ch_names, fs, ch_types) + raw = mne.io.RawArray(x, info) + + sessions = {} + sessions["0"] = {} + sessions["0"]["0"] = raw + return sessions + + def data_path( + self, subject, path=None, force_update=False, update_path=None, verbose=None + ): + """Download the data from one subject.""" + if subject not in self.subject_list: + raise (ValueError("Invalid subject number")) + + url = "{:s}subject_0{:d}.mat".format(ExampleDataset_URL, subject) + path = dl.data_dl(url, "ExampleDataset") + return [path] # it has to return a list + + +############################################################################## +# Using the ExampleDataset +# ------------------------ +# +# Now that the `ExampleDataset` is defined, it could be instantiated directly. +# The rest of the code follows the steps described in the previous tutorials. + +dataset = ExampleDataset() + +paradigm = LeftRightImagery() +X, labels, meta = paradigm.get_data(dataset=dataset, subjects=[1]) + +evaluation = WithinSessionEvaluation( + paradigm=paradigm, datasets=dataset, overwrite=False, suffix="newdataset" +) +pipelines = {} +pipelines["MDM"] = make_pipeline(Covariances("oas"), MDM(metric="riemann")) +scores = evaluation.process(pipelines) + +print(scores) + +############################################################################## +# Pushing on MOABB Github +# ----------------------- +# +# If you want to make your dataset available to everyone, you could upload +# your data on public server (like Zenodo or Figshare) and signal that you +# want to add your dataset to MOABB in the `dedicated issue `_. # noqa: E501 +# You could then follow the instructions on `how to contribute `_ # noqa: E501 diff --git a/docs/_downloads/0621540f2a81072e792d3fe5436855e1/noplot_phmd_ml_spectrum.ipynb b/docs/_downloads/0621540f2a81072e792d3fe5436855e1/noplot_phmd_ml_spectrum.ipynb new file mode 100644 index 00000000..74b21d58 --- /dev/null +++ b/docs/_downloads/0621540f2a81072e792d3fe5436855e1/noplot_phmd_ml_spectrum.ipynb @@ -0,0 +1,108 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Spectral analysis of the trials\n\nThis example demonstrates how to perform spectral\nanalysis on epochs extracted from a specific subject\nwithin the :class:`moabb.datasets.Cattan2019_PHMD` dataset.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Pedro Rodrigues \n# Modified by: Gregoire Cattan \n# License: BSD (3-clause)\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom moabb.datasets import Cattan2019_PHMD\nfrom moabb.paradigms import RestingStateToP300Adapter\n\n\nwarnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initialization\n\n1) Specify the channel and subject to compute the power spectrum.\n2) Create an instance of the :class:`moabb.datasets.Cattan2019_PHMD` dataset.\n3) Create an instance of the :class:`moabb.paradigms.RestingStateToP300Adapter` paradigm.\n By default, the data is filtered between 1-35 Hz,\n and epochs are extracted from 10 to 50 seconds after event tagging.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Select channel and subject for the remaining of the example.\nchannel = \"Cz\"\nsubject = 1\n\ndataset = Cattan2019_PHMD()\nevents = [\"on\", \"off\"]\nparadigm = RestingStateToP300Adapter(events=events, channels=[channel])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Estimate Power Spectral Density\n1) Obtain the epochs for the specified subject.\n2) Use Welch's method to estimate the power spectral density.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "f, S, _, y = paradigm.psd(subject, dataset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display of the data\n\nPlot the averaged Power Spectral Density (PSD) for each label condition,\nusing the selected channel specified at the beginning of the script.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(facecolor=\"white\", figsize=(8.2, 5.1))\nfor condition in events:\n mean_power = np.mean(S[y == condition], axis=0).flatten()\n ax.plot(f, 10 * np.log10(mean_power), label=condition)\n\nax.set_xlim(paradigm.fmin, paradigm.fmax)\nax.set_ylim(100, 135)\nax.set_ylabel(\"Spectrum Magnitude (dB)\", fontsize=14)\nax.set_xlabel(\"Frequency (Hz)\", fontsize=14)\nax.set_title(\"PSD for Channel \" + channel, fontsize=16)\nax.legend()\nfig.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip b/docs/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip new file mode 100644 index 0000000000000000000000000000000000000000..23e753d8c1f880749be8caa9ca6da1628f7f3d38 GIT binary patch literal 125174 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 +# +# License: BSD (3-clause) + +import warnings + +import matplotlib.pyplot as plt +import seaborn as sns +from sklearn.pipeline import make_pipeline + +import moabb +from moabb.datasets import MAMEM3 +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import SSVEP +from moabb.pipelines import SSVEP_CCA + + +warnings.simplefilter(action="ignore", category=FutureWarning) +warnings.simplefilter(action="ignore", category=RuntimeWarning) +moabb.set_log_level("info") + +############################################################################### +# Loading Dataset +# --------------- +# +# Load 2 subjects of MAMEM3 dataset + +subj = [1, 3] +dataset = MAMEM3() +dataset.subject_list = subj + +############################################################################### +# Choose Paradigm +# --------------- +# +# We select the paradigm SSVEP, applying a bandpass filter (3-15 Hz) on +# the data and we keep only the first 3 classes, that is stimulation +# frequency of 6.66, 7.50 and 8.57 Hz. + +paradigm = SSVEP(fmin=3, fmax=15, n_classes=3) + +############################################################################## +# Create Pipelines +# ---------------- +# +# Use a Canonical Correlation Analysis classifier + +interval = dataset.interval +freqs = paradigm.used_events(dataset) + +pipeline = {} +pipeline["CCA"] = make_pipeline(SSVEP_CCA(interval=interval, freqs=freqs, n_harmonics=3)) + +############################################################################## +# Get Data (optional) +# ------------------- +# +# To get access to the EEG signals downloaded from the dataset, you could +# use `dataset.get_data(subjects=[subject_id])` to obtain the EEG under +# MNE format, stored in a dictionary of sessions and runs. +# Otherwise, `paradigm.get_data(dataset=dataset, subjects=[subject_id])` +# allows to obtain the EEG data in scikit format, the labels and the meta +# information. In `paradigm.get_data`, the EEG are preprocessed according +# to the paradigm requirement. + +# sessions = dataset.get_data(subjects=[3]) +# X, labels, meta = paradigm.get_data(dataset=dataset, subjects=[3]) + +############################################################################## +# Evaluation +# ---------- +# +# The evaluation will return a DataFrame containing a single AUC score for +# each subject and pipeline. + +overwrite = True # set to True if we want to overwrite cached results + +evaluation = WithinSessionEvaluation( + paradigm=paradigm, datasets=dataset, suffix="examples", overwrite=overwrite +) +results = evaluation.process(pipeline) + +print(results.head()) + +############################################################################## +# Plot Results +# ---------------- +# +# Here we plot the results, indicating the score for each subject + +plt.figure() +sns.barplot(data=results, y="score", x="session", hue="subject", palette="viridis") + +############################################################################## +# And the computation time in seconds + +plt.figure() +ax = sns.barplot(data=results, y="time", x="session", hue="subject", palette="Reds") +ax.set_ylabel("Time (s)") +plt.show() diff --git a/docs/_downloads/11d7e3106c779d2d16f2ad6e45bde649/plot_braindecode.ipynb b/docs/_downloads/11d7e3106c779d2d16f2ad6e45bde649/plot_braindecode.ipynb new file mode 100644 index 00000000..e71b2d3a --- /dev/null +++ b/docs/_downloads/11d7e3106c779d2d16f2ad6e45bde649/plot_braindecode.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Cross-session motor imagery with deep learning EEGNet v4 model\nThis example shows how to use BrainDecode in combination with MOABB evaluation.\nIn this example, we use the architecture EEGNetv4.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Igor Carrara \n# Bruno Aristimunha \n#\n# License: BSD (3-clause)\n\nimport matplotlib.pyplot as plt\nimport mne\nimport seaborn as sns\nimport torch\nfrom braindecode import EEGClassifier\nfrom braindecode.models import EEGNetv4\nfrom sklearn.pipeline import make_pipeline\nfrom skorch.callbacks import EarlyStopping, EpochScoring\nfrom skorch.dataset import ValidSplit\n\nfrom moabb.datasets import BNCI2014_001\nfrom moabb.evaluations import CrossSessionEvaluation\nfrom moabb.paradigms import MotorImagery\nfrom moabb.utils import setup_seed\n\n\nmne.set_log_level(False)\n\n# Print Information PyTorch\nprint(f\"Torch Version: {torch.__version__}\")\n\n# Set up GPU if it is there\ncuda = torch.cuda.is_available()\ndevice = \"cuda\" if cuda else \"cpu\"\nprint(\"GPU is\", \"AVAILABLE\" if cuda else \"NOT AVAILABLE\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, we will use only the dataset ``BNCI2014_001``.\n\n## Running the benchmark\n\nThis example uses the CrossSession evaluation procedure. We focus on the dataset BNCI2014_001 and only on 1 subject\nto reduce computational time.\n\nTo keep the computational time low, the epoch is reduced. In a real situation, we suggest using the following:\nEPOCH = 1000\nPATIENCE = 300\n\nThis code is implemented to run on the CPU. If you're using a GPU, do not use multithreading\n(i.e. set n_jobs=1)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Set random seed to be able to reproduce results\nseed = 42\nsetup_seed(seed)\n\n# Ensure that all operations are deterministic on GPU (if used) for reproducibility\ntorch.backends.cudnn.deterministic = True\ntorch.backends.cudnn.benchmark = False\n\n# Hyperparameter\nLEARNING_RATE = 0.0625 * 0.01 # parameter taken from Braindecode\nWEIGHT_DECAY = 0 # parameter taken from Braindecode\nBATCH_SIZE = 64 # parameter taken from BrainDecode\nEPOCH = 10\nPATIENCE = 3\nfmin = 4\nfmax = 100\ntmin = 0\ntmax = None\n\n# Load the dataset\ndataset = BNCI2014_001()\nevents = [\"right_hand\", \"left_hand\"]\nparadigm = MotorImagery(\n events=events, n_classes=len(events), fmin=fmin, fmax=fmax, tmin=tmin, tmax=tmax\n)\nsubjects = [1]\nX, _, _ = paradigm.get_data(dataset=dataset, subjects=subjects)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Pipelines\nIn order to create a pipeline, we need to load a model from braindecode.\nthe second step is to define a skorch model using EEGClassifier from braindecode\nthat allows converting the PyTorch model in a scikit-learn classifier.\nHere, we will use the EEGNet v4 model [1]_ .\nThis model has mandatory hyperparameters (the number of channels, the number of classes,\nand the temporal length of the input) but we do not need to specify them because they will\nbe set dynamically by EEGClassifier using the input data during the call to the ``.fit()`` method.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define a Skorch classifier\nclf = EEGClassifier(\n module=EEGNetv4,\n optimizer=torch.optim.Adam,\n optimizer__lr=LEARNING_RATE,\n batch_size=BATCH_SIZE,\n max_epochs=EPOCH,\n train_split=ValidSplit(0.2, random_state=seed),\n device=device,\n callbacks=[\n EarlyStopping(monitor=\"valid_loss\", patience=PATIENCE),\n EpochScoring(\n scoring=\"accuracy\", on_train=True, name=\"train_acc\", lower_is_better=False\n ),\n EpochScoring(\n scoring=\"accuracy\", on_train=False, name=\"valid_acc\", lower_is_better=False\n ),\n ],\n verbose=1, # Not printing the results for each epoch\n)\n\n# Create the pipelines\npipes = {}\npipes[\"EEGNetV4\"] = make_pipeline(clf)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset.subject_list = dataset.subject_list[:2]\n\nevaluation = CrossSessionEvaluation(\n paradigm=paradigm,\n datasets=dataset,\n suffix=\"braindecode_example\",\n overwrite=True,\n return_epochs=True,\n n_jobs=1,\n)\n\nresults = evaluation.process(pipes)\n\nprint(results.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plt.figure()\nsns.barplot(data=results, y=\"score\", x=\"subject\", palette=\"viridis\")\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## References\n.. [1] Lawhern, V. J., Solon, A. J., Waytowich, N. R., Gordon, S. M.,\n Hung, C. P., & Lance, B. J. (2018). [EEGNet: a compact convolutional neural\n network for EEG-based brain-computer interfaces.](https://doi.org/10.1088/1741-2552/aace8c)\n Journal of neural engineering, 15(5), 056013.\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/14eea0f23180ed6c51f0ac41b2f0162e/plot_benchmark_DL.py b/docs/_downloads/14eea0f23180ed6c51f0ac41b2f0162e/plot_benchmark_DL.py new file mode 100644 index 00000000..032ba81c --- /dev/null +++ b/docs/_downloads/14eea0f23180ed6c51f0ac41b2f0162e/plot_benchmark_DL.py @@ -0,0 +1,128 @@ +""" +==================================================================== +Benchmarking on MOABB with Tensorflow deep net architectures +==================================================================== +This example shows how to use MOABB to benchmark a set of Deep Learning pipeline (Tensorflow) +on all available datasets. +For this example, we will use only one dataset to keep the computation time low, but this benchmark is designed +to easily scale to many datasets. +""" + +# Authors: Igor Carrara +# +# License: BSD (3-clause) + +import os + +import matplotlib.pyplot as plt +import tensorflow as tf +from absl.logging import ERROR, set_verbosity +from tensorflow import keras + +from moabb import benchmark, set_log_level +from moabb.analysis.plotting import score_plot +from moabb.datasets import BNCI2014_001 +from moabb.utils import setup_seed + + +set_log_level("info") +# Avoid output Warning +set_verbosity(ERROR) +os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" + +# Print Information Tensorflow +print(f"Tensorflow Version: {tf.__version__}") +print(f"Keras Version: {keras.__version__}") + +CPU = len(tf.config.list_physical_devices("CPU")) > 0 +print("CPU is", "AVAILABLE" if CPU else "NOT AVAILABLE") + +GPU = len(tf.config.list_physical_devices("GPU")) > 0 +print("GPU is", "AVAILABLE" if GPU else "NOT AVAILABLE") + +############################################################################### +# In this example, we will use only the dataset ``BNCI2014_001``. +# +# Running the benchmark +# --------------------- +# +# The benchmark is run using the ``benchmark`` function. You need to specify the +# folder containing the pipelines to use, the kind of evaluation and the paradigm +# to use. By default, the benchmark will use all available datasets for all +# paradigms listed in the pipelines. You could restrict to specific evaluation and +# paradigm using the ``evaluations`` and ``paradigms`` arguments. +# +# To save computation time, the results are cached. If you want to re-run the +# benchmark, you can set the ``overwrite`` argument to ``True``. +# +# It is possible to indicate the folder to cache the results and the one to save +# the analysis & figures. By default, the results are saved in the ``results`` +# folder, and the analysis & figures are saved in the ``benchmark`` folder. +# +# This code is implemented to run on CPU. If you're using a GPU, do not use multithreading +# (i.e. set n_jobs=1) + +# Set up reproducibility of Tensorflow +setup_seed(42) + +# Restrict this example only on the first two subject of BNCI2014_001 +dataset = BNCI2014_001() +dataset.subject_list = dataset.subject_list[:2] +datasets = [dataset] + +results = benchmark( + pipelines="./pipelines_DL", + evaluations=["WithinSession"], + paradigms=["LeftRightImagery"], + include_datasets=datasets, + results="./results/", + overwrite=False, + plot=False, + output="./benchmark/", + n_jobs=-1, +) + +############################################################################### +# The deep learning architectures implemented in MOABB are: +# - Shallow Convolutional Network [1]_ +# - Deep Convolutional Network [1]_ +# - EEGNet [2]_ +# - EEGTCNet [3]_ +# - EEGNex [4]_ +# - EEGITNet [5]_ +# +# Benchmark prints a summary of the results. Detailed results are saved in a +# pandas dataframe, and can be used to generate figures. The analysis & figures +# are saved in the ``benchmark`` folder. + +score_plot(results) +plt.show() + +############################################################################## +# References +# ---------- +# .. [1] Schirrmeister, R. T., Springenberg, J. T., Fiederer, L. D. J., +# Glasstetter, M., Eggensperger, K., Tangermann, M., ... & Ball, T. (2017). +# `Deep learning with convolutional neural networks for EEG decoding and +# visualization `_. +# Human brain mapping, 38(11), 5391-5420. +# .. [2] Lawhern, V. J., Solon, A. J., Waytowich, N. R., Gordon, S. M., +# Hung, C. P., & Lance, B. J. (2018). `EEGNet: a compact convolutional neural +# network for EEG-based brain-computer interfaces. +# `_ +# Journal of neural engineering, 15(5), 056013. +# .. [3] Ingolfsson, T. M., Hersche, M., Wang, X., Kobayashi, N., Cavigelli, L., & +# Benini, L. (2020, October). `EEG-TCNet: An accurate temporal convolutional +# network for embedded motor-imagery brain-machine interfaces. +# `_ +# In 2020 IEEE International Conference on Systems, Man, and Cybernetics (SMC) +# (pp. 2958-2965). IEEE. +# .. [4] Chen, X., Teng, X., Chen, H., Pan, Y., & Geyer, P. (2022). `Toward reliable +# signals decoding for electroencephalogram: A benchmark study to EEGNeX. +# `_ +# arXiv preprint arXiv:2207.12369. +# .. [5] Salami, A., Andreu-Perez, J., & Gillmeister, H. (2022). `EEG-ITNet: An +# explainable inception temporal convolutional network for motor imagery +# classification +# `_. +# IEEE Access, 10, 36672-36685. diff --git a/docs/_downloads/1cb0649d22103248d85dfccb151aabae/plot_disk_cache.ipynb b/docs/_downloads/1cb0649d22103248d85dfccb151aabae/plot_disk_cache.ipynb new file mode 100644 index 00000000..bbc52fad --- /dev/null +++ b/docs/_downloads/1cb0649d22103248d85dfccb151aabae/plot_disk_cache.ipynb @@ -0,0 +1,263 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Cache on disk intermediate data processing states\n\nThis example shows how intermediate data processing\nstates can be cached on disk to speed up the loading\nof this data in subsequent calls.\n\nWhen a MOABB paradigm processes a dataset, it will\nfirst apply processing steps to the raw data, this is\ncalled the ``raw_pipeline``. Then, it will convert the\nraw data into epochs and apply processing steps on the\nepochs, this is called the ``epochs_pipeline``.\nFinally, it will eventually convert the epochs into arrays,\nthis is called the ``array_pipeline``. In summary:\n\n``raw_pipeline`` --> ``epochs_pipeline`` --> ``array_pipeline``\n\nAfter each step, MOABB offers the possibility to save on disk\nthe result of the step. This is done by setting the ``cache_config``\nparameter of the paradigm's ``get_data`` method.\nThe ``cache_config`` parameter is a dictionary that can take all\nthe parameters of ``moabb.datasets.base.CacheConfig`` as keys,\nthey are the following: ``use``, ``save_raw``, ``save_epochs``,\n``save_array``, ``overwrite_raw``, ``overwrite_epochs``,\n``overwrite_array``, and ``path``. You can also directly pass a\n``CacheConfig`` object as ``cache_config``.\n\nIf ``use=False``, the ``save_*`` and ``overwrite_*``\nparameters are ignored.\n\nWhen trying to use the cache (i.e. ``use=True``), MOABB will\nfirst check if there exist a cache of the result of the full\npipeline (i.e. ``raw_pipeline`` --> ``epochs_pipeline`` ->\n``array_pipeline``).\nIf there is none, we remove the last step of the pipeline and\nlook for its cached result. We keep removing steps and looking\nfor a cached result until we find one or until we reach an\nempty pipeline.\nEvery time, if the ``overwrite_*`` parameter\nof the corresponding step is true, we first try to erase the\ncache of this step.\nOnce a cache has been found or the empty pipeline has been reached,\ndepending on the case we either load the cache or the original dataset.\nThen, apply the missing steps one by one and save their result\nif their corresponding ``save_*`` parameter is true.\n\nBy default, only the result of the ``raw_pipeline`` is saved.\nThis is usually a good compromise between speed and disk space\nbecause, when using cached raw data, the epochs can be obtained\nwithout preloading the whole raw signals, only the necessary\nintervals. Yet, because only the raw data is cached, the epoching\nparameters can be changed without creating a new cache each time.\nHowever, if your epoching parameters are fixed, you can directly\ncache the epochs or the arrays to speed up the loading and\nreduce the disk space used.\n\n

Note

The ``cache_config`` parameter is also available for the ``get_data``\n method of the datasets. It works the same way as for a\n paradigm except that it will save un-processed raw recordings.

\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Pierre Guetschel \n#\n# License: BSD (3-clause)\n\nimport shutil\nimport tempfile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import time\nfrom pathlib import Path\n\nfrom moabb import set_log_level\nfrom moabb.datasets import Zhou2016\nfrom moabb.paradigms import LeftRightImagery\n\n\nset_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic usage\n\nThe ``cache_config`` parameter is a dictionary that has the\nfollowing default values:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "default_cache_config = dict(\n save_raw=False,\n save_epochs=False,\n save_array=False,\n use=False,\n overwrite_raw=False,\n overwrite_epochs=False,\n overwrite_array=False,\n path=None,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You don not need to specify all the keys of ``cache_config``, only the ones\nyou want to change.\n\nBy default, the cache is saved at the MNE data directory (i.e. when\n``path=None``). The MNE data directory can be found with\n``mne.get_config('MNE_DATA')``. For this example, we will save it in a\ntemporary directory instead:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "temp_dir = Path(tempfile.mkdtemp())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will use the Zhou2016 dataset and the LeftRightImagery paradigm in this\nexample, but this works for any dataset and paradigm pair.:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset = Zhou2016()\nparadigm = LeftRightImagery()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we will only use the first subject for this example:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "subjects = [1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, saving a cache can simply be done by setting the desired parameters\nin the ``cache_config`` dictionary:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cache_config = dict(\n use=True,\n save_raw=True,\n save_epochs=True,\n save_array=True,\n path=temp_dir,\n)\n_ = paradigm.get_data(dataset, subjects, cache_config=cache_config)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Time comparison\n\nNow, we will compare the time it takes to load the with different levels of\ncache. For this, we will use the cache saved in the previous block and\noverwrite the steps results one by one so that we can compare the time it\ntakes to load the data and compute the missing steps with an increasing\nnumber of missing steps.\n\nUsing array cache:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cache_config = dict(\n use=True,\n path=temp_dir,\n save_raw=False,\n save_epochs=False,\n save_array=False,\n overwrite_raw=False,\n overwrite_epochs=False,\n overwrite_array=False,\n)\nt0 = time.time()\n_ = paradigm.get_data(dataset, subjects, cache_config=cache_config)\nt_array = time.time() - t0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using epochs cache:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cache_config = dict(\n use=True,\n path=temp_dir,\n save_raw=False,\n save_epochs=False,\n save_array=False,\n overwrite_raw=False,\n overwrite_epochs=False,\n overwrite_array=True,\n)\nt0 = time.time()\n_ = paradigm.get_data(dataset, subjects, cache_config=cache_config)\nt_epochs = time.time() - t0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using raw cache:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cache_config = dict(\n use=True,\n path=temp_dir,\n save_raw=False,\n save_epochs=False,\n save_array=False,\n overwrite_raw=False,\n overwrite_epochs=True,\n overwrite_array=True,\n)\nt0 = time.time()\n_ = paradigm.get_data(dataset, subjects, cache_config=cache_config)\nt_raw = time.time() - t0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using no cache:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cache_config = dict(\n use=False,\n path=temp_dir,\n save_raw=False,\n save_epochs=False,\n save_array=False,\n overwrite_raw=False,\n overwrite_epochs=False,\n overwrite_array=False,\n)\nt0 = time.time()\n_ = paradigm.get_data(dataset, subjects, cache_config=cache_config)\nt_nocache = time.time() - t0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Time needed to load the data with different levels of cache:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(f\"Using array cache: {t_array:.2f} seconds\")\nprint(f\"Using epochs cache: {t_epochs:.2f} seconds\")\nprint(f\"Using raw cache: {t_raw:.2f} seconds\")\nprint(f\"Without cache: {t_nocache:.2f} seconds\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see, using a raw cache is more than 5 times faster than\nwithout cache.\nThis is because when using the raw cache, the data is not preloaded, only\nthe desired epochs are loaded in memory.\n\nUsing the epochs cache is a little faster than the raw cache. This is because\nthere are several preprocessing steps done after the epoching by the\n``epochs_pipeline``. This difference would be greater if the ``resample``\nargument was different that the sampling frequency of the dataset. Indeed,\nthe data loading time is directly proportional to its sampling frequency\nand the resampling is done by the ``epochs_pipeline``.\n\nFinally, we observe very little difference between array and epochs cache.\nThe main interest of the array cache is when the user passes a\ncomputationally heavy but fixed additional preprocessing (for example\ncomputing the covariance matrices of the epochs). This can be done by using\nthe ``postprocess_pipeline`` argument. The output of this additional pipeline\n(necessary a numpy array) will be saved to avoid re-computing it each time.\n\n\n## Technical details\n\nUnder the hood, the cache is saved on disk in a Brain Imaging Data Structure\n(BIDS) compliant format. More details on this structure can be found in the\ntutorial :doc:`./plot_bids_conversion`.\n\nHowever, there are two particular aspects of the way MOABB saves the data\nthat are not specific to BIDS:\n\n* For each file, we set a\n [description key](https://bids-specification.readthedocs.io/en/stable/appendices/entities.html#desc).\n This key is a code that corresponds to a hash of the\n pipeline that was used to generate the data (i.e. from raw to the state\n of the cache). This code is unique for each different pipeline and allows\n to identify all the files that were generated by the same pipeline.\n* Once we finish saving all the files for a given combination of dataset,\n subject, and pipeline, we write a file ending in ``\"_lockfile.json\"`` at\n the root directory of this subject. This file serves two purposes:\n\n * It indicates that the cache is complete for this subject and pipeline.\n If it is not present, it means that something went wrong during the\n saving process and the cache is incomplete.\n * The file contains the un-hashed string representation of the pipeline.\n Therefore, it can be used to identify the pipeline used without having\n to decode the description key.\n\n## Cleanup\n\nFinally, we can delete the temporary folder:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "shutil.rmtree(temp_dir)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/1e19389137690794e1345c2b750ca301/noplot_bids_conversion.ipynb b/docs/_downloads/1e19389137690794e1345c2b750ca301/noplot_bids_conversion.ipynb new file mode 100644 index 00000000..54644445 --- /dev/null +++ b/docs/_downloads/1e19389137690794e1345c2b750ca301/noplot_bids_conversion.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Convert a MOABB dataset to BIDS\n\nThe Brain Imaging Data Structure (BIDS) format\nis standard for storing neuroimaging data.\nIt follows fixed principles to facilitate the\nsharing of neuroimaging data between researchers.\n\nThe MOABB library allows to convert any MOABB dataset to\nBIDS [1]_ and [2]_.\n\nIn this example, we will convert the AlexMI dataset to BIDS using the\noption ``cache_config=dict(path=temp_dir, save_raw=True)`` of the ``get_data``\nmethod from the dataset object.\n\nThis will automatically save the raw data in the BIDS format and allow to use\na cache for the next time the dataset is used.\n\nWe will use the AlexMI dataset [3]_, one of the smallest in\npeople and one that can be downloaded quickly.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Pierre Guetschel \n#\n# License: BSD (3-clause)\n\nimport shutil\nimport tempfile\nfrom pathlib import Path\n\nimport mne\n\nfrom moabb import set_log_level\nfrom moabb.datasets import AlexMI\n\n\nset_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic usage\n\nHere, we will save the BIDS version of the dataset in a temporary folder\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "temp_dir = Path(tempfile.mkdtemp())\n# The conversion of any MOABB dataset to a BIDS-compliant structure can be done\n# by simply calling its ``get_data`` method and using the ``cache_config``\n# parameter. This parameter is a dictionary.\ndataset = AlexMI()\n_ = dataset.get_data(cache_config=dict(path=temp_dir, save_raw=True))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Before / after folder structure\n\nTo investigate what was saved, we will first define a function to print\nthe folder structure of a given path:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def print_tree(p: Path, last=True, header=\"\"):\n elbow = \"\u2514\u2500\u2500\"\n pipe = \"\u2502 \"\n tee = \"\u251c\u2500\u2500\"\n blank = \" \"\n print(header + (elbow if last else tee) + p.name)\n if p.is_dir():\n children = list(p.iterdir())\n for i, c in enumerate(children):\n print_tree(\n c, header=header + (blank if last else pipe), last=i == len(children) - 1\n )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we will retrieve the location of the original dataset. It is stored\nin the MNE data directory, which can be found with the ``\"MNE_DATA\"`` key:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "mne_data = Path(mne.get_config(\"MNE_DATA\"))\nprint(f\"MNE data directory: {mne_data}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we can print the folder structure of the original dataset:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"Before conversion:\")\nprint_tree(mne_data / \"MNE-alexeeg-data\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see, before conversion, all the data (i.e. from all subjects,\nsessions and runs) is stored in a single folder. This follows no particular\nstandard and can vary from one dataset to another.\n\nAfter conversion, the data is stored in a BIDS-compliant way:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"After conversion:\")\nprint_tree(temp_dir / \"MNE-BIDS-alexandre-motor-imagery\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the BIDS version of our dataset, the raw files are saved in EDF.\nThe data is organized in a hierarchy of folders,\nstarting with the subjects, then the sessions, and then the runs. Metadata\nfiles are stored to describe the data. For more details on the BIDS\nstructure, please refer to the [BIDS website](https://bids.neuroimaging.io)\nand the [BIDS spec](https://bids-specification.readthedocs.io/en/stable/).\n\nUnder the hood, saving datasets to BIDS is done through the caching system\nof MOABB. Only raw EEG files are officially supported by the BIDS\nspecification.\nHowever, MOABB's caching mechanism also offers the possibility to save\nthe data in a pseudo-BIDS after different preprocessing steps.\nIn particular, we can save :class:`mne.Epochs` and ``np.ndarray`` objects.\nFor more details on the caching system,\nplease refer to the tutorial :doc:`./plot_disk_cache`.\n\n## Cleanup\n\nFinally, we can delete the temporary folder:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "shutil.rmtree(temp_dir)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## References\n\n.. [1] Pernet, C.R., Appelhoff, S., Gorgolewski, K.J. et al. EEG-BIDS,\n An extension to the brain imaging data structure for\n electroencephalography. Sci Data 6, 103 (2019).\n https://doi.org/10.1038/s41597-019-0104-8\n\n.. [2] Appelhoff et al., (2019). MNE-BIDS: Organizing electrophysiological\n data into the BIDS format and facilitating their analysis.\n Journal of Open Source Software, 4(44), 1896,\n https://doi.org/10.21105/joss.01896\n\n.. [3] Barachant, A., 2012. Commande robuste d'un effecteur par une\n interface cerveau machine EEG asynchrone (Doctoral dissertation,\n Universit\u00e9 de Grenoble).\n https://tel.archives-ouvertes.fr/tel-01196752\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/1eb996e21dc5546952cdf5d77959e6ad/plot_learning_curve_p300_external.py b/docs/_downloads/1eb996e21dc5546952cdf5d77959e6ad/plot_learning_curve_p300_external.py new file mode 100644 index 00000000..82a1444b --- /dev/null +++ b/docs/_downloads/1eb996e21dc5546952cdf5d77959e6ad/plot_learning_curve_p300_external.py @@ -0,0 +1,149 @@ +""" +======================================= +Within Session P300 with Learning Curve +======================================= + +This example shows how to perform a within session analysis while also +creating learning curves for a P300 dataset. +Additionally, we will evaluate external code. Make sure to have tdlda installed +, which can be found in requirements_external.txt + +We will compare three pipelines : + +- Riemannian geometry +- Jumping Means-based Linear Discriminant Analysis +- Time-Decoupled Linear Discriminant Analysis + +We will use the P300 paradigm, which uses the AUC as metric. +""" + +# Authors: Jan Sosulski +# +# License: BSD (3-clause) + +import warnings + +import matplotlib.pyplot as plt +import numpy as np +import seaborn as sns +from pyriemann.estimation import XdawnCovariances +from pyriemann.tangentspace import TangentSpace +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.pipeline import make_pipeline +from tdlda import TimeDecoupledLda +from tdlda import Vectorizer as JumpingMeansVectorizer + +import moabb +from moabb.datasets import BNCI2014_009 +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import P300 + + +# getting rid of the warnings about the future (on s'en fout !) +warnings.simplefilter(action="ignore", category=FutureWarning) +warnings.simplefilter(action="ignore", category=RuntimeWarning) + +moabb.set_log_level("info") + +############################################################################## +# Create pipelines +# ---------------- +# +# Pipelines must be a dict of sklearn pipeline transformer. +processing_sampling_rate = 128 +pipelines = {} + +# We have to do this because the classes are called 'Target' and 'NonTarget' +# but the evaluation function uses a LabelEncoder, transforming them +# to 0 and 1 +labels_dict = {"Target": 1, "NonTarget": 0} + +# Riemannian geometry based classification +pipelines["RG+LDA"] = make_pipeline( + XdawnCovariances(nfilter=5, estimator="lwf", xdawn_estimator="scm"), + TangentSpace(), + LDA(solver="lsqr", shrinkage="auto"), +) + +# Simple LDA pipeline using averaged feature values in certain time intervals +jumping_mean_ivals = [ + [0.10, 0.139], + [0.14, 0.169], + [0.17, 0.199], + [0.20, 0.229], + [0.23, 0.269], + [0.27, 0.299], + [0.30, 0.349], + [0.35, 0.409], + [0.41, 0.449], + [0.45, 0.499], +] +jmv = JumpingMeansVectorizer( + fs=processing_sampling_rate, jumping_mean_ivals=jumping_mean_ivals +) + +pipelines["JM+LDA"] = make_pipeline(jmv, LDA(solver="lsqr", shrinkage="auto")) + +# Time-decoupled Covariance classifier, needs information about number of +# channels and time intervals +c = TimeDecoupledLda(N_channels=16, N_times=10) +# TD-LDA needs to know about the used jumping means intervals +c.preproc = jmv +pipelines["JM+TD-LDA"] = make_pipeline(jmv, c) + +############################################################################## +# Evaluation +# ---------- +# +# We define the paradigm (P300) and use the BNCI 2014-009 dataset for it. +# The evaluation will return a dataframe containing AUCs for each permutation +# and dataset size. + +paradigm = P300(resample=processing_sampling_rate) +dataset = BNCI2014_009() +# Remove the slicing of the subject list to evaluate multiple subjects +dataset.subject_list = dataset.subject_list[0:1] +datasets = [dataset] +overwrite = True # set to True if we want to overwrite cached results +data_size = dict(policy="ratio", value=np.geomspace(0.02, 1, 6)) +# When the training data is sparse, perform more permutations than when we have +# a lot of data +n_perms = np.floor(np.geomspace(20, 2, len(data_size["value"]))).astype(int) +print(n_perms) +# Guarantee reproducibility +np.random.seed(7536298) +evaluation = WithinSessionEvaluation( + paradigm=paradigm, + datasets=datasets, + data_size=data_size, + n_perms=n_perms, + suffix="examples_lr", + overwrite=overwrite, +) + +results = evaluation.process(pipelines) + +############################################################################## +# Plot Results +# ------------ +# +# Here we plot the results. + +fig, ax = plt.subplots(facecolor="white", figsize=[8, 4]) + +n_subs = len(dataset.subject_list) + +if n_subs > 1: + r = results.groupby(["pipeline", "subject", "data_size"]).mean().reset_index() +else: + r = results + +sns.pointplot(data=r, x="data_size", y="score", hue="pipeline", ax=ax, palette="Set1") + +errbar_meaning = "subjects" if n_subs > 1 else "permutations" +title_str = f"Errorbar shows Mean-CI across {errbar_meaning}" +ax.set_xlabel("Amount of training samples") +ax.set_ylabel("ROC AUC") +ax.set_title(title_str) +fig.tight_layout() +plt.show() diff --git a/docs/_downloads/1fae02a0d2f8a8b38412328b11979e03/example_codecarbon.py b/docs/_downloads/1fae02a0d2f8a8b38412328b11979e03/example_codecarbon.py new file mode 100644 index 00000000..eaffaa26 --- /dev/null +++ b/docs/_downloads/1fae02a0d2f8a8b38412328b11979e03/example_codecarbon.py @@ -0,0 +1,122 @@ +""" +================================================= +Benchmarking with MOABB showing the CO2 footprint +================================================= + +This example shows how to use MOABB to track the CO2 footprint +using `CodeCarbon library `__. +For this example, we will use only one +dataset to keep the computation time low, but this benchmark is designed +to easily scale to many datasets. Due to limitation of online documentation +generation, the results is computed on a local cluster but could be easily +replicated on your infrastructure. +""" + +# Authors: Igor Carrara +# Bruno Aristimunha +# +# License: BSD (3-clause) + +############################################################################### +from moabb import benchmark, set_log_level +from moabb.analysis.plotting import codecarbon_plot +from moabb.datasets import BNCI2014_001, Zhou2016 +from moabb.paradigms import LeftRightImagery + + +set_log_level("info") + +############################################################################### +# Loading the pipelines +# --------------------- +# +# To run this example we use several pipelines, ML and DL (Keras) and also +# pipelines that need an optimization of the hyperparameter. +# All this different pipelines are stored in ``pipelines_codecarbon`` + +############################################################################### +# Selecting the datasets (optional) +# --------------------------------- +# +# If you want to limit your benchmark on a subset of datasets, you can use the +# ``include_datasets`` and ``exclude_datasets`` arguments. You will need either +# to provide the dataset's object, or a dataset's code. To get the list of +# available dataset's code for a given paradigm, you can use the following +# command: + +paradigm = LeftRightImagery() +for d in paradigm.datasets: + print(d.code) + +############################################################################### +# In this example, we will use only the last dataset, 'Zhou 2016', considering +# only the first subject. +# +# Running the benchmark +# --------------------- +# +# The benchmark is run using the ``benchmark`` function. You need to specify the +# folder containing the pipelines to use, the kind of evaluation and the paradigm +# to use. By default, the benchmark will use all available datasets for all +# paradigms listed in the pipelines. You could restrict to specific evaluation +# and paradigm using the ``evaluations`` and ``paradigms`` arguments. +# +# To save computation time, the results are cached. If you want to re-run the +# benchmark, you can set the ``overwrite`` argument to ``True``. +# +# It is possible to indicate the folder to cache the results and the one to +# save the analysis & figures. By default, the results are saved in the +# ``results`` folder, and the analysis & figures are saved in the ``benchmark`` +# folder. + +dataset = Zhou2016() +dataset2 = BNCI2014_001() +dataset.subject_list = dataset.subject_list[:1] +dataset2.subject_list = dataset2.subject_list[:1] +datasets = [dataset, dataset2] + +results = benchmark( + pipelines="./pipelines_codecarbon/", + evaluations=["WithinSession"], + paradigms=["LeftRightImagery"], + include_datasets=datasets, + results="./results/", + overwrite=False, + plot=False, + output="./benchmark/", +) + +############################################################################### +# Benchmark prints a summary of the results. Detailed results are saved in a +# pandas dataframe, and can be used to generate figures. The analysis & figures +# are saved in the ``benchmark`` folder. +results.head() + +order_list = [ + "CSP + SVM", + "Tangent Space LR", + "EN Grid", + "CSP + LDA Grid", + "Keras_EEGNet_8_2", +] + +############################################################################### +# Plotting the results +# -------------------- +# We can plot the results using the ``codecarbon_plot`` function, generated +# below. This function takes the dataframe returned by the ``benchmark`` +# function as input, and returns a pyplot figure. +# The ``order_list`` argument is used to specify the order of the pipelines in +# the plot. + +codecarbon_plot(results, order_list, country="(France)") + +############################################################################### +# The result expected will be the following image, but varying depending on the +# machine and the country used to run the example. +# +# .. image:: ../images/example_codecarbon.png +# :align: center +# :alt: carbon_example +# +############################################################################### diff --git a/docs/_downloads/225d2b2bd0960a1fa6a57be5e1838af9/plot_benchmark.ipynb b/docs/_downloads/225d2b2bd0960a1fa6a57be5e1838af9/plot_benchmark.ipynb new file mode 100644 index 00000000..5add2d09 --- /dev/null +++ b/docs/_downloads/225d2b2bd0960a1fa6a57be5e1838af9/plot_benchmark.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Examples of how to use MOABB to benchmark pipelines.\nBenchmarking with MOABB\n=======================\n\nThis example shows how to use MOABB to benchmark a set of pipelines\non all available datasets. For this example, we will use only one\ndataset to keep the computation time low, but this benchmark is designed\nto easily scale to many datasets.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Sylvain Chevallier \n#\n# License: BSD (3-clause)\n\nimport matplotlib.pyplot as plt\n\nfrom moabb import benchmark, set_log_level\nfrom moabb.analysis.plotting import score_plot\nfrom moabb.paradigms import LeftRightImagery\n\n\nset_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading the pipelines\n\nThe ML pipelines used in benchmark are defined in YAML files, following a\nsimple format. It simplifies sharing and reusing pipelines across benchmarks,\nreproducing state-of-the-art results.\n\nMOABB comes with complete list of pipelines that cover most of the successful\napproaches in the literature. You can find them in the\n[pipelines folder](https://github.com/NeuroTechX/moabb/tree/develop/pipelines).\nFor this example, we will use a folder with only 2 pipelines, to keep the\ncomputation time low.\n\nThis is an example of a pipeline defined in YAML, defining on which paradigms it\ncan be used, the original publication, and the steps to perform using a\nscikit-learn API. In this case, a CSP + SVM pipeline, the covariance are estimated\nto compute a CSP filter and then a linear SVM is trained on the CSP filtered\nsignals.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "with open(\"sample_pipelines/CSP_SVM.yml\", \"r\") as f:\n lines = f.readlines()\n for line in lines:\n print(line, end=\"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ``sample_pipelines`` folder contains a second pipeline, a logistic regression\nperformed in the tangent space using Riemannian geometry.\n\n## Selecting the datasets (optional)\n\nIf you want to limit your benchmark on a subset of datasets, you can use the\n``include_datasets`` and ``exclude_datasets`` arguments. You will need either\nto provide the dataset's object, or a the dataset's code. To get the list of\navailable dataset's code for a given paradigm, you can use the following command:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = LeftRightImagery()\nfor d in paradigm.datasets:\n print(d.code)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, we will use only the last dataset, 'Zhou 2016'.\n\n## Running the benchmark\n\nThe benchmark is run using the ``benchmark`` function. You need to specify the\nfolder containing the pipelines to use, the kind of evaluation and the paradigm\nto use. By default, the benchmark will use all available datasets for all\nparadigms listed in the pipelines. You could restrict to specific evaluation and\nparadigm using the ``evaluations`` and ``paradigms`` arguments.\n\nTo save computation time, the results are cached. If you want to re-run the\nbenchmark, you can set the ``overwrite`` argument to ``True``.\n\nIt is possible to indicate the folder to cache the results and the one to save\nthe analysis & figures. By default, the results are saved in the ``results``\nfolder, and the analysis & figures are saved in the ``benchmark`` folder.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "results = benchmark(\n pipelines=\"./sample_pipelines/\",\n evaluations=[\"WithinSession\"],\n paradigms=[\"LeftRightImagery\"],\n include_datasets=[\"Zhou2016\"],\n results=\"./results/\",\n overwrite=False,\n plot=False,\n output=\"./benchmark/\",\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Benchmark prints a summary of the results. Detailed results are saved in a\npandas dataframe, and can be used to generate figures. The analysis & figures\nare saved in the ``benchmark`` folder.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "score_plot(results)\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/284aff1e2748c45a1efdc5d7071c4a77/plot_benchmark_braindecode.py b/docs/_downloads/284aff1e2748c45a1efdc5d7071c4a77/plot_benchmark_braindecode.py new file mode 100644 index 00000000..3b69b56b --- /dev/null +++ b/docs/_downloads/284aff1e2748c45a1efdc5d7071c4a77/plot_benchmark_braindecode.py @@ -0,0 +1,122 @@ +""" +======================================================================= +Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures +======================================================================= +This example shows how to use MOABB to benchmark a set of Braindecode pipelines (deep learning +architectures) on all available datasets. +For this example, we will use only 2 datasets to keep the computation time low, but this benchmark is designed +to easily scale to many datasets. +""" + +# Authors: Igor Carrara +# Bruno Aristimunha +# Sylvain Chevallier +# +# License: BSD (3-clause) + +import os + +import matplotlib.pyplot as plt +import torch +from absl.logging import ERROR, set_verbosity + +from moabb import benchmark, set_log_level +from moabb.analysis.plotting import score_plot +from moabb.datasets import BNCI2014_001, BNCI2014_004 +from moabb.utils import setup_seed + + +set_log_level("info") +# Avoid output Warning +set_verbosity(ERROR) +os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" + +# Print Information PyTorch +print(f"Torch Version: {torch.__version__}") + +# Set up GPU if it is there +cuda = torch.cuda.is_available() +device = "cuda" if cuda else "cpu" +print("GPU is", "AVAILABLE" if cuda else "NOT AVAILABLE") + +############################################################################### +# In this example, we will use only 2 subjects from the dataset ``BNCI2014_001`` and ``BNCI2014_004``. +# +# Running the benchmark +# --------------------- +# +# The benchmark is run using the ``benchmark`` function. You need to specify the +# folder containing the pipelines, the kind of evaluation, and the paradigm +# to use. By default, the benchmark will use all available datasets for all +# paradigms listed in the pipelines. You could restrict to specific evaluation and +# paradigm using the ``evaluations`` and ``paradigms`` arguments. +# +# To save computation time, the results are cached. If you want to re-run the +# benchmark, you can set the ``overwrite`` argument to ``True``. +# +# It is possible to indicate the folder to cache the results and the one to save +# the analysis & figures. By default, the results are saved in the ``results`` +# folder, and the analysis & figures are saved in the ``benchmark`` folder. +# +# This code is implemented to run on CPU. If you're using a GPU, do not use multithreading +# (i.e. set n_jobs=1) +# +# In order to allow the benchmark function to work with return_epoch=True (Required to use Braindecode( +# we need to call each pipeline as "braindecode_xxx...", with xxx the name of the model to be +# handled correctly by the benchmark function. + +# Set up reproducibility of Tensorflow +setup_seed(42) + +# Restrict this example only to the first two subjects of BNCI2014_001 +dataset = BNCI2014_001() +dataset2 = BNCI2014_004() +dataset.subject_list = dataset.subject_list[:2] +dataset2.subject_list = dataset2.subject_list[:2] +datasets = [dataset, dataset2] + +results = benchmark( + pipelines="./pipelines_braindecode", + evaluations=["CrossSession"], + paradigms=["LeftRightImagery"], + include_datasets=datasets, + results="./results/", + overwrite=False, + plot=False, + output="./benchmark/", + n_jobs=-1, +) + +############################################################################### +# The deep learning architectures implemented in MOABB using Braindecode are: +# +# - Shallow Convolutional Network [1]_ +# - Deep Convolutional Network [1]_ +# - EEGNetv4 [2]_ +# - EEGInception [3]_ +# +# Benchmark prints a summary of the results. Detailed results are saved in a +# pandas dataframe, and can be used to generate figures. The analysis & figures +# are saved in the ``benchmark`` folder. + +score_plot(results) +plt.show() + +############################################################################## +# References +# ---------- +# .. [1] Schirrmeister, R. T., Springenberg, J. T., Fiederer, L. D. J., +# Glasstetter, M., Eggensperger, K., Tangermann, M., ... & Ball, T. (2017). +# `Deep learning with convolutional neural networks for EEG decoding and +# visualization `_. +# Human brain mapping, 38(11), 5391-5420. +# .. [2] Lawhern, V. J., Solon, A. J., Waytowich, N. R., Gordon, S. M., +# Hung, C. P., & Lance, B. J. (2018). `EEGNet: a compact convolutional neural +# network for EEG-based brain-computer interfaces. +# `_ +# Journal of neural engineering, 15(5), 056013. +# .. [3] Santamaria-Vazquez, E., Martinez-Cagigal, V., Vaquerizo-Villar, +# F., & Hornero, R. (2020). `EEG-inception: A novel deep convolutional neural network +# for assistive ERP-based brain-computer interfaces. +# `_ +# IEEE Transactions on Neural Systems and Rehabilitation Engineering diff --git a/docs/_downloads/2a0ca02a0f1b91ece5afbc9bdeceffe4/plot_fixed_interval_windows.ipynb b/docs/_downloads/2a0ca02a0f1b91ece5afbc9bdeceffe4/plot_fixed_interval_windows.ipynb new file mode 100644 index 00000000..56447cef --- /dev/null +++ b/docs/_downloads/2a0ca02a0f1b91ece5afbc9bdeceffe4/plot_fixed_interval_windows.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Fixed interval windows processing\n\nThis example shows how to process a dataset using the\n:class:`moabb.paradigms.FixedIntervalWindowsProcessing` paradigm. This paradigm\ncreates epochs at fixed intervals, ignoring the stim\nchannel and events of the datasets. Therefore, it is\ncompatible with all the datasets. Unfortunately,\nthis paradigm is not compatible with the MOABB evaluation\nframework. However, it can be used to process datasets\nfor unsupervised algorithms.\n\nIn this example, we will use the Zhou2016 dataset because\nit is relatively small and can be downloaded quickly.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Pierre Guetschel \n#\n# License: BSD (3-clause)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\nimport mne\nimport numpy as np\n\nfrom moabb import set_log_level\nfrom moabb.datasets import Zhou2016\nfrom moabb.paradigms import FixedIntervalWindowsProcessing, MotorImagery\n\n\nset_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Process a dataset\n\nTo process a dataset with\n:class:`moabb.paradigms.FixedIntervalWindowsProcessing` , you can use the\nmethod as with every other paradigm. The only additional parameters are\n``length``, ``stride``, ``start_offset``, and ``stop_offset``. They are\nall parametrised in seconds. ``length`` is the length of the epochs,\n``stride`` is the time between the onset of two consecutive epochs,\n``start_offset`` is the offset between each run start and their first\nepoch, and ``stop_offset`` is the offset between each run start and their\nlast epoch. The default values are ``length=5``, ``stride=10``,\n``start_offset=0``, and ``stop_offset=None`` (i.e. end of the run).\n\nAn example usage of :class:`moabb.paradigms.FixedIntervalWindowsProcessing`\nwith the :class:`moabb.datasets.Zhou2016` dataset:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset = Zhou2016()\nprocessing = FixedIntervalWindowsProcessing(\n # new parameters:\n length=100,\n stride=50,\n start_offset=300,\n stop_offset=900, # we epoch 10 minutes per run, starting at 5 minutes (i.e. 300 seconds)\n # parameters common with other paradigms:\n resample=100,\n fmin=7,\n fmax=45,\n baseline=None,\n channels=None,\n)\nX, labels, metadata = processing.get_data(dataset=dataset, subjects=[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this dataset, there are three sessions per subject and two runs per\nsession:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for column in metadata.columns:\n print(f\"{column}s: {metadata[column].unique()}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We expect to obtained ``(stop_offset - start_offset - length) / stride``;\ni.e. $(900-300-100)/50=10$ epochs per run. Here we have 3*2=6 runs.\nAnd indeed, we obtain\na total of $6*10=60$ epochs:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(f\"Number of epochs: {len(X)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Note

To apply a bank of bandpass filters, you can use the\n :class:`moabb.paradigms.FilterBankFixedIntervalWindowsProcessing`\n paradigm instead.

\n\n## Print the events\n\nWe can print the position of the created epochs within the run next to\nthe original events of the dataset. For this, we will first instantiate\na :class:`moabb.paradigms.MotorImagery` paradigm to recover the original\nevents of the dataset:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = MotorImagery(\n resample=100,\n fmin=7,\n fmax=45,\n baseline=None,\n channels=None,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we can recover the events of both paradigms using the\n``_get_events_pipeline`` method:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "events_pipeline_dataset = paradigm._get_events_pipeline(dataset)\nevents_pipeline_fixed = processing._get_events_pipeline(dataset)\nraw = dataset.get_data(subjects=[1])[1][\"0\"][\"0\"]\nevents_dataset = events_pipeline_dataset.transform(raw)\nevents_fixed = events_pipeline_fixed.transform(raw)\nevents = np.concatenate([events_dataset, events_fixed])\nevent_id = dict(**paradigm.used_events(dataset), **processing.used_events(dataset))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we can plot the events. The artificial events created by\n:class:`moabb.paradigms.FixedIntervalWindowsProcessing` are named\n``\"Windows\"``:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig = mne.viz.plot_events(\n events,\n sfreq=raw.info[\"sfreq\"],\n event_id=event_id,\n)\nfig.subplots_adjust(right=0.7)\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the epochs were effectively created at a fixed interval\nevery 50 seconds between 300 and 900 seconds, and ignoring\nthe original events of the dataset.\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/321fdb18266d890de5e5f577f03c2c73/plot_within_session_p300.ipynb b/docs/_downloads/321fdb18266d890de5e5f577f03c2c73/plot_within_session_p300.ipynb new file mode 100644 index 00000000..e10a3c3e --- /dev/null +++ b/docs/_downloads/321fdb18266d890de5e5f577f03c2c73/plot_within_session_p300.ipynb @@ -0,0 +1,144 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Within Session P300\n\nThis example shows how to perform a within session analysis on three different\nP300 datasets.\n\nWe will compare two pipelines :\n\n- Riemannian geometry\n- XDAWN with Linear Discriminant Analysis\n\nWe will use the P300 paradigm, which uses the AUC as metric.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Pedro Rodrigues \n#\n# License: BSD (3-clause)\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom mne.decoding import Vectorizer\nfrom pyriemann.estimation import Xdawn, XdawnCovariances\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nfrom moabb.datasets import BNCI2014_009\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import P300" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "getting rid of the warnings about the future\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "warnings.simplefilter(action=\"ignore\", category=FutureWarning)\nwarnings.simplefilter(action=\"ignore\", category=RuntimeWarning)\n\nmoabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Pipelines\n\nPipelines must be a dict of sklearn pipeline transformer.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipelines = {}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have to do this because the classes are called 'Target' and 'NonTarget'\nbut the evaluation function uses a LabelEncoder, transforming them\nto 0 and 1\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "labels_dict = {\"Target\": 1, \"NonTarget\": 0}\n\npipelines[\"RG+LDA\"] = make_pipeline(\n XdawnCovariances(\n nfilter=2, classes=[labels_dict[\"Target\"]], estimator=\"lwf\", xdawn_estimator=\"scm\"\n ),\n TangentSpace(),\n LDA(solver=\"lsqr\", shrinkage=\"auto\"),\n)\n\npipelines[\"Xdw+LDA\"] = make_pipeline(\n Xdawn(nfilter=2, estimator=\"scm\"), Vectorizer(), LDA(solver=\"lsqr\", shrinkage=\"auto\")\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nWe define the paradigm (P300) and use all three datasets available for it.\nThe evaluation will return a DataFrame containing a single AUC score for\neach subject / session of the dataset, and for each pipeline.\n\nResults are saved into the database, so that if you add a new pipeline, it\nwill not run again the evaluation unless a parameter has changed. Results can\nbe overwritten if necessary.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = P300(resample=128)\ndataset = BNCI2014_009()\ndataset.subject_list = dataset.subject_list[:2]\ndatasets = [dataset]\noverwrite = True # set to True if we want to overwrite cached results\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm, datasets=datasets, suffix=\"examples\", overwrite=overwrite\n)\nresults = evaluation.process(pipelines)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\nHere we plot the results to compare the two pipelines\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(facecolor=\"white\", figsize=[8, 4])\n\nsns.stripplot(\n data=results,\n y=\"score\",\n x=\"pipeline\",\n ax=ax,\n jitter=True,\n alpha=0.5,\n zorder=1,\n palette=\"Set1\",\n)\nsns.pointplot(data=results, y=\"score\", x=\"pipeline\", ax=ax, palette=\"Set1\")\n\nax.set_ylabel(\"ROC AUC\")\nax.set_ylim(0.5, 1)\n\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/33bee7d7204a7cb56293bd1d838b63f8/plot_statistical_analysis.ipynb b/docs/_downloads/33bee7d7204a7cb56293bd1d838b63f8/plot_statistical_analysis.ipynb new file mode 100644 index 00000000..eb692ea3 --- /dev/null +++ b/docs/_downloads/33bee7d7204a7cb56293bd1d838b63f8/plot_statistical_analysis.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Statistical Analysis\n\nThe MOABB codebase comes with convenience plotting utilities and some\nstatistical testing. This tutorial focuses on what those exactly are and how\nthey can be used.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Vinay Jayaram \n#\n# License: BSD (3-clause)\n# sphinx_gallery_thumbnail_number = -2\n\nimport matplotlib.pyplot as plt\nfrom mne.decoding import CSP\nfrom pyriemann.estimation import Covariances\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nimport moabb.analysis.plotting as moabb_plt\nfrom moabb.analysis.meta_analysis import ( # noqa: E501\n compute_dataset_statistics,\n find_significant_differences,\n)\nfrom moabb.datasets import BNCI2014_001\nfrom moabb.evaluations import CrossSessionEvaluation\nfrom moabb.paradigms import LeftRightImagery\n\n\nmoabb.set_log_level(\"info\")\n\nprint(__doc__)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Results Generation\n\nFirst we need to set up a paradigm, dataset list, and some pipelines to\ntest. This is explored more in the examples -- we choose left vs right\nimagery paradigm with a single bandpass. There is only one dataset here but\nany number can be added without changing this workflow.\n\n## Create Pipelines\n\nPipelines must be a dict of sklearn pipeline transformer.\n\nThe CSP implementation from MNE is used. We selected 8 CSP components, as\nusually done in the literature.\n\nThe Riemannian geometry pipeline consists in covariance estimation, tangent\nspace mapping and finally a logistic regression for the classification.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipelines = {}\n\npipelines[\"CSP+LDA\"] = make_pipeline(CSP(n_components=8), LDA())\n\npipelines[\"RG+LR\"] = make_pipeline(Covariances(), TangentSpace(), LogisticRegression())\n\npipelines[\"CSP+LR\"] = make_pipeline(CSP(n_components=8), LogisticRegression())\n\npipelines[\"RG+LDA\"] = make_pipeline(Covariances(), TangentSpace(), LDA())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nWe define the paradigm (LeftRightImagery) and the dataset (BNCI2014_001).\nThe evaluation will return a DataFrame containing a single AUC score for\neach subject / session of the dataset, and for each pipeline.\n\nResults are saved into the database, so that if you add a new pipeline, it\nwill not run again the evaluation unless a parameter has changed. Results can\nbe overwritten if necessary.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = LeftRightImagery()\ndataset = BNCI2014_001()\ndataset.subject_list = dataset.subject_list[:4]\ndatasets = [dataset]\noverwrite = True # set to False if we want to use cached results\nevaluation = CrossSessionEvaluation(\n paradigm=paradigm, datasets=datasets, suffix=\"stats\", overwrite=overwrite\n)\n\nresults = evaluation.process(pipelines)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## MOABB Plotting\n\nHere we plot the results using some of the convenience methods within the\ntoolkit. The score_plot visualizes all the data with one score per subject\nfor every dataset and pipeline.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig = moabb_plt.score_plot(results)\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For a comparison of two algorithms, there is the paired_plot, which plots\nperformance in one versus the performance in the other over all chosen\ndatasets. Note that there is only one score per subject, regardless of the\nnumber of sessions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig = moabb_plt.paired_plot(results, \"CSP+LDA\", \"RG+LDA\")\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Statistical Testing and Further Plots\n\nIf the statistical significance of results is of interest, the method\ncompute_dataset_statistics allows one to show a meta-analysis style plot as\nwell. For an overview of how all algorithms perform in comparison with each\nother, the method find_significant_differences and the summary_plot are\npossible.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "stats = compute_dataset_statistics(results)\nP, T = find_significant_differences(stats)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The meta-analysis style plot shows the standardized mean difference within\neach tested dataset for the two algorithms in question, in addition to a\nmeta-effect and significance both per-dataset and overall.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig = moabb_plt.meta_analysis_plot(stats, \"CSP+LDA\", \"RG+LDA\")\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The summary plot shows the effect and significance related to the hypothesis\nthat the algorithm on the y-axis significantly outperformed the algorithm on\nthe x-axis over all datasets\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "moabb_plt.summary_plot(P, T)\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/3492da53de2fcbbc267c5e45e1d04fb9/plot_learning_curve_p300.ipynb b/docs/_downloads/3492da53de2fcbbc267c5e45e1d04fb9/plot_learning_curve_p300.ipynb new file mode 100644 index 00000000..f07388ab --- /dev/null +++ b/docs/_downloads/3492da53de2fcbbc267c5e45e1d04fb9/plot_learning_curve_p300.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Within Session P300 with Learning Curve\n\nThis example shows how to perform a within session analysis while also\ncreating learning curves for a P300 dataset.\nAdditionally, we will evaluate external code. Make sure to have tdlda installed, which\ncan be found in requirements_external.txt\n\nWe will compare two pipelines :\n\n- Riemannian geometry with Linear Discriminant Analysis\n- XDAWN and Linear Discriminant Analysis\n\nWe will use the P300 paradigm, which uses the AUC as metric.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Jan Sosulski\n#\n# License: BSD (3-clause)\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns\nfrom mne.decoding import Vectorizer\nfrom pyriemann.estimation import XdawnCovariances\nfrom pyriemann.spatialfilters import Xdawn\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nfrom moabb.datasets import BNCI2014_009\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import P300\n\n\n# getting rid of the warnings about the future (on s'en fout !)\nwarnings.simplefilter(action=\"ignore\", category=FutureWarning)\nwarnings.simplefilter(action=\"ignore\", category=RuntimeWarning)\n\nmoabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Pipelines\n\nPipelines must be a dict of sklearn pipeline transformer.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "processing_sampling_rate = 128\npipelines = {}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have to do this because the classes are called 'Target' and 'NonTarget'\nbut the evaluation function uses a LabelEncoder, transforming them\nto 0 and 1\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "labels_dict = {\"Target\": 1, \"NonTarget\": 0}\n\n# Riemannian geometry based classification\npipelines[\"RG+LDA\"] = make_pipeline(\n XdawnCovariances(nfilter=5, estimator=\"lwf\", xdawn_estimator=\"scm\"),\n TangentSpace(),\n LDA(solver=\"lsqr\", shrinkage=\"auto\"),\n)\n\npipelines[\"Xdw+LDA\"] = make_pipeline(\n Xdawn(nfilter=2, estimator=\"scm\"), Vectorizer(), LDA(solver=\"lsqr\", shrinkage=\"auto\")\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nWe define the paradigm (P300) and use all three datasets available for it.\nThe evaluation will return a DataFrame containing AUCs for each permutation\nand dataset size.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = P300(resample=processing_sampling_rate)\ndataset = BNCI2014_009()\n# Remove the slicing of the subject list to evaluate multiple subjects\ndataset.subject_list = dataset.subject_list[1:2]\ndatasets = [dataset]\noverwrite = True # set to True if we want to overwrite cached results\ndata_size = dict(policy=\"ratio\", value=np.geomspace(0.02, 1, 4))\n# When the training data is sparse, perform more permutations than when we have a lot of data\nn_perms = np.floor(np.geomspace(20, 2, len(data_size[\"value\"]))).astype(int)\n# Guarantee reproducibility\nnp.random.seed(7536298)\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm,\n datasets=datasets,\n data_size=data_size,\n n_perms=n_perms,\n suffix=\"examples_lr\",\n overwrite=overwrite,\n)\n\nresults = evaluation.process(pipelines)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\nWe plot the accuracy as a function of the number of training samples, for\neach pipeline\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(facecolor=\"white\", figsize=[8, 4])\n\nn_subs = len(dataset.subject_list)\n\nif n_subs > 1:\n r = results.groupby([\"pipeline\", \"subject\", \"data_size\"]).mean().reset_index()\nelse:\n r = results\n\nsns.pointplot(data=r, x=\"data_size\", y=\"score\", hue=\"pipeline\", ax=ax, palette=\"Set1\")\n\nerrbar_meaning = \"subjects\" if n_subs > 1 else \"permutations\"\ntitle_str = f\"Errorbar shows Mean-CI across {errbar_meaning}\"\nax.set_xlabel(\"Amount of training samples\")\nax.set_ylabel(\"ROC AUC\")\nax.set_title(title_str)\nfig.tight_layout()\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/38abfe5b8b42dcb9de08824fd90d346b/plot_cross_subject_ssvep.ipynb b/docs/_downloads/38abfe5b8b42dcb9de08824fd90d346b/plot_cross_subject_ssvep.ipynb new file mode 100644 index 00000000..5814e615 --- /dev/null +++ b/docs/_downloads/38abfe5b8b42dcb9de08824fd90d346b/plot_cross_subject_ssvep.ipynb @@ -0,0 +1,234 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Cross-Subject SSVEP\nThis example shows how to perform a cross-subject analysis on an SSVEP dataset.\nWe will compare four pipelines :\n\n- Riemannian Geometry\n- CCA\n- TRCA\n- MsetCCA\n\nWe will use the SSVEP paradigm, which uses the AUC as metric.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Sylvain Chevallier \n#\n# License: BSD (3-clause)\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport seaborn as sns\nfrom pyriemann.estimation import Covariances\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nfrom moabb.datasets import Kalunga2016\nfrom moabb.evaluations import CrossSubjectEvaluation\nfrom moabb.paradigms import SSVEP, FilterBankSSVEP\nfrom moabb.pipelines import SSVEP_CCA, SSVEP_TRCA, ExtendedSSVEPSignal, SSVEP_MsetCCA\n\n\nwarnings.simplefilter(action=\"ignore\", category=FutureWarning)\nwarnings.simplefilter(action=\"ignore\", category=RuntimeWarning)\nmoabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading Dataset\n\nWe will load the data from the first 2 subjects of the ``SSVEP_Exo`` dataset\nand compare two algorithms on this set. One of the algorithms could only\nprocess class associated with a stimulation frequency, we will thus drop\nthe resting class. As the resting class is the last defined class, picking\nthe first three classes (out of four) allows to focus only on the stimulation\nfrequency.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "n_subject = 2\ndataset = Kalunga2016()\ndataset.subject_list = dataset.subject_list[:n_subject]\ninterval = dataset.interval" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Choose Paradigm\n\nWe define the paradigms (SSVEP, SSVEP TRCA, SSVEP MsetCCA, and FilterBankSSVEP) and\nuse the dataset Kalunga2016. All 3 SSVEP paradigms applied a bandpass filter (10-42 Hz) on\nthe data, which include all stimuli frequencies and their first harmonics,\nwhile the FilterBankSSVEP paradigm uses as many bandpass filters as\nthere are stimulation frequencies (here 3). For each stimulation frequency\nthe EEG is filtered with a 1 Hz-wide bandpass filter centered on the\nfrequency. This results in ``n_classes`` copies of the signal, filtered for each\nclass, as used in the filterbank motor imagery paradigms.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = SSVEP(fmin=10, fmax=42, n_classes=3)\nparadigm_TRCA = SSVEP(fmin=10, fmax=42, n_classes=3)\nparadigm_MSET_CCA = SSVEP(fmin=10, fmax=42, n_classes=3)\nparadigm_fb = FilterBankSSVEP(filters=None, n_classes=3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Classes are defined by the frequency of the stimulation, here we use\nthe first two frequencies of the dataset, 13 and 17 Hz.\nThe evaluation function uses a LabelEncoder, transforming them\nto 0 and 1\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "freqs = paradigm.used_events(dataset)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Pipelines\n\nPipelines must be a dict of sklearn pipeline transformer.\nThe first pipeline uses Riemannian geometry, by building an extended\ncovariance matrices from the signal filtered around the considered\nfrequency and applying a logistic regression in the tangent plane.\nThe second pipeline relies on the above defined CCA classifier.\nThe third pipeline relies on the TRCA algorithm,\nand the fourth uses the MsetCCA algorithm. Both CCA based methods\n(i.e. CCA and MsetCCA) used 3 CCA components.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipelines_fb = {}\npipelines_fb[\"RG+LogReg\"] = make_pipeline(\n ExtendedSSVEPSignal(),\n Covariances(estimator=\"lwf\"),\n TangentSpace(),\n LogisticRegression(solver=\"lbfgs\", multi_class=\"auto\"),\n)\n\npipelines = {}\npipelines[\"CCA\"] = make_pipeline(SSVEP_CCA(interval=interval, freqs=freqs, n_harmonics=2))\n\npipelines_TRCA = {}\npipelines_TRCA[\"TRCA\"] = make_pipeline(SSVEP_TRCA(interval=interval, freqs=freqs))\n\npipelines_MSET_CCA = {}\npipelines_MSET_CCA[\"MSET_CCA\"] = make_pipeline(SSVEP_MsetCCA(freqs=freqs))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nThe evaluation will return a DataFrame containing an accuracy score for\neach subject / session of the dataset, and for each pipeline.\n\nResults are saved into the database, so that if you add a new pipeline, it\nwill not run again the evaluation unless a parameter has changed. Results can\nbe overwritten if necessary.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "overwrite = False # set to True if we want to overwrite cached results\n\nevaluation = CrossSubjectEvaluation(\n paradigm=paradigm, datasets=dataset, overwrite=overwrite\n)\nresults = evaluation.process(pipelines)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Filter bank processing, determine the filter automatically from the\nstimulation frequency values of events.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "evaluation_fb = CrossSubjectEvaluation(\n paradigm=paradigm_fb, datasets=dataset, overwrite=overwrite\n)\nresults_fb = evaluation_fb.process(pipelines_fb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "TRCA processing also relies on filter bank that is automatically designed.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "evaluation_TRCA = CrossSubjectEvaluation(\n paradigm=paradigm_TRCA, datasets=dataset, overwrite=overwrite\n)\nresults_TRCA = evaluation_TRCA.process(pipelines_TRCA)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "MsetCCA processing\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "evaluation_MSET_CCA = CrossSubjectEvaluation(\n paradigm=paradigm_MSET_CCA, datasets=dataset, overwrite=overwrite\n)\nresults_MSET_CCA = evaluation_MSET_CCA.process(pipelines_MSET_CCA)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After processing the four, we simply concatenate the results.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "results = pd.concat([results, results_fb, results_TRCA, results_MSET_CCA])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\nHere we display the results as stripplot, with a pointplot for error bar.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(facecolor=\"white\", figsize=[8, 4])\nsns.stripplot(\n data=results,\n y=\"score\",\n x=\"pipeline\",\n ax=ax,\n jitter=True,\n alpha=0.5,\n zorder=1,\n palette=\"Set1\",\n)\nsns.pointplot(data=results, y=\"score\", x=\"pipeline\", ax=ax, palette=\"Set1\")\nax.set_ylabel(\"Accuracy\")\nax.set_ylim(0.1, 0.6)\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/39844aaaee383c2803c6ac93e64037d5/plot_within_session_p300.py b/docs/_downloads/39844aaaee383c2803c6ac93e64037d5/plot_within_session_p300.py new file mode 100644 index 00000000..5939879d --- /dev/null +++ b/docs/_downloads/39844aaaee383c2803c6ac93e64037d5/plot_within_session_p300.py @@ -0,0 +1,117 @@ +""" +=========================== +Within Session P300 +=========================== + +This example shows how to perform a within session analysis on three different +P300 datasets. + +We will compare two pipelines : + +- Riemannian geometry +- XDAWN with Linear Discriminant Analysis + +We will use the P300 paradigm, which uses the AUC as metric. + +""" + +# Authors: Pedro Rodrigues +# +# License: BSD (3-clause) + +import warnings + +import matplotlib.pyplot as plt +import seaborn as sns +from mne.decoding import Vectorizer +from pyriemann.estimation import Xdawn, XdawnCovariances +from pyriemann.tangentspace import TangentSpace +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.pipeline import make_pipeline + +import moabb +from moabb.datasets import BNCI2014_009 +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import P300 + + +############################################################################## +# getting rid of the warnings about the future +warnings.simplefilter(action="ignore", category=FutureWarning) +warnings.simplefilter(action="ignore", category=RuntimeWarning) + +moabb.set_log_level("info") + +############################################################################## +# Create Pipelines +# ---------------- +# +# Pipelines must be a dict of sklearn pipeline transformer. + + +pipelines = {} + +############################################################################## +# We have to do this because the classes are called 'Target' and 'NonTarget' +# but the evaluation function uses a LabelEncoder, transforming them +# to 0 and 1 +labels_dict = {"Target": 1, "NonTarget": 0} + +pipelines["RG+LDA"] = make_pipeline( + XdawnCovariances( + nfilter=2, classes=[labels_dict["Target"]], estimator="lwf", xdawn_estimator="scm" + ), + TangentSpace(), + LDA(solver="lsqr", shrinkage="auto"), +) + +pipelines["Xdw+LDA"] = make_pipeline( + Xdawn(nfilter=2, estimator="scm"), Vectorizer(), LDA(solver="lsqr", shrinkage="auto") +) + +############################################################################## +# Evaluation +# ---------- +# +# We define the paradigm (P300) and use all three datasets available for it. +# The evaluation will return a DataFrame containing a single AUC score for +# each subject / session of the dataset, and for each pipeline. +# +# Results are saved into the database, so that if you add a new pipeline, it +# will not run again the evaluation unless a parameter has changed. Results can +# be overwritten if necessary. + +paradigm = P300(resample=128) +dataset = BNCI2014_009() +dataset.subject_list = dataset.subject_list[:2] +datasets = [dataset] +overwrite = True # set to True if we want to overwrite cached results +evaluation = WithinSessionEvaluation( + paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite +) +results = evaluation.process(pipelines) + +############################################################################## +# Plot Results +# ---------------- +# +# Here we plot the results to compare the two pipelines + +fig, ax = plt.subplots(facecolor="white", figsize=[8, 4]) + +sns.stripplot( + data=results, + y="score", + x="pipeline", + ax=ax, + jitter=True, + alpha=0.5, + zorder=1, + palette="Set1", +) +sns.pointplot(data=results, y="score", x="pipeline", ax=ax, palette="Set1") + +ax.set_ylabel("ROC AUC") +ax.set_ylim(0.5, 1) + +plt.show() diff --git a/docs/_downloads/3bb6d35e266c94de44c44ec75aa9d550/plot_mne_and_scikit_estimators.py b/docs/_downloads/3bb6d35e266c94de44c44ec75aa9d550/plot_mne_and_scikit_estimators.py new file mode 100644 index 00000000..4bfa5cf9 --- /dev/null +++ b/docs/_downloads/3bb6d35e266c94de44c44ec75aa9d550/plot_mne_and_scikit_estimators.py @@ -0,0 +1,199 @@ +""" +========================== +MNE Epochs-based pipelines +========================== + +This example shows how to use machine learning pipeline based on MNE Epochs +instead of Numpy arrays. This is useful to make the most of the MNE code base +and to embed EEG specific code inside sklearn pipelines. + +We will compare different pipelines for P300: +- Logistic regression, based on MNE Epochs +- XDAWN and Logistic Regression (LR), based on MNE Epochs +- XDAWN extended covariance and LR on tangent space, based on Numpy + +""" + +# Authors: Sylvain Chevallier +# +# License: BSD (3-clause) +# sphinx_gallery_thumbnail_number = 2 + +import warnings + +import matplotlib.pyplot as plt +import pandas as pd +from mne.decoding import Vectorizer +from mne.preprocessing import Xdawn +from pyriemann.estimation import XdawnCovariances +from pyriemann.tangentspace import TangentSpace +from sklearn.base import BaseEstimator, TransformerMixin +from sklearn.linear_model import LogisticRegression +from sklearn.pipeline import make_pipeline +from sklearn.preprocessing import StandardScaler + +import moabb +from moabb.analysis.meta_analysis import ( # noqa: E501 + compute_dataset_statistics, + find_significant_differences, +) +from moabb.analysis.plotting import paired_plot, summary_plot +from moabb.datasets import BNCI2014_009 +from moabb.evaluations import CrossSessionEvaluation +from moabb.paradigms import P300 + + +warnings.simplefilter(action="ignore", category=FutureWarning) +warnings.simplefilter(action="ignore", category=RuntimeWarning) +moabb.set_log_level("info") + +############################################################################### +# Loading Dataset +# --------------- +# +# Load 2 subjects of BNCI 2014-009 dataset, with 3 session each + +dataset = BNCI2014_009() +dataset.subject_list = dataset.subject_list[:3] +datasets = [dataset] +paradigm = P300() + +############################################################################## +# Get Data (optional) +# ------------------- +# +# To get access to the EEG signals downloaded from the dataset, you could +# use ``dataset.get_data([subject_id)`` to obtain the EEG as MNE Epochs, stored +# in a dictionary of sessions and runs. +# The ``paradigm.get_data(dataset=dataset, subjects=[subject_id])`` allows to +# obtain the preprocessed EEG data, the labels and the meta information. By +# default, the EEG is return as a Numpy array. With ``return_epochs=True``, MNE +# Epochs are returned. + +subject_list = [1] +sessions = dataset.get_data(subject_list) +X, labels, meta = paradigm.get_data(dataset=dataset, subjects=subject_list) +epochs, labels, meta = paradigm.get_data( + dataset=dataset, subjects=subject_list, return_epochs=True +) + + +############################################################################## +# A Simple MNE Pipeline +# --------------------- +# +# Using ``return_epochs=True`` in the evaluation, it is possible to design a +# pipeline based on MNE Epochs input. Let's create a simple one, that +# reshape the input data from epochs, rescale the data and uses a logistic +# regression to classify the data. We will need to write a basic Transformer +# estimator, that complies with +# `sklearn convention `_. +# This transformer will extract the data from an input Epoch, and reshapes into +# 2D array. + + +class MyVectorizer(BaseEstimator, TransformerMixin): + def __init__(self): + pass + + def fit(self, X, y=None): + arr = X.get_data() + self.features_shape_ = arr.shape[1:] + return self + + def transform(self, X, y=None): + arr = X.get_data() + return arr.reshape(len(arr), -1) + + +############################################################################## +# We will define a pipeline that is based on this new class, using a scaler +# and a logistic regression. This pipeline is evaluated across session using +# ROC-AUC metric. + +mne_ppl = {} +mne_ppl["MNE LR"] = make_pipeline( + MyVectorizer(), StandardScaler(), LogisticRegression(penalty="l1", solver="liblinear") +) + +mne_eval = CrossSessionEvaluation( + paradigm=paradigm, + datasets=datasets, + suffix="examples", + overwrite=True, + return_epochs=True, +) +mne_res = mne_eval.process(mne_ppl) + +############################################################################## +# Advanced MNE Pipeline +# --------------------- +# +# In some case, the MNE pipeline should have access to the original labels from +# the dataset. This is the case for the XDAWN code of MNE. One could pass +# `mne_labels` to evaluation in order to keep this label. +# As an example, we will define a pipeline that computes an XDAWN filter, rescale, +# then apply a logistic regression. + +mne_adv = {} +mne_adv["XDAWN LR"] = make_pipeline( + Xdawn(n_components=5, reg="ledoit_wolf", correct_overlap=False), + Vectorizer(), + StandardScaler(), + LogisticRegression(penalty="l1", solver="liblinear"), +) +adv_eval = CrossSessionEvaluation( + paradigm=paradigm, + datasets=datasets, + suffix="examples", + overwrite=True, + return_epochs=True, + mne_labels=True, +) +adv_res = mne_eval.process(mne_adv) + +############################################################################### +# Numpy-based Pipeline +# -------------------- +# +# For the comparison, we will define a Numpy-based pipeline that relies on +# pyriemann to estimate XDAWN-extended covariance matrices that are projected +# on the tangent space and classified with a logistic regression. + +sk_ppl = {} +sk_ppl["RG LR"] = make_pipeline( + XdawnCovariances(nfilter=5, estimator="lwf", xdawn_estimator="scm"), + TangentSpace(), + LogisticRegression(penalty="l1", solver="liblinear"), +) +sk_eval = CrossSessionEvaluation( + paradigm=paradigm, + datasets=datasets, + suffix="examples", + overwrite=True, +) +sk_res = sk_eval.process(sk_ppl) + +############################################################################### +# Combining Results +# ----------------- +# +# Even if the results have been obtained by different evaluation processes, it +# is possible to combine the resulting DataFrames to analyze and plot the +# results. + +all_res = pd.concat([mne_res, adv_res, sk_res]) + +############################################################################## +# We could compare the Euclidean and Riemannian performance using a `paired_plot` + +paired_plot(all_res, "XDAWN LR", "RG LR") + +############################################################################## +# All the results could be compared and statistical analysis could highlight the +# differences between pipelines. + +stats = compute_dataset_statistics(all_res) +P, T = find_significant_differences(stats) +summary_plot(P, T) +plt.show() diff --git a/docs/_downloads/3f1909c085169067146e835f0f34191d/noplot_tutorial_5_build_a_custom_dataset.py b/docs/_downloads/3f1909c085169067146e835f0f34191d/noplot_tutorial_5_build_a_custom_dataset.py new file mode 100644 index 00000000..24c7ee9a --- /dev/null +++ b/docs/_downloads/3f1909c085169067146e835f0f34191d/noplot_tutorial_5_build_a_custom_dataset.py @@ -0,0 +1,122 @@ +""" +==================================== +Tutorial 5: Creating a dataset class +==================================== +""" + +# Author: Gregoire Cattan +# +# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019 + +from pyriemann.classification import MDM +from pyriemann.estimation import ERPCovariances +from sklearn.pipeline import make_pipeline + +from moabb.datasets import Cattan2019_VR +from moabb.datasets.braininvaders import BI2014a +from moabb.datasets.compound_dataset import CompoundDataset +from moabb.datasets.utils import blocks_reps +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms.p300 import P300 + + +############################################################################## +# Initialization +# ------------------ +# +# This tutorial illustrates how to use the CompoundDataset to: +# 1) Select a few subjects/sessions/runs in an existing dataset +# 2) Merge two CompoundDataset into a new one +# 3) ... and finally use this new dataset on a pipeline +# (this steps is not specific to CompoundDataset) +# +# Let's define a paradigm and a pipeline for evaluation first. + +paradigm = P300() +pipelines = {} +pipelines["MDM"] = make_pipeline(ERPCovariances(estimator="lwf"), MDM(metric="riemann")) + + +############################################################################## +# Creation a selection of subject +# ------------------ +# +# We are going to great two CompoundDataset, namely CustomDataset1 & 2. +# A CompoundDataset accepts a subjects_list of subjects. +# It is a list of tuple. A tuple contains 4 values: +# - the original dataset +# - the subject number to select +# - the sessions. It can be: +# - a session name ('0') +# - a list of sessions (['0', '1']) +# - `None` to select all the sessions attributed to a subject +# - the runs. As for sessions, it can be a single run name, a list or `None`` (to select all runs). + + +class CustomDataset1(CompoundDataset): + def __init__(self): + biVR = Cattan2019_VR(virtual_reality=True, screen_display=True) + runs = blocks_reps([0, 2], [0, 1, 2, 3, 4], biVR.n_repetitions) + subjects_list = [ + (biVR, 1, "0VR", runs), + (biVR, 2, "0VR", runs), + ] + CompoundDataset.__init__( + self, + subjects_list=subjects_list, + code="CustomDataset1", + interval=[0, 1.0], + ) + + +class CustomDataset2(CompoundDataset): + def __init__(self): + bi2014 = BI2014a() + subjects_list = [ + (bi2014, 4, None, None), + (bi2014, 7, None, None), + ] + CompoundDataset.__init__( + self, + subjects_list=subjects_list, + code="CustomDataset2", + interval=[0, 1.0], + ) + + +############################################################################## +# Merging the datasets +# ------------------ +# +# We are now going to merge the two CompoundDataset into a single one. +# The implementation is straight forward. Instead of providing a list of subjects, +# you should provide a list of CompoundDataset. +# subjects_list = [CustomDataset1(), CustomDataset2()] + + +class CustomDataset3(CompoundDataset): + def __init__(self): + subjects_list = [CustomDataset1(), CustomDataset2()] + CompoundDataset.__init__( + self, + subjects_list=subjects_list, + code="CustomDataset3", + interval=[0, 1.0], + ) + + +############################################################################## +# Evaluate and display +# ------------------ +# +# Let's use a WithinSessionEvaluation to evaluate our new dataset. +# If you already new how to do this, nothing changed: +# The CompoundDataset can be used as a `normal` dataset. + +datasets = [CustomDataset3()] +evaluation = WithinSessionEvaluation( + paradigm=paradigm, datasets=datasets, overwrite=False, suffix="newdataset" +) +scores = evaluation.process(pipelines) + +print(scores) diff --git a/docs/_downloads/45332a7ce05680b6eb2282c04cab7d5b/plot_cross_session_multiple_datasets.ipynb b/docs/_downloads/45332a7ce05680b6eb2282c04cab7d5b/plot_cross_session_multiple_datasets.ipynb new file mode 100644 index 00000000..bac40dbe --- /dev/null +++ b/docs/_downloads/45332a7ce05680b6eb2282c04cab7d5b/plot_cross_session_multiple_datasets.ipynb @@ -0,0 +1,162 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Cross-Session on Multiple Datasets\n\nThis example shows how to perform a cross-session analysis on two MI datasets\nusing a CSP+LDA pipeline\n\nThe cross session evaluation context will evaluate performance using a leave\none session out cross-validation. For each session in the dataset, a model\nis trained on every other session and performance are evaluated on the current\nsession.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Sylvain Chevallier \n#\n# License: BSD (3-clause)\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom mne.decoding import CSP\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nfrom moabb.datasets import BNCI2014_001, Zhou2016\nfrom moabb.evaluations import CrossSessionEvaluation\nfrom moabb.paradigms import LeftRightImagery\n\n\nwarnings.simplefilter(action=\"ignore\", category=FutureWarning)\nwarnings.simplefilter(action=\"ignore\", category=RuntimeWarning)\nmoabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading Dataset\n\nLoad 2 subjects of BNCI 2014-004 and Zhou2016 datasets, with 2 session each\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "subj = [1, 2]\ndatasets = [Zhou2016(), BNCI2014_001()]\nfor d in datasets:\n d.subject_list = subj" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Choose Paradigm\n\nWe select the paradigm MI, applying a bandpass filter (8-35 Hz) on\nthe data and we will keep only left- and right-hand motor imagery\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = LeftRightImagery(fmin=8, fmax=35)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Pipelines\n\nUse the Common Spatial Patterns with 8 components and a Linear Discriminant\nAnalysis classifier.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipeline = {}\npipeline[\"CSP+LDA\"] = make_pipeline(CSP(n_components=8), LDA())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get Data (optional)\n\nTo get access to the EEG signals downloaded from the dataset, you could\nuse `dataset.get_data(subjects=[subject_id])` to obtain the EEG under\nan MNE format, stored in a dictionary of sessions and runs.\nOtherwise, `paradigm.get_data(dataset=dataset, subjects=[subject_id])`\nallows to obtain the EEG data in sklearn format, the labels and the meta\ninformation. The data are preprocessed according to the paradigm\nrequirements.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# X_all, labels_all, meta_all = [], [], []\n# for d in datasets:\n# # sessions = d.get_data(subjects=[2])\n# X, labels, meta = paradigm.get_data(dataset=d, subjects=[2])\n# X_all.append(X)\n# labels_all.append(labels)\n# meta_all.append(meta)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nThe evaluation will return a DataFrame containing a single AUC score for\neach subject / session of the dataset, and for each pipeline.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "overwrite = True # set to True if we want to overwrite cached results\n\nevaluation = CrossSessionEvaluation(\n paradigm=paradigm, datasets=datasets, suffix=\"examples\", overwrite=overwrite\n)\nresults = evaluation.process(pipeline)\n\nprint(results.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\nHere we plot the results, indicating the score for each session and subject\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sns.catplot(\n data=results,\n x=\"session\",\n y=\"score\",\n hue=\"subject\",\n col=\"dataset\",\n kind=\"bar\",\n palette=\"viridis\",\n)\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/47ae966f3ab36fc8884cda73c38e648d/plot_benchmark_grid_search.ipynb b/docs/_downloads/47ae966f3ab36fc8884cda73c38e648d/plot_benchmark_grid_search.ipynb new file mode 100644 index 00000000..901ce00a --- /dev/null +++ b/docs/_downloads/47ae966f3ab36fc8884cda73c38e648d/plot_benchmark_grid_search.ipynb @@ -0,0 +1,90 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Benchmarking with MOABB with Grid Search\n\nThis example shows how to use MOABB to benchmark a set of pipelines\non all available datasets. In particular we run the Gridsearch to select the best hyperparameter of some pipelines\nand save the gridsearch.\nFor this example, we will use only one dataset to keep the computation time low, but this benchmark is designed\nto easily scale to many datasets.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Igor Carrara \n#\n# License: BSD (3-clause)\n\nimport matplotlib.pyplot as plt\n\nfrom moabb import benchmark, set_log_level\nfrom moabb.analysis.plotting import score_plot\n\n\nset_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, we will use only the dataset 'Zhou 2016'.\n\n## Running the benchmark\n\nThe benchmark is run using the ``benchmark`` function. You need to specify the\nfolder containing the pipelines to use, the kind of evaluation and the paradigm\nto use. By default, the benchmark will use all available datasets for all\nparadigms listed in the pipelines. You could restrict to specific evaluation and\nparadigm using the ``evaluations`` and ``paradigms`` arguments.\n\nTo save computation time, the results are cached. If you want to re-run the\nbenchmark, you can set the ``overwrite`` argument to ``True``.\n\nIt is possible to indicate the folder to cache the results and the one to save\nthe analysis & figures. By default, the results are saved in the ``results``\nfolder, and the analysis & figures are saved in the ``benchmark`` folder.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# In the results folder we will save the gridsearch evaluation\n# When write the pipeline in ylm file we need to specify the parameter that we want to test, in format\n# pipeline-name__estimator-name_parameter. Note that pipeline and estimator names MUST\n# be in lower case (no capital letters allowed).\n# If the grid search is already implemented it will load the previous results\n\nresults = benchmark(\n pipelines=\"./pipelines_grid/\",\n evaluations=[\"WithinSession\"],\n paradigms=[\"LeftRightImagery\"],\n include_datasets=[\"Zhou2016\"],\n results=\"./results/\",\n overwrite=False,\n plot=False,\n output=\"./benchmark/\",\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Benchmark prints a summary of the results. Detailed results are saved in a\npandas dataframe, and can be used to generate figures. The analysis & figures\nare saved in the ``benchmark`` folder.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "score_plot(results)\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/4819137c12db5666618aa0e7e8603bce/noplot_tutorial_5_build_a_custom_dataset.ipynb b/docs/_downloads/4819137c12db5666618aa0e7e8603bce/noplot_tutorial_5_build_a_custom_dataset.ipynb new file mode 100644 index 00000000..345830d0 --- /dev/null +++ b/docs/_downloads/4819137c12db5666618aa0e7e8603bce/noplot_tutorial_5_build_a_custom_dataset.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Tutorial 5: Creating a dataset class\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Author: Gregoire Cattan\n#\n# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019\n\nfrom pyriemann.classification import MDM\nfrom pyriemann.estimation import ERPCovariances\nfrom sklearn.pipeline import make_pipeline\n\nfrom moabb.datasets import Cattan2019_VR\nfrom moabb.datasets.braininvaders import BI2014a\nfrom moabb.datasets.compound_dataset import CompoundDataset\nfrom moabb.datasets.utils import blocks_reps\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms.p300 import P300" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initialization\n\nThis tutorial illustrates how to use the CompoundDataset to:\n1) Select a few subjects/sessions/runs in an existing dataset\n2) Merge two CompoundDataset into a new one\n3) ... and finally use this new dataset on a pipeline\n(this steps is not specific to CompoundDataset)\n\nLet's define a paradigm and a pipeline for evaluation first.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = P300()\npipelines = {}\npipelines[\"MDM\"] = make_pipeline(ERPCovariances(estimator=\"lwf\"), MDM(metric=\"riemann\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creation a selection of subject\n\nWe are going to great two CompoundDataset, namely CustomDataset1 & 2.\nA CompoundDataset accepts a subjects_list of subjects.\nIt is a list of tuple. A tuple contains 4 values:\n- the original dataset\n- the subject number to select\n- the sessions. It can be:\n - a session name ('0')\n - a list of sessions (['0', '1'])\n - `None` to select all the sessions attributed to a subject\n- the runs. As for sessions, it can be a single run name, a list or `None`` (to select all runs).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class CustomDataset1(CompoundDataset):\n def __init__(self):\n biVR = Cattan2019_VR(virtual_reality=True, screen_display=True)\n runs = blocks_reps([0, 2], [0, 1, 2, 3, 4], biVR.n_repetitions)\n subjects_list = [\n (biVR, 1, \"0VR\", runs),\n (biVR, 2, \"0VR\", runs),\n ]\n CompoundDataset.__init__(\n self,\n subjects_list=subjects_list,\n code=\"CustomDataset1\",\n interval=[0, 1.0],\n )\n\n\nclass CustomDataset2(CompoundDataset):\n def __init__(self):\n bi2014 = BI2014a()\n subjects_list = [\n (bi2014, 4, None, None),\n (bi2014, 7, None, None),\n ]\n CompoundDataset.__init__(\n self,\n subjects_list=subjects_list,\n code=\"CustomDataset2\",\n interval=[0, 1.0],\n )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Merging the datasets\n\nWe are now going to merge the two CompoundDataset into a single one.\nThe implementation is straight forward. Instead of providing a list of subjects,\nyou should provide a list of CompoundDataset.\nsubjects_list = [CustomDataset1(), CustomDataset2()]\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class CustomDataset3(CompoundDataset):\n def __init__(self):\n subjects_list = [CustomDataset1(), CustomDataset2()]\n CompoundDataset.__init__(\n self,\n subjects_list=subjects_list,\n code=\"CustomDataset3\",\n interval=[0, 1.0],\n )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluate and display\n\nLet's use a WithinSessionEvaluation to evaluate our new dataset.\nIf you already new how to do this, nothing changed:\nThe CompoundDataset can be used as a `normal` dataset.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "datasets = [CustomDataset3()]\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm, datasets=datasets, overwrite=False, suffix=\"newdataset\"\n)\nscores = evaluation.process(pipelines)\n\nprint(scores)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/4c45605b7f9e2012cf86c10fa0f2ed72/plot_filterbank_csp_vs_csp.py b/docs/_downloads/4c45605b7f9e2012cf86c10fa0f2ed72/plot_filterbank_csp_vs_csp.py new file mode 100644 index 00000000..b982073d --- /dev/null +++ b/docs/_downloads/4c45605b7f9e2012cf86c10fa0f2ed72/plot_filterbank_csp_vs_csp.py @@ -0,0 +1,129 @@ +""" +========================= +FilterBank CSP versus CSP +========================= + +This example show a comparison of CSP versus FilterBank CSP on the +very popular dataset 2a from the BCI competition IV. +""" + +# Authors: Alexandre Barachant +# +# License: BSD (3-clause) + +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns +from mne.decoding import CSP +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.pipeline import make_pipeline + +import moabb +from moabb.datasets import BNCI2014_001 +from moabb.evaluations import CrossSessionEvaluation +from moabb.paradigms import FilterBankLeftRightImagery, LeftRightImagery +from moabb.pipelines.utils import FilterBank + + +moabb.set_log_level("info") + +############################################################################## +# Create Pipelines +# ---------------- +# +# The CSP implementation from MNE is used. We selected 8 CSP components, as +# usually done in the literature. +# +# The second pipeline is the filter bank CSP. We use the FilterBank object +# with a CSP estimator. We set up the CSP to 4 components, to compensate for +# the higher dimensionality. +# +# The two pipelines will be applied on two different paradigm, so they have +# their own dict. + +pipelines = {} +pipelines["CSP+LDA"] = make_pipeline(CSP(n_components=8), LDA()) + +pipelines_fb = {} +pipelines_fb["FBCSP+LDA"] = make_pipeline(FilterBank(CSP(n_components=4)), LDA()) + +############################################################################## +# Evaluation +# ---------- +# +# Since two different preprocessing will be applied, we have two different +# paradigm objects. We have to make sure their filter matches so the comparison +# will be fair. +# +# The first one is a standard `LeftRightImagery` with a 8 to 35 Hz broadband +# filter. +# +# The second is a `FilterBankLeftRightImagery` with a bank of 2 filters, ranging +# from 8 to 35 Hz. + +# Because this is being auto-generated we only use 2 subjects +dataset = BNCI2014_001() +dataset.subject_list = dataset.subject_list[:2] +datasets = [dataset] +overwrite = False # set to True if we want to overwrite cached results + +# broadband filters +fmin = 8 +fmax = 35 +paradigm = LeftRightImagery(fmin=fmin, fmax=fmax) +evaluation = CrossSessionEvaluation( + paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite +) +results = evaluation.process(pipelines) + +# Bank of 2 filters +filters = [[8, 24], [16, 32]] +paradigm = FilterBankLeftRightImagery(filters=filters) +evaluation = CrossSessionEvaluation( + paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite +) +results_fb = evaluation.process(pipelines_fb) + +############################################################################### +# After processing the two, we simply concatenate the results. + +results = pd.concat([results, results_fb]) + +############################################################################## +# Plot Results +# ---------------- +# +# Here we plot the results via seaborn. We first display a pointplot +# with the average performance of each pipeline across session and subjects. +# The second plot is a paired scatter plot. Each point representing the score +# of a single session. An algorithm will outperform another is most of the +# points are in its quadrant. + +fig, axes = plt.subplots(1, 2, figsize=[8, 4], sharey=True) + +sns.stripplot( + data=results, + y="score", + x="pipeline", + ax=axes[0], + jitter=True, + alpha=0.5, + zorder=1, + palette="Set1", +) +sns.pointplot(data=results, y="score", x="pipeline", ax=axes[0], palette="Set1") + +axes[0].set_ylabel("ROC AUC") +axes[0].set_ylim(0.5, 1) + +# paired plot +paired = results.pivot_table( + values="score", columns="pipeline", index=["subject", "session"] +) +paired = paired.reset_index() + +sns.regplot(data=paired, y="FBCSP+LDA", x="CSP+LDA", ax=axes[1], fit_reg=False) +axes[1].plot([0, 1], [0, 1], ls="--", c="k") +axes[1].set_xlim(0.5, 1) + +plt.show() diff --git a/docs/_downloads/4ecaaa7a22e7ba0d94b874867e072727/tutorial_2_using_mulitple_datasets.ipynb b/docs/_downloads/4ecaaa7a22e7ba0d94b874867e072727/tutorial_2_using_mulitple_datasets.ipynb new file mode 100644 index 00000000..7f5b32f0 --- /dev/null +++ b/docs/_downloads/4ecaaa7a22e7ba0d94b874867e072727/tutorial_2_using_mulitple_datasets.ipynb @@ -0,0 +1,108 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Tutorial 2: Using multiple datasets\n\nWe extend the previous example to a case where we want to analyze the score of\na classifier with three different MI datasets instead of just one. As before,\nwe begin by importing all relevant libraries.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier\n#\n# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport mne\nimport seaborn as sns\nfrom mne.decoding import CSP\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nfrom moabb.datasets import BNCI2014_001, Zhou2016\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import LeftRightImagery\n\n\nmoabb.set_log_level(\"info\")\nmne.set_log_level(\"CRITICAL\")\nwarnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initializing Datasets\n\nWe instantiate the two different datasets that follow the MI paradigm\n(with left-hand/right-hand classes) but were recorded with different number\nof electrodes, different number of trials, etc.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "datasets = [Zhou2016(), BNCI2014_001()]\nsubj = [1, 2, 3]\nfor d in datasets:\n d.subject_list = subj" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following lines go exactly as in the previous example, where we end up\nobtaining a pandas dataframe containing the results of the evaluation. We\ncould set `overwrite` to False to cache the results, avoiding to restart all\nthe evaluation from scratch if a problem occurs.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = LeftRightImagery()\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm, datasets=datasets, overwrite=False\n)\npipeline = make_pipeline(CSP(n_components=8), LDA())\nresults = evaluation.process({\"csp+lda\": pipeline})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotting Results\n\nWe plot the results using the seaborn library. Note how easy it\nis to plot the results from the three datasets with just one line.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "results[\"subj\"] = [str(resi).zfill(2) for resi in results[\"subject\"]]\ng = sns.catplot(\n kind=\"bar\",\n x=\"score\",\n y=\"subj\",\n col=\"dataset\",\n data=results,\n orient=\"h\",\n palette=\"viridis\",\n)\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/51a1867bba0844057530c56f925fbc95/plot_benchmark_DL.ipynb b/docs/_downloads/51a1867bba0844057530c56f925fbc95/plot_benchmark_DL.ipynb new file mode 100644 index 00000000..1a0ccfb8 --- /dev/null +++ b/docs/_downloads/51a1867bba0844057530c56f925fbc95/plot_benchmark_DL.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Benchmarking on MOABB with Tensorflow deep net architectures\nThis example shows how to use MOABB to benchmark a set of Deep Learning pipeline (Tensorflow)\non all available datasets.\nFor this example, we will use only one dataset to keep the computation time low, but this benchmark is designed\nto easily scale to many datasets.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Igor Carrara \n#\n# License: BSD (3-clause)\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nfrom absl.logging import ERROR, set_verbosity\nfrom tensorflow import keras\n\nfrom moabb import benchmark, set_log_level\nfrom moabb.analysis.plotting import score_plot\nfrom moabb.datasets import BNCI2014_001\nfrom moabb.utils import setup_seed\n\n\nset_log_level(\"info\")\n# Avoid output Warning\nset_verbosity(ERROR)\nos.environ[\"TF_CPP_MIN_LOG_LEVEL\"] = \"3\"\n\n# Print Information Tensorflow\nprint(f\"Tensorflow Version: {tf.__version__}\")\nprint(f\"Keras Version: {keras.__version__}\")\n\nCPU = len(tf.config.list_physical_devices(\"CPU\")) > 0\nprint(\"CPU is\", \"AVAILABLE\" if CPU else \"NOT AVAILABLE\")\n\nGPU = len(tf.config.list_physical_devices(\"GPU\")) > 0\nprint(\"GPU is\", \"AVAILABLE\" if GPU else \"NOT AVAILABLE\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, we will use only the dataset ``BNCI2014_001``.\n\n## Running the benchmark\n\nThe benchmark is run using the ``benchmark`` function. You need to specify the\nfolder containing the pipelines to use, the kind of evaluation and the paradigm\nto use. By default, the benchmark will use all available datasets for all\nparadigms listed in the pipelines. You could restrict to specific evaluation and\nparadigm using the ``evaluations`` and ``paradigms`` arguments.\n\nTo save computation time, the results are cached. If you want to re-run the\nbenchmark, you can set the ``overwrite`` argument to ``True``.\n\nIt is possible to indicate the folder to cache the results and the one to save\nthe analysis & figures. By default, the results are saved in the ``results``\nfolder, and the analysis & figures are saved in the ``benchmark`` folder.\n\nThis code is implemented to run on CPU. If you're using a GPU, do not use multithreading\n(i.e. set n_jobs=1)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Set up reproducibility of Tensorflow\nsetup_seed(42)\n\n# Restrict this example only on the first two subject of BNCI2014_001\ndataset = BNCI2014_001()\ndataset.subject_list = dataset.subject_list[:2]\ndatasets = [dataset]\n\nresults = benchmark(\n pipelines=\"./pipelines_DL\",\n evaluations=[\"WithinSession\"],\n paradigms=[\"LeftRightImagery\"],\n include_datasets=datasets,\n results=\"./results/\",\n overwrite=False,\n plot=False,\n output=\"./benchmark/\",\n n_jobs=-1,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The deep learning architectures implemented in MOABB are:\n- Shallow Convolutional Network [1]_\n- Deep Convolutional Network [1]_\n- EEGNet [2]_\n- EEGTCNet [3]_\n- EEGNex [4]_\n- EEGITNet [5]_\n\nBenchmark prints a summary of the results. Detailed results are saved in a\npandas dataframe, and can be used to generate figures. The analysis & figures\nare saved in the ``benchmark`` folder.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "score_plot(results)\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## References\n.. [1] Schirrmeister, R. T., Springenberg, J. T., Fiederer, L. D. J.,\n Glasstetter, M., Eggensperger, K., Tangermann, M., ... & Ball, T. (2017).\n [Deep learning with convolutional neural networks for EEG decoding and\n visualization](https://doi.org/10.1002/hbm.23730).\n Human brain mapping, 38(11), 5391-5420.\n.. [2] Lawhern, V. J., Solon, A. J., Waytowich, N. R., Gordon, S. M.,\n Hung, C. P., & Lance, B. J. (2018). [EEGNet: a compact convolutional neural\n network for EEG-based brain-computer interfaces.](https://doi.org/10.1088/1741-2552/aace8c)\n Journal of neural engineering, 15(5), 056013.\n.. [3] Ingolfsson, T. M., Hersche, M., Wang, X., Kobayashi, N., Cavigelli, L., &\n Benini, L. (2020, October). [EEG-TCNet: An accurate temporal convolutional\n network for embedded motor-imagery brain-machine interfaces.](https://doi.org/10.1109/SMC42975.2020.9283028)\n In 2020 IEEE International Conference on Systems, Man, and Cybernetics (SMC)\n (pp. 2958-2965). IEEE.\n.. [4] Chen, X., Teng, X., Chen, H., Pan, Y., & Geyer, P. (2022). [Toward reliable\n signals decoding for electroencephalogram: A benchmark study to EEGNeX.](https://doi.org/10.48550/arXiv.2207.12369)\n arXiv preprint arXiv:2207.12369.\n.. [5] Salami, A., Andreu-Perez, J., & Gillmeister, H. (2022). [EEG-ITNet: An\n explainable inception temporal convolutional network for motor imagery\n classification](https://doi.org/10.1109/ACCESS.2022.3161489).\n IEEE Access, 10, 36672-36685.\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/5303bff802560c798e898bab8eb895a3/noplot_vr_pc_p300_different_epoch_size.py b/docs/_downloads/5303bff802560c798e898bab8eb895a3/noplot_vr_pc_p300_different_epoch_size.py new file mode 100644 index 00000000..222a668e --- /dev/null +++ b/docs/_downloads/5303bff802560c798e898bab8eb895a3/noplot_vr_pc_p300_different_epoch_size.py @@ -0,0 +1,149 @@ +""" Example of P300 classification with different epoch size. + +======================================= +Changing epoch size in P300 VR dataset +======================================= + +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. + +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 +# License: BSD (3-clause) + +import warnings + +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 Cattan2019_VR +from moabb.paradigms import P300 + + +warnings.filterwarnings("ignore") + +############################################################################### +# 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. + +dataset = Cattan2019_VR() +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 Cattan2019_VR 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}") + + # 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" + + 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)): + # 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 + ) + + X_test, y_test, _ = dataset.get_block_repetition( + paradigm, [subject], blocks[test_idx], repetitions + ) + + # We use riemannian geometry processing techniques 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 + scores_subject.append(np.mean(auc)) + + 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 length" +) diff --git a/docs/_downloads/5459b5c2be76a529eb282ae496a50415/plot_cross_subject_ssvep.py b/docs/_downloads/5459b5c2be76a529eb282ae496a50415/plot_cross_subject_ssvep.py new file mode 100644 index 00000000..5feffeb2 --- /dev/null +++ b/docs/_downloads/5459b5c2be76a529eb282ae496a50415/plot_cross_subject_ssvep.py @@ -0,0 +1,180 @@ +""" +=========================== +Cross-Subject SSVEP +=========================== +This example shows how to perform a cross-subject analysis on an SSVEP dataset. +We will compare four pipelines : + +- Riemannian Geometry +- CCA +- TRCA +- MsetCCA + +We will use the SSVEP paradigm, which uses the AUC as metric. +""" + +# Authors: Sylvain Chevallier +# +# License: BSD (3-clause) + +import warnings + +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns +from pyriemann.estimation import Covariances +from pyriemann.tangentspace import TangentSpace +from sklearn.linear_model import LogisticRegression +from sklearn.pipeline import make_pipeline + +import moabb +from moabb.datasets import Kalunga2016 +from moabb.evaluations import CrossSubjectEvaluation +from moabb.paradigms import SSVEP, FilterBankSSVEP +from moabb.pipelines import SSVEP_CCA, SSVEP_TRCA, ExtendedSSVEPSignal, SSVEP_MsetCCA + + +warnings.simplefilter(action="ignore", category=FutureWarning) +warnings.simplefilter(action="ignore", category=RuntimeWarning) +moabb.set_log_level("info") + +############################################################################### +# Loading Dataset +# --------------- +# +# We will load the data from the first 2 subjects of the ``SSVEP_Exo`` dataset +# and compare two algorithms on this set. One of the algorithms could only +# process class associated with a stimulation frequency, we will thus drop +# the resting class. As the resting class is the last defined class, picking +# the first three classes (out of four) allows to focus only on the stimulation +# frequency. + +n_subject = 2 +dataset = Kalunga2016() +dataset.subject_list = dataset.subject_list[:n_subject] +interval = dataset.interval + +############################################################################### +# Choose Paradigm +# --------------- +# +# We define the paradigms (SSVEP, SSVEP TRCA, SSVEP MsetCCA, and FilterBankSSVEP) and +# use the dataset Kalunga2016. All 3 SSVEP paradigms applied a bandpass filter (10-42 Hz) on +# the data, which include all stimuli frequencies and their first harmonics, +# while the FilterBankSSVEP paradigm uses as many bandpass filters as +# there are stimulation frequencies (here 3). For each stimulation frequency +# the EEG is filtered with a 1 Hz-wide bandpass filter centered on the +# frequency. This results in ``n_classes`` copies of the signal, filtered for each +# class, as used in the filterbank motor imagery paradigms. + +paradigm = SSVEP(fmin=10, fmax=42, n_classes=3) +paradigm_TRCA = SSVEP(fmin=10, fmax=42, n_classes=3) +paradigm_MSET_CCA = SSVEP(fmin=10, fmax=42, n_classes=3) +paradigm_fb = FilterBankSSVEP(filters=None, n_classes=3) + +############################################################################### +# Classes are defined by the frequency of the stimulation, here we use +# the first two frequencies of the dataset, 13 and 17 Hz. +# The evaluation function uses a LabelEncoder, transforming them +# to 0 and 1 + +freqs = paradigm.used_events(dataset) + +############################################################################## +# Create Pipelines +# ---------------- +# +# Pipelines must be a dict of sklearn pipeline transformer. +# The first pipeline uses Riemannian geometry, by building an extended +# covariance matrices from the signal filtered around the considered +# frequency and applying a logistic regression in the tangent plane. +# The second pipeline relies on the above defined CCA classifier. +# The third pipeline relies on the TRCA algorithm, +# and the fourth uses the MsetCCA algorithm. Both CCA based methods +# (i.e. CCA and MsetCCA) used 3 CCA components. + +pipelines_fb = {} +pipelines_fb["RG+LogReg"] = make_pipeline( + ExtendedSSVEPSignal(), + Covariances(estimator="lwf"), + TangentSpace(), + LogisticRegression(solver="lbfgs", multi_class="auto"), +) + +pipelines = {} +pipelines["CCA"] = make_pipeline(SSVEP_CCA(interval=interval, freqs=freqs, n_harmonics=2)) + +pipelines_TRCA = {} +pipelines_TRCA["TRCA"] = make_pipeline(SSVEP_TRCA(interval=interval, freqs=freqs)) + +pipelines_MSET_CCA = {} +pipelines_MSET_CCA["MSET_CCA"] = make_pipeline(SSVEP_MsetCCA(freqs=freqs)) + +############################################################################## +# Evaluation +# ---------- +# +# The evaluation will return a DataFrame containing an accuracy score for +# each subject / session of the dataset, and for each pipeline. +# +# Results are saved into the database, so that if you add a new pipeline, it +# will not run again the evaluation unless a parameter has changed. Results can +# be overwritten if necessary. + +overwrite = False # set to True if we want to overwrite cached results + +evaluation = CrossSubjectEvaluation( + paradigm=paradigm, datasets=dataset, overwrite=overwrite +) +results = evaluation.process(pipelines) + +############################################################################### +# Filter bank processing, determine the filter automatically from the +# stimulation frequency values of events. + +evaluation_fb = CrossSubjectEvaluation( + paradigm=paradigm_fb, datasets=dataset, overwrite=overwrite +) +results_fb = evaluation_fb.process(pipelines_fb) + +############################################################################### +# TRCA processing also relies on filter bank that is automatically designed. + +evaluation_TRCA = CrossSubjectEvaluation( + paradigm=paradigm_TRCA, datasets=dataset, overwrite=overwrite +) +results_TRCA = evaluation_TRCA.process(pipelines_TRCA) + +############################################################################### +# MsetCCA processing +evaluation_MSET_CCA = CrossSubjectEvaluation( + paradigm=paradigm_MSET_CCA, datasets=dataset, overwrite=overwrite +) +results_MSET_CCA = evaluation_MSET_CCA.process(pipelines_MSET_CCA) + +############################################################################### +# After processing the four, we simply concatenate the results. + +results = pd.concat([results, results_fb, results_TRCA, results_MSET_CCA]) + +############################################################################## +# Plot Results +# ---------------- +# +# Here we display the results as stripplot, with a pointplot for error bar. + +fig, ax = plt.subplots(facecolor="white", figsize=[8, 4]) +sns.stripplot( + data=results, + y="score", + x="pipeline", + ax=ax, + jitter=True, + alpha=0.5, + zorder=1, + palette="Set1", +) +sns.pointplot(data=results, y="score", x="pipeline", ax=ax, palette="Set1") +ax.set_ylabel("Accuracy") +ax.set_ylim(0.1, 0.6) +plt.show() diff --git a/docs/_downloads/55cdcc1a57595324be0a4f77a5294187/plot_Getting_Started.py b/docs/_downloads/55cdcc1a57595324be0a4f77a5294187/plot_Getting_Started.py new file mode 100644 index 00000000..c455c036 --- /dev/null +++ b/docs/_downloads/55cdcc1a57595324be0a4f77a5294187/plot_Getting_Started.py @@ -0,0 +1,119 @@ +""" +============================ +Tutorial 0: Getting Started +============================ + +This tutorial takes you through a basic working example of how to use this +codebase, including all the different components, up to the results +generation. If you'd like to know about the statistics and plotting, see the +next tutorial. + +""" + +# Authors: Vinay Jayaram +# +# License: BSD (3-clause) + + +########################################################################## +# Introduction +# -------------------- +# To use the codebase you need an evaluation and a paradigm, some algorithms, +# and a list of datasets to run it all on. You can find those in the following +# submodules; detailed tutorials are given for each of them. + +import numpy as np +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.model_selection import GridSearchCV +from sklearn.pipeline import make_pipeline +from sklearn.svm import SVC + +########################################################################## +# If you would like to specify the logging level when it is running, you can +# use the standard python logging commands through the top-level moabb module +import moabb +from moabb.datasets import BNCI2014_001, utils +from moabb.evaluations import CrossSessionEvaluation +from moabb.paradigms import LeftRightImagery +from moabb.pipelines.features import LogVariance + + +########################################################################## +# In order to create pipelines within a script, you will likely need at least +# the make_pipeline function. They can also be specified via a .yml file. Here +# we will make a couple pipelines just for convenience + + +moabb.set_log_level("info") + +############################################################################## +# Create pipelines +# ---------------- +# +# We create two pipelines: channel-wise log variance followed by LDA, and +# channel-wise log variance followed by a cross-validated SVM (note that a +# cross-validation via scikit-learn cannot be described in a .yml file). For +# later in the process, the pipelines need to be in a dictionary where the key +# is the name of the pipeline and the value is the Pipeline object + +pipelines = {} +pipelines["AM+LDA"] = make_pipeline(LogVariance(), LDA()) +parameters = {"C": np.logspace(-2, 2, 10)} +clf = GridSearchCV(SVC(kernel="linear"), parameters) +pipe = make_pipeline(LogVariance(), clf) + +pipelines["AM+SVM"] = pipe + +############################################################################## +# Datasets +# ----------------- +# +# Datasets can be specified in many ways: Each paradigm has a property +# 'datasets' which returns the datasets that are appropriate for that paradigm + +print(LeftRightImagery().datasets) + +########################################################################## +# Or you can run a search through the available datasets: +print(utils.dataset_search(paradigm="imagery", min_subjects=6)) + +########################################################################## +# Or you can simply make your own list (which we do here due to computational +# constraints) + +dataset = BNCI2014_001() +dataset.subject_list = dataset.subject_list[:2] +datasets = [dataset] + +########################################################################## +# Paradigm +# -------------------- +# +# Paradigms define the events, epoch time, bandpass, and other preprocessing +# parameters. They have defaults that you can read in the documentation, or you +# can simply set them as we do here. A single paradigm defines a method for +# going from continuous data to trial data of a fixed size. To learn more look +# at the tutorial Exploring Paradigms + +fmin = 8 +fmax = 35 +paradigm = LeftRightImagery(fmin=fmin, fmax=fmax) + +########################################################################## +# Evaluation +# -------------------- +# +# An evaluation defines how the training and test sets are chosen. This could +# be cross-validated within a single recording, or across days, or sessions, or +# subjects. This also is the correct place to specify multiple threads. + +evaluation = CrossSessionEvaluation( + paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=False +) +results = evaluation.process(pipelines) + +########################################################################## +# Results are returned as a pandas DataFrame, and from here you can do as you +# want with them + +print(results.head()) diff --git a/docs/_downloads/5657e54b8c692376a881117a99de998e/plot_benchmark.py b/docs/_downloads/5657e54b8c692376a881117a99de998e/plot_benchmark.py new file mode 100644 index 00000000..4d39459c --- /dev/null +++ b/docs/_downloads/5657e54b8c692376a881117a99de998e/plot_benchmark.py @@ -0,0 +1,102 @@ +"""Examples of how to use MOABB to benchmark pipelines. +======================= +Benchmarking with MOABB +======================= + +This example shows how to use MOABB to benchmark a set of pipelines +on all available datasets. For this example, we will use only one +dataset to keep the computation time low, but this benchmark is designed +to easily scale to many datasets. +""" + +# Authors: Sylvain Chevallier +# +# License: BSD (3-clause) + +import matplotlib.pyplot as plt + +from moabb import benchmark, set_log_level +from moabb.analysis.plotting import score_plot +from moabb.paradigms import LeftRightImagery + + +set_log_level("info") + +############################################################################### +# Loading the pipelines +# --------------------- +# +# The ML pipelines used in benchmark are defined in YAML files, following a +# simple format. It simplifies sharing and reusing pipelines across benchmarks, +# reproducing state-of-the-art results. +# +# MOABB comes with complete list of pipelines that cover most of the successful +# approaches in the literature. You can find them in the +# `pipelines folder `_. +# For this example, we will use a folder with only 2 pipelines, to keep the +# computation time low. +# +# This is an example of a pipeline defined in YAML, defining on which paradigms it +# can be used, the original publication, and the steps to perform using a +# scikit-learn API. In this case, a CSP + SVM pipeline, the covariance are estimated +# to compute a CSP filter and then a linear SVM is trained on the CSP filtered +# signals. + +with open("sample_pipelines/CSP_SVM.yml", "r") as f: + lines = f.readlines() + for line in lines: + print(line, end="") + +############################################################################### +# The ``sample_pipelines`` folder contains a second pipeline, a logistic regression +# performed in the tangent space using Riemannian geometry. +# +# Selecting the datasets (optional) +# --------------------------------- +# +# If you want to limit your benchmark on a subset of datasets, you can use the +# ``include_datasets`` and ``exclude_datasets`` arguments. You will need either +# to provide the dataset's object, or a the dataset's code. To get the list of +# available dataset's code for a given paradigm, you can use the following command: + +paradigm = LeftRightImagery() +for d in paradigm.datasets: + print(d.code) + +############################################################################### +# In this example, we will use only the last dataset, 'Zhou 2016'. +# +# Running the benchmark +# --------------------- +# +# The benchmark is run using the ``benchmark`` function. You need to specify the +# folder containing the pipelines to use, the kind of evaluation and the paradigm +# to use. By default, the benchmark will use all available datasets for all +# paradigms listed in the pipelines. You could restrict to specific evaluation and +# paradigm using the ``evaluations`` and ``paradigms`` arguments. +# +# To save computation time, the results are cached. If you want to re-run the +# benchmark, you can set the ``overwrite`` argument to ``True``. +# +# It is possible to indicate the folder to cache the results and the one to save +# the analysis & figures. By default, the results are saved in the ``results`` +# folder, and the analysis & figures are saved in the ``benchmark`` folder. + +results = benchmark( + pipelines="./sample_pipelines/", + evaluations=["WithinSession"], + paradigms=["LeftRightImagery"], + include_datasets=["Zhou2016"], + results="./results/", + overwrite=False, + plot=False, + output="./benchmark/", +) + +############################################################################### +# Benchmark prints a summary of the results. Detailed results are saved in a +# pandas dataframe, and can be used to generate figures. The analysis & figures +# are saved in the ``benchmark`` folder. + +score_plot(results) +plt.show() diff --git a/docs/_downloads/5b1f506cd53838de0dd70e569a36f198/plot_learning_curve_motor_imagery.ipynb b/docs/_downloads/5b1f506cd53838de0dd70e569a36f198/plot_learning_curve_motor_imagery.ipynb new file mode 100644 index 00000000..c27dbaa0 --- /dev/null +++ b/docs/_downloads/5b1f506cd53838de0dd70e569a36f198/plot_learning_curve_motor_imagery.ipynb @@ -0,0 +1,108 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Within Session Motor Imagery with Learning Curve\n\nThis example shows how to perform a within session motor imagery analysis on the\nvery popular dataset 2a from the BCI competition IV.\n\nWe will compare two pipelines :\n\n- CSP + LDA\n- Riemannian Geometry + Logistic Regression\n\nWe will use the LeftRightImagery paradigm. This will restrict the analysis\nto two classes (left- vs right-hand) and use AUC as metric.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Original author: Alexandre Barachant \n# Learning curve modification: Jan Sosulski\n#\n# License: BSD (3-clause)\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns\nfrom mne.decoding import CSP\nfrom pyriemann.estimation import Covariances\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nfrom moabb.datasets import BNCI2014_001\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import LeftRightImagery\n\n\nmoabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Pipelines\n\nPipelines must be a dict of sklearn pipeline transformer.\n\nThe CSP implementation from MNE is used. We selected 8 CSP components, as\nusually done in the literature.\n\nThe Riemannian geometry pipeline consists in covariance estimation, tangent\nspace mapping and finally a logistic regression for the classification.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipelines = {}\n\npipelines[\"CSP+LDA\"] = make_pipeline(\n CSP(n_components=8), LDA(solver=\"lsqr\", shrinkage=\"auto\")\n)\n\npipelines[\"RG+LR\"] = make_pipeline(\n Covariances(), TangentSpace(), LogisticRegression(solver=\"lbfgs\")\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nWe define the paradigm (LeftRightImagery) and the dataset (BNCI2014_001).\nThe evaluation will return a DataFrame containing a single AUC score for\neach subject / session of the dataset, and for each pipeline.\n\nResults are saved into the database, so that if you add a new pipeline, it\nwill not run again the evaluation unless a parameter has changed. Results can\nbe overwritten if necessary.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = LeftRightImagery()\ndataset = BNCI2014_001()\ndataset.subject_list = dataset.subject_list[:1]\ndatasets = [dataset]\noverwrite = True # set to True if we want to overwrite cached results\n# Evaluate for a specific number of training samples per class\ndata_size = dict(policy=\"per_class\", value=np.array([5, 10, 30, 50]))\n# When the training data is sparse, perform more permutations than when we have a lot of data\nn_perms = np.floor(np.geomspace(20, 2, len(data_size[\"value\"]))).astype(int)\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm,\n datasets=datasets,\n suffix=\"examples\",\n overwrite=overwrite,\n data_size=data_size,\n n_perms=n_perms,\n)\n\nresults = evaluation.process(pipelines)\n\nprint(results.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\nWe plot the accuracy as a function of the number of training samples, for\neach pipeline\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(facecolor=\"white\", figsize=[8, 4])\n\nn_subs = len(dataset.subject_list)\n\nif n_subs > 1:\n r = results.groupby([\"pipeline\", \"subject\", \"data_size\"]).mean().reset_index()\nelse:\n r = results\n\nsns.pointplot(data=r, x=\"data_size\", y=\"score\", hue=\"pipeline\", ax=ax, palette=\"Set1\")\n\nerrbar_meaning = \"subjects\" if n_subs > 1 else \"permutations\"\ntitle_str = f\"Errorbar shows Mean-CI across {errbar_meaning}\"\nax.set_xlabel(\"Amount of training samples\")\nax.set_ylabel(\"ROC AUC\")\nax.set_title(title_str)\nfig.tight_layout()\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/5c05a4e8c08dd8d574a1e608b6e51c83/tutorial_3_benchmarking_multiple_pipelines.ipynb b/docs/_downloads/5c05a4e8c08dd8d574a1e608b6e51c83/tutorial_3_benchmarking_multiple_pipelines.ipynb new file mode 100644 index 00000000..71c3d911 --- /dev/null +++ b/docs/_downloads/5c05a4e8c08dd8d574a1e608b6e51c83/tutorial_3_benchmarking_multiple_pipelines.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Tutorial 3: Benchmarking multiple pipelines\n\nIn this last part, we extend the previous example by assessing the\nclassification score of not one but three classification pipelines.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier\n#\n# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport mne\nimport seaborn as sns\nfrom mne.decoding import CSP\nfrom pyriemann.classification import MDM\nfrom pyriemann.estimation import Covariances\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.svm import SVC\n\nimport moabb\nfrom moabb.datasets import BNCI2014_001, Zhou2016\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import LeftRightImagery\n\n\nmne.set_log_level(\"CRITICAL\")\nmoabb.set_log_level(\"info\")\nwarnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating Pipelines\n\nWe instantiate the three different classiciation pipelines to be considered\nin the analysis. The object that gathers each pipeline is a dictionary. The\nfirst pipeline is the CSP+LDA that we have seen in the previous parts. The\nother two pipelines rely on Riemannian geometry, using an SVM classification\nin the tangent space of the covariance matrices estimated from the EEG or a\nMDM classifier that works directly on covariance matrices.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipelines = {}\npipelines[\"csp+lda\"] = make_pipeline(CSP(n_components=8), LDA())\npipelines[\"tgsp+svm\"] = make_pipeline(\n Covariances(\"oas\"), TangentSpace(metric=\"riemann\"), SVC(kernel=\"linear\")\n)\npipelines[\"MDM\"] = make_pipeline(Covariances(\"oas\"), MDM(metric=\"riemann\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following lines go exactly as in the previous tutorial, where we end up\nobtaining a pandas dataframe containing the results of the evaluation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "datasets = [BNCI2014_001(), Zhou2016()]\nsubj = [1, 2, 3]\nfor d in datasets:\n d.subject_list = subj\nparadigm = LeftRightImagery()\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm, datasets=datasets, overwrite=False\n)\nresults = evaluation.process(pipelines)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As `overwrite` is set to False, the results from the previous tutorial are reused and\nonly the new pipelines are evaluated. The results from \"csp+lda\" are not recomputed.\nThe results are saved in ~/mne_data/results if the parameter `hdf5_path` is not set.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotting Results\n\nThe following plot shows a comparison of the three classification pipelines\nfor each subject of each dataset.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "results[\"subj\"] = [str(resi).zfill(2) for resi in results[\"subject\"]]\ng = sns.catplot(\n kind=\"bar\",\n x=\"score\",\n y=\"subj\",\n hue=\"pipeline\",\n col=\"dataset\",\n height=12,\n aspect=0.5,\n data=results,\n orient=\"h\",\n palette=\"viridis\",\n)\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/657e87726c4d308a5b176dbb4277773e/plot_select_electrodes_resample.ipynb b/docs/_downloads/657e87726c4d308a5b176dbb4277773e/plot_select_electrodes_resample.ipynb new file mode 100644 index 00000000..8c32dd2a --- /dev/null +++ b/docs/_downloads/657e87726c4d308a5b176dbb4277773e/plot_select_electrodes_resample.ipynb @@ -0,0 +1,144 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Select Electrodes and Resampling\n\nWithin paradigm, it is possible to restrict analysis only to a subset of\nelectrodes and to resample to a specific sampling rate. There is also a\nutility function to select common electrodes shared between datasets.\nThis tutorial demonstrates how to use this functionality.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Sylvain Chevallier \n#\n# License: BSD (3-clause)\nimport matplotlib.pyplot as plt\nfrom mne.decoding import CSP\nfrom pyriemann.estimation import Covariances\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.linear_model import LogisticRegression as LR\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb.analysis.plotting as moabb_plt\nfrom moabb.datasets import BNCI2014_001, Zhou2016\nfrom moabb.datasets.utils import find_intersecting_channels\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import LeftRightImagery" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Datasets\n\nLoad 2 subjects of BNCI 2014-004 and Zhou2016 datasets, with 2 sessions each\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "subj = [1, 2]\ndatasets = [Zhou2016(), BNCI2014_001()]\nfor d in datasets:\n d.subject_list = subj" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Paradigm\n\nRestrict further analysis to specified channels, here C3, C4, and Cz.\nAlso, use a specific resampling. In this example, all datasets are\nset to 200 Hz.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = LeftRightImagery(channels=[\"C3\", \"C4\", \"Cz\"], resample=200.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nThe evaluation is conducted on with CSP+LDA, only on the 3 electrodes, with\na sampling rate of 200 Hz.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "evaluation = WithinSessionEvaluation(paradigm=paradigm, datasets=datasets)\ncsp_lda = make_pipeline(CSP(n_components=2), LDA())\nts_lr = make_pipeline(\n Covariances(estimator=\"oas\"), TangentSpace(metric=\"riemann\"), LR(C=1.0)\n)\nresults = evaluation.process({\"csp+lda\": csp_lda, \"ts+lr\": ts_lr})\nprint(results.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Electrode Selection\n\nIt is possible to select the electrodes that are shared by all datasets\nusing the `find_intersecting_channels` function. Datasets that have 0\noverlap with others are discarded. It returns the set of common channels,\nas well as the list of datasets with valid channels.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "electrodes, datasets = find_intersecting_channels(datasets)\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm, datasets=datasets, overwrite=True, suffix=\"resample\"\n)\nresults = evaluation.process({\"csp+lda\": csp_lda, \"ts+lr\": ts_lr})\nprint(results.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\nCompare the obtained results with the two pipelines, CSP+LDA and logistic\nregression computed in the tangent space of the covariance matrices.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig = moabb_plt.paired_plot(results, \"csp+lda\", \"ts+lr\")\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip b/docs/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip new file mode 100644 index 0000000000000000000000000000000000000000..fadc9d9d3ee1d82b7a3a2b1ad0ce5837f9da710b GIT binary patch literal 179505 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 literal 0 HcmV?d00001 diff --git a/docs/_downloads/73deabcc8228302a2b46b9595661aedc/noplot_vr_pc_p300_different_epoch_size.ipynb b/docs/_downloads/73deabcc8228302a2b46b9595661aedc/noplot_vr_pc_p300_different_epoch_size.ipynb new file mode 100644 index 00000000..2332cb34 --- /dev/null +++ b/docs/_downloads/73deabcc8228302a2b46b9595661aedc/noplot_vr_pc_p300_different_epoch_size.ipynb @@ -0,0 +1,108 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Example of P300 classification with different epoch size.\n\n# Changing epoch size in P300 VR dataset\n\nThis example shows how to extract the epochs from the P300-VR dataset of a given\nsubject and then classify them using Riemannian Geometry framework for BCI.\nWe compare the scores in the VR and PC conditions, using different epoch size.\n\nThis example demonstrates the use of `get_block_repetition`, which allows\nto specify the experimental blocks and repetitions for analysis.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Pedro Rodrigues \n# Modified by: Gregoire Cattan \n# License: BSD (3-clause)\n\nimport warnings\n\nimport numpy as np\nimport pandas as pd\nfrom pyriemann.classification import MDM\nfrom pyriemann.estimation import ERPCovariances\nfrom sklearn.metrics import roc_auc_score\nfrom sklearn.model_selection import KFold\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.preprocessing import LabelEncoder\nfrom tqdm import tqdm\n\nfrom moabb.datasets import Cattan2019_VR\nfrom moabb.paradigms import P300\n\n\nwarnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initialization\n\n1) Create an instance of the dataset.\n2) Create an instance of a P300 paradigm.\n By default filtering between 1-24 Hz\n with epochs of length 1s.\n In this example we will be modifying the length of the epochs, by\n changing the `tmax` attribute of the paradigm.\n3) Encode categorical variable (Target/NonTarget) to numerical values.\n We will be using label encoding.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset = Cattan2019_VR()\nparadigm = P300()\nle = LabelEncoder().fit([\"Target\", \"NonTarget\"])\n\n# change this to include more subjects\nnsubjects = 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Validation\n\nWe will perform a 3-folds validation for each combination of\ntmax, subjects and experimental conditions (VR or PC).\n\nNot all the data will be used for this validation.\nThe Cattan2019_VR dataset contains the data from a randomized experiment.\nWe will only be using the two first repetitions of the 12 experimental blocks.\nData will be selected thanks to the `get_block_repetition` method.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Contains the score for all combination of tmax, subjects\n# and experimental condition (VR or PC).\nscores = []\n\n# Init 3-folds validation.\nkf = KFold(n_splits=3)\n\n# Select the first two repetitions.\nrepetitions = [1, 2]\n\n# Generate all possible arrangement with the 12 blocks.\nblocks = np.arange(1, 12 + 1)\n\n# run validation for each combination.\nfor tmax in [0.2, 1.0]:\n paradigm.tmax = tmax\n\n for subject in tqdm(dataset.subject_list[:nsubjects]):\n # Note: here we are adding `tmax` to scores_subject,\n # although `tmax` is defined outside the scope of this inner loop.\n # The reason behind is to facilitate the conversion from array to dataframe at the end.\n scores_subject = [tmax, subject]\n\n for condition in [\"VR\", \"PC\"]:\n print(f\"subject {subject}, {condition}, tmax {tmax}\")\n\n # Rather than creating a new instance depending on the condition,\n # let's change the attribute value to download the correct data.\n dataset.virtual_reality = condition == \"VR\"\n dataset.personal_computer = condition == \"PC\"\n\n auc = []\n\n # Split in training and testing blocks, and fit/predict.\n # This loop will run 3 times as we are using a 3-folds validation\n for train_idx, test_idx in kf.split(np.arange(12)):\n # Note the use of the `get_block_repetition` method,\n # to select the appropriate number of blocks and repetitions:\n # - 8 blocks for training, 4 for testing\n # - only the first two repetitions inside each blocks\n X_train, y_train, _ = dataset.get_block_repetition(\n paradigm, [subject], blocks[train_idx], repetitions\n )\n\n X_test, y_test, _ = dataset.get_block_repetition(\n paradigm, [subject], blocks[test_idx], repetitions\n )\n\n # We use riemannian geometry processing techniques with MDM algorithm.\n pipe = make_pipeline(ERPCovariances(estimator=\"lwf\"), MDM())\n pipe.fit(X_train, y_train)\n y_pred = pipe.predict(X_test)\n\n # y_test and y_pred contains categorical variable (Target/NonTarget).\n # To use a metric, we need to convert target information to numerical values.\n y_test = le.transform(y_test)\n y_pred = le.transform(y_pred)\n\n # We use the roc_auc_score, which is a reliable metric for multi-class problem.\n auc.append(roc_auc_score(y_test, y_pred))\n\n # stock scores\n scores_subject.append(np.mean(auc))\n\n scores.append(scores_subject)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Display of the data\n\nLet's transform or array to a dataframe.\nWe can then print it on the console, and\nplot the mean AUC as a function of the epoch length.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "df = pd.DataFrame(scores, columns=[\"tmax\", \"subject\", \"VR\", \"PC\"])\n\nprint(df)\n\ndf.groupby(\"tmax\").mean().plot(\n y=[\"VR\", \"PC\"], title=\"Mean AUC as a function of the epoch length\"\n)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/744775bda3ec8d62d828dcc3cff768f5/load_model.ipynb b/docs/_downloads/744775bda3ec8d62d828dcc3cff768f5/load_model.ipynb new file mode 100644 index 00000000..a93771f6 --- /dev/null +++ b/docs/_downloads/744775bda3ec8d62d828dcc3cff768f5/load_model.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Load Model (Scikit, Pytorch, Keras) with MOABB\n\nThis example shows how to use load the pretrained pipeline in MOABB.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Igor Carrara \n#\n# License: BSD (3-clause)\n\nfrom pickle import load\n\nimport keras\nimport torch\nfrom braindecode import EEGClassifier\nfrom braindecode.models import EEGInception\nfrom scikeras.wrappers import KerasClassifier\nfrom sklearn.pipeline import Pipeline, make_pipeline\nfrom skorch.callbacks import EarlyStopping, EpochScoring\nfrom skorch.dataset import ValidSplit\n\nfrom moabb import set_log_level\nfrom moabb.pipelines.features import StandardScaler_Epoch\nfrom moabb.utils import setup_seed\n\n\nset_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, we will use the results computed by the following examples\n\n- plot_benchmark_\n- plot_benchmark_braindecode_\n- plot_benchmark_DL_\n---------------------\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Set up reproducibility of Tensorflow and PyTorch\nsetup_seed(42)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loading the Scikit-learn pipelines\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "with open(\n \"./results/Models_WithinSession/Zhou2016/1/0/CSP + SVM/fitted_model_best.pkl\",\n \"rb\",\n) as pickle_file:\n CSP_SVM_Trained = load(pickle_file)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loading the Keras model\nWe load the single Keras model, if we want we can set in the exact same pipeline.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "model_Keras = keras.models.load_model(\n \"./results/Models_WithinSession/BNCI2014-001/1/1E/Keras_DeepConvNet/kerasdeepconvnet_fitted_model_best.h5\"\n)\n# Now we need to instantiate a new SciKeras object since we only saved the Keras model\nKeras_DeepConvNet_Trained = KerasClassifier(model_Keras)\n# Create the pipelines\n\n\npipes_keras = Pipeline(\n [\n (\"StandardScaler_Epoch\", StandardScaler_Epoch),\n (\"Keras_DeepConvNet_Trained\", Keras_DeepConvNet_Trained),\n ]\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loading the PyTorch model\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Hyperparameter\nLEARNING_RATE = 0.0001\nWEIGHT_DECAY = 0\nBATCH_SIZE = 64\nSEED = 42\nVERBOSE = 1\nEPOCH = 2\nPATIENCE = 3\n\n# Define a Skorch classifier\nclf = EEGClassifier(\n module=EEGInception,\n optimizer=torch.optim.Adam,\n optimizer__lr=LEARNING_RATE,\n batch_size=BATCH_SIZE,\n max_epochs=EPOCH,\n train_split=ValidSplit(0.2, random_state=SEED),\n callbacks=[\n EarlyStopping(monitor=\"valid_loss\", patience=PATIENCE),\n EpochScoring(\n scoring=\"accuracy\", on_train=True, name=\"train_acc\", lower_is_better=False\n ),\n EpochScoring(\n scoring=\"accuracy\", on_train=False, name=\"valid_acc\", lower_is_better=False\n ),\n ],\n verbose=VERBOSE, # Not printing the results for each epoch\n)\n\nclf.initialize()\n\nf_params = \"./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_model.pkl\"\nf_optimizer = \"./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_optim.pkl\"\nf_history = \"./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_history.json\"\n\nclf.load_params(f_params=f_params, f_optimizer=f_optimizer, f_history=f_history)\n\n# Create the pipelines\npipes_pytorch = make_pipeline(clf)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/7f676ecf06fb47e9238e23dd03876176/plot_benchmark_braindecode.ipynb b/docs/_downloads/7f676ecf06fb47e9238e23dd03876176/plot_benchmark_braindecode.ipynb new file mode 100644 index 00000000..3d9fca61 --- /dev/null +++ b/docs/_downloads/7f676ecf06fb47e9238e23dd03876176/plot_benchmark_braindecode.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures\nThis example shows how to use MOABB to benchmark a set of Braindecode pipelines (deep learning\narchitectures) on all available datasets.\nFor this example, we will use only 2 datasets to keep the computation time low, but this benchmark is designed\nto easily scale to many datasets.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Igor Carrara \n# Bruno Aristimunha \n# Sylvain Chevallier \n#\n# License: BSD (3-clause)\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport torch\nfrom absl.logging import ERROR, set_verbosity\n\nfrom moabb import benchmark, set_log_level\nfrom moabb.analysis.plotting import score_plot\nfrom moabb.datasets import BNCI2014_001, BNCI2014_004\nfrom moabb.utils import setup_seed\n\n\nset_log_level(\"info\")\n# Avoid output Warning\nset_verbosity(ERROR)\nos.environ[\"TF_CPP_MIN_LOG_LEVEL\"] = \"3\"\n\n# Print Information PyTorch\nprint(f\"Torch Version: {torch.__version__}\")\n\n# Set up GPU if it is there\ncuda = torch.cuda.is_available()\ndevice = \"cuda\" if cuda else \"cpu\"\nprint(\"GPU is\", \"AVAILABLE\" if cuda else \"NOT AVAILABLE\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, we will use only 2 subjects from the dataset ``BNCI2014_001`` and ``BNCI2014_004``.\n\n## Running the benchmark\n\nThe benchmark is run using the ``benchmark`` function. You need to specify the\nfolder containing the pipelines, the kind of evaluation, and the paradigm\nto use. By default, the benchmark will use all available datasets for all\nparadigms listed in the pipelines. You could restrict to specific evaluation and\nparadigm using the ``evaluations`` and ``paradigms`` arguments.\n\nTo save computation time, the results are cached. If you want to re-run the\nbenchmark, you can set the ``overwrite`` argument to ``True``.\n\nIt is possible to indicate the folder to cache the results and the one to save\nthe analysis & figures. By default, the results are saved in the ``results``\nfolder, and the analysis & figures are saved in the ``benchmark`` folder.\n\nThis code is implemented to run on CPU. If you're using a GPU, do not use multithreading\n(i.e. set n_jobs=1)\n\nIn order to allow the benchmark function to work with return_epoch=True (Required to use Braindecode(\nwe need to call each pipeline as \"braindecode_xxx...\", with xxx the name of the model to be\nhandled correctly by the benchmark function.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Set up reproducibility of Tensorflow\nsetup_seed(42)\n\n# Restrict this example only to the first two subjects of BNCI2014_001\ndataset = BNCI2014_001()\ndataset2 = BNCI2014_004()\ndataset.subject_list = dataset.subject_list[:2]\ndataset2.subject_list = dataset2.subject_list[:2]\ndatasets = [dataset, dataset2]\n\nresults = benchmark(\n pipelines=\"./pipelines_braindecode\",\n evaluations=[\"CrossSession\"],\n paradigms=[\"LeftRightImagery\"],\n include_datasets=datasets,\n results=\"./results/\",\n overwrite=False,\n plot=False,\n output=\"./benchmark/\",\n n_jobs=-1,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The deep learning architectures implemented in MOABB using Braindecode are:\n\n- Shallow Convolutional Network [1]_\n- Deep Convolutional Network [1]_\n- EEGNetv4 [2]_\n- EEGInception [3]_\n\nBenchmark prints a summary of the results. Detailed results are saved in a\npandas dataframe, and can be used to generate figures. The analysis & figures\nare saved in the ``benchmark`` folder.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "score_plot(results)\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## References\n.. [1] Schirrmeister, R. T., Springenberg, J. T., Fiederer, L. D. J.,\n Glasstetter, M., Eggensperger, K., Tangermann, M., ... & Ball, T. (2017).\n [Deep learning with convolutional neural networks for EEG decoding and\n visualization](https://doi.org/10.1002/hbm.23730).\n Human brain mapping, 38(11), 5391-5420.\n.. [2] Lawhern, V. J., Solon, A. J., Waytowich, N. R., Gordon, S. M.,\n Hung, C. P., & Lance, B. J. (2018). [EEGNet: a compact convolutional neural\n network for EEG-based brain-computer interfaces.](https://doi.org/10.1088/1741-2552/aace8c)\n Journal of neural engineering, 15(5), 056013.\n.. [3] Santamaria-Vazquez, E., Martinez-Cagigal, V., Vaquerizo-Villar,\n F., & Hornero, R. (2020). [EEG-inception: A novel deep convolutional neural network\n for assistive ERP-based brain-computer interfaces.](https://doi.org/10.1109/TNSRE.2020.3048106)\n IEEE Transactions on Neural Systems and Rehabilitation Engineering\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/82e3e6cb009bb9a9c444c6cff254cea8/plot_cross_session_motor_imagery.py b/docs/_downloads/82e3e6cb009bb9a9c444c6cff254cea8/plot_cross_session_motor_imagery.py new file mode 100644 index 00000000..33ce516f --- /dev/null +++ b/docs/_downloads/82e3e6cb009bb9a9c444c6cff254cea8/plot_cross_session_motor_imagery.py @@ -0,0 +1,127 @@ +""" +=========================== +Cross-Session Motor Imagery +=========================== + +This example show how to perform a cross session motor imagery analysis on the +very popular dataset 2a from the BCI competition IV. + +We will compare two pipelines : + +- CSP+LDA +- Riemannian Geometry+Logistic Regression + +We will use the LeftRightImagery paradigm. This will restrict the analysis +to two classes (left hand versus right hand) and use AUC as metric. + +The cross session evaluation context will evaluate performance using a leave +one session out cross-validation. For each session in the dataset, a model +is trained on every other session and performance are evaluated on the current +session. +""" + +# Authors: Alexandre Barachant +# Sylvain Chevallier +# +# License: BSD (3-clause) + +import matplotlib.pyplot as plt +import seaborn as sns +from mne.decoding import CSP +from pyriemann.estimation import Covariances +from pyriemann.tangentspace import TangentSpace +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.linear_model import LogisticRegression +from sklearn.pipeline import make_pipeline + +import moabb +from moabb.datasets import BNCI2014_001 +from moabb.evaluations import CrossSessionEvaluation +from moabb.paradigms import LeftRightImagery + + +moabb.set_log_level("info") + +############################################################################## +# Create Pipelines +# ---------------- +# +# Pipelines must be a dict of sklearn pipeline transformer. +# +# The CSP implementation is based on the MNE implementation. We selected 8 CSP +# components, as usually done in the literature. +# +# The Riemannian geometry pipeline consists in covariance estimation, tangent +# space mapping and finally a logistic regression for the classification. + +pipelines = {} + +pipelines["CSP+LDA"] = make_pipeline(CSP(n_components=8), LDA()) + +pipelines["RG+LR"] = make_pipeline( + Covariances(), TangentSpace(), LogisticRegression(solver="lbfgs") +) + +############################################################################## +# Evaluation +# ---------- +# +# We define the paradigm (LeftRightImagery) and the dataset (BNCI2014_001). +# The evaluation will return a DataFrame containing a single AUC score for +# each subject / session of the dataset, and for each pipeline. +# +# Results are saved into the database, so that if you add a new pipeline, it +# will not run again the evaluation unless a parameter has changed. Results can +# be overwritten if necessary. + +paradigm = LeftRightImagery() +# Because this is being auto-generated we only use 2 subjects +dataset = BNCI2014_001() +dataset.subject_list = dataset.subject_list[:2] +datasets = [dataset] +overwrite = False # set to True if we want to overwrite cached results +evaluation = CrossSessionEvaluation( + paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite +) + +results = evaluation.process(pipelines) + +print(results.head()) + +############################################################################## +# Plot Results +# ---------------- +# +# Here we plot the results. We first make a pointplot with the average +# performance of each pipeline across session and subjects. +# The second plot is a paired scatter plot. Each point representing the score +# of a single session. An algorithm will outperform another is most of the +# points are in its quadrant. + +fig, axes = plt.subplots(1, 2, figsize=[8, 4], sharey=True) + +sns.stripplot( + data=results, + y="score", + x="pipeline", + ax=axes[0], + jitter=True, + alpha=0.5, + zorder=1, + palette="Set1", +) +sns.pointplot(data=results, y="score", x="pipeline", ax=axes[0], palette="Set1") + +axes[0].set_ylabel("ROC AUC") +axes[0].set_ylim(0.5, 1) + +paired = results.pivot_table( + values="score", columns="pipeline", index=["subject", "session"] +) +paired = paired.reset_index() + +sns.regplot(data=paired, y="RG+LR", x="CSP+LDA", ax=axes[1], fit_reg=False) +axes[1].plot([0, 1], [0, 1], ls="--", c="k") +axes[1].set_xlim(0.5, 1) + +plt.show() diff --git a/docs/_downloads/833e0bb5b511f838d653ea6df7213ca7/plot_learning_curve_motor_imagery.py b/docs/_downloads/833e0bb5b511f838d653ea6df7213ca7/plot_learning_curve_motor_imagery.py new file mode 100644 index 00000000..eaa8491c --- /dev/null +++ b/docs/_downloads/833e0bb5b511f838d653ea6df7213ca7/plot_learning_curve_motor_imagery.py @@ -0,0 +1,121 @@ +""" +================================================ +Within Session Motor Imagery with Learning Curve +================================================ + +This example shows how to perform a within session motor imagery analysis on the +very popular dataset 2a from the BCI competition IV. + +We will compare two pipelines : + +- CSP + LDA +- Riemannian Geometry + Logistic Regression + +We will use the LeftRightImagery paradigm. This will restrict the analysis +to two classes (left- vs right-hand) and use AUC as metric. +""" + +# Original author: Alexandre Barachant +# Learning curve modification: Jan Sosulski +# +# License: BSD (3-clause) + +import matplotlib.pyplot as plt +import numpy as np +import seaborn as sns +from mne.decoding import CSP +from pyriemann.estimation import Covariances +from pyriemann.tangentspace import TangentSpace +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.linear_model import LogisticRegression +from sklearn.pipeline import make_pipeline + +import moabb +from moabb.datasets import BNCI2014_001 +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import LeftRightImagery + + +moabb.set_log_level("info") + +############################################################################## +# Create Pipelines +# ---------------- +# +# Pipelines must be a dict of sklearn pipeline transformer. +# +# The CSP implementation from MNE is used. We selected 8 CSP components, as +# usually done in the literature. +# +# The Riemannian geometry pipeline consists in covariance estimation, tangent +# space mapping and finally a logistic regression for the classification. + +pipelines = {} + +pipelines["CSP+LDA"] = make_pipeline( + CSP(n_components=8), LDA(solver="lsqr", shrinkage="auto") +) + +pipelines["RG+LR"] = make_pipeline( + Covariances(), TangentSpace(), LogisticRegression(solver="lbfgs") +) + +############################################################################## +# Evaluation +# ---------- +# +# We define the paradigm (LeftRightImagery) and the dataset (BNCI2014_001). +# The evaluation will return a DataFrame containing a single AUC score for +# each subject / session of the dataset, and for each pipeline. +# +# Results are saved into the database, so that if you add a new pipeline, it +# will not run again the evaluation unless a parameter has changed. Results can +# be overwritten if necessary. + +paradigm = LeftRightImagery() +dataset = BNCI2014_001() +dataset.subject_list = dataset.subject_list[:1] +datasets = [dataset] +overwrite = True # set to True if we want to overwrite cached results +# Evaluate for a specific number of training samples per class +data_size = dict(policy="per_class", value=np.array([5, 10, 30, 50])) +# When the training data is sparse, perform more permutations than when we have a lot of data +n_perms = np.floor(np.geomspace(20, 2, len(data_size["value"]))).astype(int) +evaluation = WithinSessionEvaluation( + paradigm=paradigm, + datasets=datasets, + suffix="examples", + overwrite=overwrite, + data_size=data_size, + n_perms=n_perms, +) + +results = evaluation.process(pipelines) + +print(results.head()) + +############################################################################## +# Plot Results +# ------------ +# +# We plot the accuracy as a function of the number of training samples, for +# each pipeline + +fig, ax = plt.subplots(facecolor="white", figsize=[8, 4]) + +n_subs = len(dataset.subject_list) + +if n_subs > 1: + r = results.groupby(["pipeline", "subject", "data_size"]).mean().reset_index() +else: + r = results + +sns.pointplot(data=r, x="data_size", y="score", hue="pipeline", ax=ax, palette="Set1") + +errbar_meaning = "subjects" if n_subs > 1 else "permutations" +title_str = f"Errorbar shows Mean-CI across {errbar_meaning}" +ax.set_xlabel("Amount of training samples") +ax.set_ylabel("ROC AUC") +ax.set_title(title_str) +fig.tight_layout() +plt.show() diff --git a/docs/_downloads/83c876b60654b8a0b9ebaf6714ef3607/plot_select_electrodes_resample.py b/docs/_downloads/83c876b60654b8a0b9ebaf6714ef3607/plot_select_electrodes_resample.py new file mode 100644 index 00000000..c326b125 --- /dev/null +++ b/docs/_downloads/83c876b60654b8a0b9ebaf6714ef3607/plot_select_electrodes_resample.py @@ -0,0 +1,90 @@ +""" +================================ +Select Electrodes and Resampling +================================ + +Within paradigm, it is possible to restrict analysis only to a subset of +electrodes and to resample to a specific sampling rate. There is also a +utility function to select common electrodes shared between datasets. +This tutorial demonstrates how to use this functionality. +""" + +# Authors: Sylvain Chevallier +# +# License: BSD (3-clause) +import matplotlib.pyplot as plt +from mne.decoding import CSP +from pyriemann.estimation import Covariances +from pyriemann.tangentspace import TangentSpace +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.linear_model import LogisticRegression as LR +from sklearn.pipeline import make_pipeline + +import moabb.analysis.plotting as moabb_plt +from moabb.datasets import BNCI2014_001, Zhou2016 +from moabb.datasets.utils import find_intersecting_channels +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import LeftRightImagery + + +############################################################################## +# Datasets +# -------- +# +# Load 2 subjects of BNCI 2014-004 and Zhou2016 datasets, with 2 sessions each + +subj = [1, 2] +datasets = [Zhou2016(), BNCI2014_001()] +for d in datasets: + d.subject_list = subj + +############################################################################## +# Paradigm +# -------- +# +# Restrict further analysis to specified channels, here C3, C4, and Cz. +# Also, use a specific resampling. In this example, all datasets are +# set to 200 Hz. + +paradigm = LeftRightImagery(channels=["C3", "C4", "Cz"], resample=200.0) + +############################################################################## +# Evaluation +# ---------- +# +# The evaluation is conducted on with CSP+LDA, only on the 3 electrodes, with +# a sampling rate of 200 Hz. + +evaluation = WithinSessionEvaluation(paradigm=paradigm, datasets=datasets) +csp_lda = make_pipeline(CSP(n_components=2), LDA()) +ts_lr = make_pipeline( + Covariances(estimator="oas"), TangentSpace(metric="riemann"), LR(C=1.0) +) +results = evaluation.process({"csp+lda": csp_lda, "ts+lr": ts_lr}) +print(results.head()) + +############################################################################## +# Electrode Selection +# ------------------- +# +# It is possible to select the electrodes that are shared by all datasets +# using the `find_intersecting_channels` function. Datasets that have 0 +# overlap with others are discarded. It returns the set of common channels, +# as well as the list of datasets with valid channels. + +electrodes, datasets = find_intersecting_channels(datasets) +evaluation = WithinSessionEvaluation( + paradigm=paradigm, datasets=datasets, overwrite=True, suffix="resample" +) +results = evaluation.process({"csp+lda": csp_lda, "ts+lr": ts_lr}) +print(results.head()) + +############################################################################## +# Plot Results +# ------------ +# +# Compare the obtained results with the two pipelines, CSP+LDA and logistic +# regression computed in the tangent space of the covariance matrices. + +fig = moabb_plt.paired_plot(results, "csp+lda", "ts+lr") +plt.show() diff --git a/docs/_downloads/8fed52c2a57f02454c33ebb464a390de/load_model.py b/docs/_downloads/8fed52c2a57f02454c33ebb464a390de/load_model.py new file mode 100644 index 00000000..2593fd0e --- /dev/null +++ b/docs/_downloads/8fed52c2a57f02454c33ebb464a390de/load_model.py @@ -0,0 +1,111 @@ +""" +============================================== +Load Model (Scikit, Pytorch, Keras) with MOABB +============================================== + +This example shows how to use load the pretrained pipeline in MOABB. +""" + +# Authors: Igor Carrara +# +# License: BSD (3-clause) + +from pickle import load + +import keras +import torch +from braindecode import EEGClassifier +from braindecode.models import EEGInception +from scikeras.wrappers import KerasClassifier +from sklearn.pipeline import Pipeline, make_pipeline +from skorch.callbacks import EarlyStopping, EpochScoring +from skorch.dataset import ValidSplit + +from moabb import set_log_level +from moabb.pipelines.features import StandardScaler_Epoch +from moabb.utils import setup_seed + + +set_log_level("info") + +############################################################################### +# In this example, we will use the results computed by the following examples +# +# - plot_benchmark_ +# - plot_benchmark_braindecode_ +# - plot_benchmark_DL_ +# --------------------- + +# Set up reproducibility of Tensorflow and PyTorch +setup_seed(42) + +############################################################################### +# Loading the Scikit-learn pipelines + +with open( + "./results/Models_WithinSession/Zhou2016/1/0/CSP + SVM/fitted_model_best.pkl", + "rb", +) as pickle_file: + CSP_SVM_Trained = load(pickle_file) + +############################################################################### +# Loading the Keras model +# We load the single Keras model, if we want we can set in the exact same pipeline. + +model_Keras = keras.models.load_model( + "./results/Models_WithinSession/BNCI2014-001/1/1E/Keras_DeepConvNet/kerasdeepconvnet_fitted_model_best.h5" +) +# Now we need to instantiate a new SciKeras object since we only saved the Keras model +Keras_DeepConvNet_Trained = KerasClassifier(model_Keras) +# Create the pipelines + + +pipes_keras = Pipeline( + [ + ("StandardScaler_Epoch", StandardScaler_Epoch), + ("Keras_DeepConvNet_Trained", Keras_DeepConvNet_Trained), + ] +) + +############################################################################### +# Loading the PyTorch model + +# Hyperparameter +LEARNING_RATE = 0.0001 +WEIGHT_DECAY = 0 +BATCH_SIZE = 64 +SEED = 42 +VERBOSE = 1 +EPOCH = 2 +PATIENCE = 3 + +# Define a Skorch classifier +clf = EEGClassifier( + module=EEGInception, + optimizer=torch.optim.Adam, + optimizer__lr=LEARNING_RATE, + batch_size=BATCH_SIZE, + max_epochs=EPOCH, + train_split=ValidSplit(0.2, random_state=SEED), + callbacks=[ + EarlyStopping(monitor="valid_loss", patience=PATIENCE), + EpochScoring( + scoring="accuracy", on_train=True, name="train_acc", lower_is_better=False + ), + EpochScoring( + scoring="accuracy", on_train=False, name="valid_acc", lower_is_better=False + ), + ], + verbose=VERBOSE, # Not printing the results for each epoch +) + +clf.initialize() + +f_params = "./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_model.pkl" +f_optimizer = "./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_optim.pkl" +f_history = "./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_history.json" + +clf.load_params(f_params=f_params, f_optimizer=f_optimizer, f_history=f_history) + +# Create the pipelines +pipes_pytorch = make_pipeline(clf) diff --git a/docs/_downloads/93f59072dcc594921985afeb50d4cf2b/changing_download_directory.py b/docs/_downloads/93f59072dcc594921985afeb50d4cf2b/changing_download_directory.py new file mode 100644 index 00000000..b42bc2b9 --- /dev/null +++ b/docs/_downloads/93f59072dcc594921985afeb50d4cf2b/changing_download_directory.py @@ -0,0 +1,37 @@ +""" +=========================== +Change Download Directory +=========================== + +This is a minimal example to demonstrate how to change the default data +download directory to a custom path/location. """ + +# Authors: Divyesh Narayanan +# +# License: BSD (3-clause) + +import os.path as osp + +from mne import get_config + +from moabb.utils import set_download_dir + + +############################################################################### +# You can choose to change the download directory to any path of your choice. +# If the path/folder doesn't exist, it will be created for you. + +original_path = get_config("MNE_DATA") +print(f"The download directory is currently {original_path}") +new_path = osp.join(osp.expanduser("~"), "mne_data_test") +set_download_dir(new_path) + +############################################################################### +# You could verify that the MNE config has been changed correctly + +check_path = get_config("MNE_DATA") +print(f"Now the download directory has been changed to {check_path}") + +############################################################################### +# Set the directory back to default location +set_download_dir(original_path) diff --git a/docs/_downloads/97a1de59bce682890841bb846e3dd09c/auto_tutorials_jupyter.zip b/docs/_downloads/97a1de59bce682890841bb846e3dd09c/auto_tutorials_jupyter.zip new file mode 100644 index 0000000000000000000000000000000000000000..e08c13aa5cc8b5f578557e08002a19ae82798f78 GIT binary patch literal 41030 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 LVd2ex;&1;CC%S1L literal 0 HcmV?d00001 diff --git a/docs/_downloads/9ab89018120aed26b30f3efdfdef47fe/noplot_bids_conversion.py b/docs/_downloads/9ab89018120aed26b30f3efdfdef47fe/noplot_bids_conversion.py new file mode 100644 index 00000000..b5bda364 --- /dev/null +++ b/docs/_downloads/9ab89018120aed26b30f3efdfdef47fe/noplot_bids_conversion.py @@ -0,0 +1,134 @@ +""" +=============================== +Convert a MOABB dataset to BIDS +=============================== + +The Brain Imaging Data Structure (BIDS) format +is standard for storing neuroimaging data. +It follows fixed principles to facilitate the +sharing of neuroimaging data between researchers. + +The MOABB library allows to convert any MOABB dataset to +BIDS [1]_ and [2]_. + +In this example, we will convert the AlexMI dataset to BIDS using the +option ``cache_config=dict(path=temp_dir, save_raw=True)`` of the ``get_data`` +method from the dataset object. + +This will automatically save the raw data in the BIDS format and allow to use +a cache for the next time the dataset is used. + +We will use the AlexMI dataset [3]_, one of the smallest in +people and one that can be downloaded quickly. +""" + +# Authors: Pierre Guetschel +# +# License: BSD (3-clause) + +import shutil +import tempfile +from pathlib import Path + +import mne + +from moabb import set_log_level +from moabb.datasets import AlexMI + + +set_log_level("info") + +############################################################################### +# Basic usage +# ----------- +# +# Here, we will save the BIDS version of the dataset in a temporary folder +temp_dir = Path(tempfile.mkdtemp()) +# The conversion of any MOABB dataset to a BIDS-compliant structure can be done +# by simply calling its ``get_data`` method and using the ``cache_config`` +# parameter. This parameter is a dictionary. +dataset = AlexMI() +_ = dataset.get_data(cache_config=dict(path=temp_dir, save_raw=True)) + + +############################################################################### +# Before / after folder structure +# ----------------------------- +# +# To investigate what was saved, we will first define a function to print +# the folder structure of a given path: +def print_tree(p: Path, last=True, header=""): + elbow = "└──" + pipe = "│ " + tee = "├──" + blank = " " + print(header + (elbow if last else tee) + p.name) + if p.is_dir(): + children = list(p.iterdir()) + for i, c in enumerate(children): + print_tree( + c, header=header + (blank if last else pipe), last=i == len(children) - 1 + ) + + +############################################################################### +# Now, we will retrieve the location of the original dataset. It is stored +# in the MNE data directory, which can be found with the ``"MNE_DATA"`` key: +mne_data = Path(mne.get_config("MNE_DATA")) +print(f"MNE data directory: {mne_data}") + +############################################################################### +# Now, we can print the folder structure of the original dataset: +print("Before conversion:") +print_tree(mne_data / "MNE-alexeeg-data") + +############################################################################### +# As we can see, before conversion, all the data (i.e. from all subjects, +# sessions and runs) is stored in a single folder. This follows no particular +# standard and can vary from one dataset to another. +# +# After conversion, the data is stored in a BIDS-compliant way: +print("After conversion:") +print_tree(temp_dir / "MNE-BIDS-alexandre-motor-imagery") + +############################################################################### +# In the BIDS version of our dataset, the raw files are saved in EDF. +# The data is organized in a hierarchy of folders, +# starting with the subjects, then the sessions, and then the runs. Metadata +# files are stored to describe the data. For more details on the BIDS +# structure, please refer to the `BIDS website `_ +# and the `BIDS spec `_. +# +# Under the hood, saving datasets to BIDS is done through the caching system +# of MOABB. Only raw EEG files are officially supported by the BIDS +# specification. +# However, MOABB's caching mechanism also offers the possibility to save +# the data in a pseudo-BIDS after different preprocessing steps. +# In particular, we can save :class:`mne.Epochs` and ``np.ndarray`` objects. +# For more details on the caching system, +# please refer to the tutorial :doc:`./plot_disk_cache`. +# +# Cleanup +# ------- +# +# Finally, we can delete the temporary folder: +shutil.rmtree(temp_dir) + +############################################################################### +# References +# ----------- +# +# .. [1] Pernet, C.R., Appelhoff, S., Gorgolewski, K.J. et al. EEG-BIDS, +# An extension to the brain imaging data structure for +# electroencephalography. Sci Data 6, 103 (2019). +# https://doi.org/10.1038/s41597-019-0104-8 +# +# .. [2] Appelhoff et al., (2019). MNE-BIDS: Organizing electrophysiological +# data into the BIDS format and facilitating their analysis. +# Journal of Open Source Software, 4(44), 1896, +# https://doi.org/10.21105/joss.01896 +# +# .. [3] Barachant, A., 2012. Commande robuste d'un effecteur par une +# interface cerveau machine EEG asynchrone (Doctoral dissertation, +# Université de Grenoble). +# https://tel.archives-ouvertes.fr/tel-01196752 diff --git a/docs/_downloads/9b872d163c45f60eb451b1869667203a/plot_explore_paradigm.py b/docs/_downloads/9b872d163c45f60eb451b1869667203a/plot_explore_paradigm.py new file mode 100644 index 00000000..ce3b6667 --- /dev/null +++ b/docs/_downloads/9b872d163c45f60eb451b1869667203a/plot_explore_paradigm.py @@ -0,0 +1,147 @@ +""" +======================= +Explore Paradigm Object +======================= + +A paradigm defines how the raw data will be converted to trials ready +to be processed by a decoding algorithm. This is a function of the paradigm +used, i.e. in motor imagery one can have two-class, multi-class, +or continuous paradigms; similarly, different preprocessing is necessary +for ERP vs ERD paradigms. + +A paradigm also defines the appropriate evaluation metric, for example AUC +for binary classification problems, accuracy for multiclass, or kappa +coefficients for continuous paradigms. + +This tutorial explores the paradigm object, with 3 examples of paradigm : + - MotorImagery + - FilterBankMotorImagery + - LeftRightImagery + +""" + +# Authors: Alexandre Barachant +# Sylvain Chevallier +# +# License: BSD (3-clause) + +import numpy as np + +from moabb.datasets import BNCI2014_001 +from moabb.paradigms import FilterBankMotorImagery, LeftRightImagery, MotorImagery + + +print(__doc__) + +############################################################################### +# MotorImagery +# ----------------- +# +# First, let's take an example of the MotorImagery paradigm. + +paradigm = MotorImagery(n_classes=4) + +print(paradigm.__doc__) + +############################################################################### +# The function `get_data` allow you to access preprocessed data from a dataset. +# this function will return 3 objects. A numpy array containing the +# preprocessed EEG data, the labels, and a dataframe with metadata. + +print(paradigm.get_data.__doc__) + +############################################################################### +# Lets take the example of the BNCI2014_001 dataset, known as the dataset IIa +# from the BCI competition IV. We will load the data from the subject 1. +# When calling `get_data`, the paradigm will retrieve the data from the +# specified list of subjects, apply preprocessing (by default, a bandpass +# between 7 and 35 Hz), epoch the data (with interval specified by the dataset, +# unless superseded by the paradigm) and return the corresponding objects. + +dataset = BNCI2014_001() +subjects = [1] + +X, y, metadata = paradigm.get_data(dataset=dataset, subjects=subjects) + +############################################################################### +# The epoched data is a 3D array, with epochs on the first dimension (here +# 576 trials), channels on the second (22 channels) and time sample on the last +# one. + +print(X.shape) + +############################################################################### +# Labels contains the labels corresponding to each trial. in the case of this +# dataset, we have the 4 types of motor imagery that was performed. + +print(np.unique(y)) + +############################################################################### +# Metadata have at least 3 columns: subject, session and run. +# +# - subject is the subject id of the corresponding trial +# - session is the session id. A session denotes a recording made without +# removing the EEG cap. +# - run is the individual continuous recording made during a session. A session +# may or may not contain multiple runs. +# + +print(metadata.head()) + +############################################################################### +# For this data, we have one subject, 2 sessions (2 different recording days) +# and 6 runs per session. + +print(metadata.describe(include="all")) + +############################################################################### +# Paradigm objects can also return the list of all dataset compatible. Here +# it will return the list all the imagery datasets from the MOABB. + +compatible_datasets = paradigm.datasets +print([dataset.code for dataset in compatible_datasets]) + +############################################################################### +# FilterBank MotorImagery +# ----------------------- +# +# FilterBankMotorImagery is the same paradigm, but with a different +# preprocessing. In this case, it applies a bank of 6 bandpass filter on the data +# before concatenating the output. + +paradigm = FilterBankMotorImagery() + +print(paradigm.__doc__) + +############################################################################### +# Therefore, the output X is a 4D array, with trial x channel x time x filter + +X, y, metadata = paradigm.get_data(dataset=dataset, subjects=subjects) + +print(X.shape) + +############################################################################### +# LeftRight MotorImagery +# ---------------------- +# +# LeftRightImagery is a variation over the BaseMotorImagery paradigm, +# restricted to left- and right-hand events. + +paradigm = LeftRightImagery() + +print(paradigm.__doc__) + +############################################################################### +# The compatible dataset list is a subset of motor imagery dataset that +# contains at least left and right hand events. + +compatible_datasets = paradigm.datasets +print([dataset.code for dataset in compatible_datasets]) + +############################################################################### +# So if we apply this to our original dataset, it will only return trials +# corresponding to left- and right-hand motor imagination. + +X, y, metadata = paradigm.get_data(dataset=dataset, subjects=subjects) + +print(np.unique(y)) diff --git a/docs/_downloads/9bb96dc7985cb9e3189360966fe90306/tutorial_1_simple_example_motor_imagery.ipynb b/docs/_downloads/9bb96dc7985cb9e3189360966fe90306/tutorial_1_simple_example_motor_imagery.ipynb new file mode 100644 index 00000000..b29511c7 --- /dev/null +++ b/docs/_downloads/9bb96dc7985cb9e3189360966fe90306/tutorial_1_simple_example_motor_imagery.ipynb @@ -0,0 +1,288 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Tutorial 1: Simple Motor Imagery\n\nIn this example, we will go through all the steps to make a simple BCI\nclassification task, downloading a dataset and using a standard classifier. We\nchoose the dataset 2a from BCI Competition IV, a motor imagery task. We will\nuse a CSP to enhance the signal-to-noise ratio of the EEG epochs and a LDA to\nclassify these signals.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier\n#\n# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport seaborn as sns\nfrom mne.decoding import CSP\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nfrom moabb.datasets import BNCI2014_001\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import LeftRightImagery\n\n\nmoabb.set_log_level(\"info\")\nwarnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiating Dataset\n\nThe first thing to do is to instantiate the dataset that we want to analyze.\nMOABB has a list of many different datasets, each one containing all the\nnecessary information for describing them, such as the number of subjects,\nsize of trials, names of classes, etc.\n\nThe dataset class has methods for:\n\n- downloading its files from some online source (e.g. Zenodo)\n- importing the data from the files in whatever extension they might be\n (like .mat, .gdf, etc.) and instantiate a Raw object from the MNE package\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset = BNCI2014_001()\ndataset.subject_list = [1, 2, 3]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Accessing EEG Recording\n\nAs an example, we may access the EEG recording from a given session and a\ngiven run as follows:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sessions = dataset.get_data(subjects=[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This returns a MNE Raw object that can be manipulated. This might be enough\nfor some users, since the pre-processing and epoching steps can be easily\ndone via MNE. However, to conduct an assessment of several classifiers on\nmultiple subjects, MOABB ends up being a more appropriate option.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "subject = 1\nsession_name = \"0train\"\nrun_name = \"0\"\nraw = sessions[subject][session_name][run_name]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Choosing a Paradigm\n\nOnce we have instantiated a dataset, we have to choose a paradigm. This\nobject is responsible for filtering the data, epoching it, and extracting\nthe labels for each epoch. Note that each dataset comes with the names of\nthe paradigms to which it might be associated. It would not make sense to\nprocess a P300 dataset with a MI paradigm object.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(dataset.paradigm)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the example below, we will consider the paradigm associated to\nleft-hand/right-hand motor imagery task, but there are other options in\nMOABB for motor imagery, P300 or SSVEP.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = LeftRightImagery()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We may check the list of all datasets available in MOABB for using with this\nparadigm (note that BNCI2014_001 is in it)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(paradigm.datasets)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The data from a list of subjects could be preprocessed and return as a 3D\nnumpy array `X`, follow a scikit-like format with the associated `labels`.\nThe `meta` object contains all information regarding the subject, the\nsession and the run associated to each trial.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X, labels, meta = paradigm.get_data(dataset=dataset, subjects=[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Pipeline\n\nOur goal is to evaluate the performance of a given classification pipeline\n(or several of them) when it is applied to the epochs from the previously\nchosen dataset. We will consider a very simple classification pipeline in\nwhich the dimension of the epochs are reduced via a CSP step and then\nclassified via a linear discriminant analysis.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipeline = make_pipeline(CSP(n_components=8), LDA())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nTo evaluate the score of this pipeline, we use the `evaluation` class. When\ninstantiating it, we say which paradigm we want to consider, a list with the\ndatasets to analyze, and whether the scores should be recalculated each time\nwe run the evaluation or if MOABB should create a cache file.\n\nNote that there are different ways of evaluating a classifier; in this\nexample, we choose `WithinSessionEvaluation`, which consists of doing a\ncross-validation procedure where the training and testing partitions are from\nthe same recording session of the dataset. We could have used\n`CrossSessionEvaluation`, which takes all but one session as training\npartition and the remaining one as testing partition.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "evaluation = WithinSessionEvaluation(\n paradigm=paradigm,\n datasets=[dataset],\n overwrite=True,\n hdf5_path=None,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We obtain the results in the form of a pandas dataframe\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "results = evaluation.process({\"csp+lda\": pipeline})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The results are stored in locally, to avoid recomputing the results each time.\nIt is saved in `hdf5_path` if defined or in ~/mne_data/results otherwise.\nTo export the results in CSV:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "results.to_csv(\"./results_part2-1.csv\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To load previously obtained results saved in CSV\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "results = pd.read_csv(\"./results_part2-1.csv\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotting Results\n\nWe create a figure with the seaborn package comparing the classification\nscore for each subject on each session. Note that the 'subject' field from\nthe `results` is given in terms of integers, but seaborn accepts only\nstrings for its labeling. This is why we create the field 'subj'.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(figsize=(8, 7))\nresults[\"subj\"] = results[\"subject\"].apply(str)\nsns.barplot(\n x=\"score\", y=\"subj\", hue=\"session\", data=results, orient=\"h\", palette=\"viridis\", ax=ax\n)\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/9d4b12baed30d0e2fe09c8116ace859d/plot_learning_curve_p300.py b/docs/_downloads/9d4b12baed30d0e2fe09c8116ace859d/plot_learning_curve_p300.py new file mode 100644 index 00000000..cea40639 --- /dev/null +++ b/docs/_downloads/9d4b12baed30d0e2fe09c8116ace859d/plot_learning_curve_p300.py @@ -0,0 +1,126 @@ +""" +======================================= +Within Session P300 with Learning Curve +======================================= + +This example shows how to perform a within session analysis while also +creating learning curves for a P300 dataset. +Additionally, we will evaluate external code. Make sure to have tdlda installed, which +can be found in requirements_external.txt + +We will compare two pipelines : + +- Riemannian geometry with Linear Discriminant Analysis +- XDAWN and Linear Discriminant Analysis + +We will use the P300 paradigm, which uses the AUC as metric. +""" + +# Authors: Jan Sosulski +# +# License: BSD (3-clause) + +import warnings + +import matplotlib.pyplot as plt +import numpy as np +import seaborn as sns +from mne.decoding import Vectorizer +from pyriemann.estimation import XdawnCovariances +from pyriemann.spatialfilters import Xdawn +from pyriemann.tangentspace import TangentSpace +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.pipeline import make_pipeline + +import moabb +from moabb.datasets import BNCI2014_009 +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import P300 + + +# getting rid of the warnings about the future (on s'en fout !) +warnings.simplefilter(action="ignore", category=FutureWarning) +warnings.simplefilter(action="ignore", category=RuntimeWarning) + +moabb.set_log_level("info") + +############################################################################## +# Create Pipelines +# ---------------- +# +# Pipelines must be a dict of sklearn pipeline transformer. +processing_sampling_rate = 128 +pipelines = {} + +############################################################################## +# We have to do this because the classes are called 'Target' and 'NonTarget' +# but the evaluation function uses a LabelEncoder, transforming them +# to 0 and 1 +labels_dict = {"Target": 1, "NonTarget": 0} + +# Riemannian geometry based classification +pipelines["RG+LDA"] = make_pipeline( + XdawnCovariances(nfilter=5, estimator="lwf", xdawn_estimator="scm"), + TangentSpace(), + LDA(solver="lsqr", shrinkage="auto"), +) + +pipelines["Xdw+LDA"] = make_pipeline( + Xdawn(nfilter=2, estimator="scm"), Vectorizer(), LDA(solver="lsqr", shrinkage="auto") +) + +############################################################################## +# Evaluation +# ---------- +# +# We define the paradigm (P300) and use all three datasets available for it. +# The evaluation will return a DataFrame containing AUCs for each permutation +# and dataset size. + +paradigm = P300(resample=processing_sampling_rate) +dataset = BNCI2014_009() +# Remove the slicing of the subject list to evaluate multiple subjects +dataset.subject_list = dataset.subject_list[1:2] +datasets = [dataset] +overwrite = True # set to True if we want to overwrite cached results +data_size = dict(policy="ratio", value=np.geomspace(0.02, 1, 4)) +# When the training data is sparse, perform more permutations than when we have a lot of data +n_perms = np.floor(np.geomspace(20, 2, len(data_size["value"]))).astype(int) +# Guarantee reproducibility +np.random.seed(7536298) +evaluation = WithinSessionEvaluation( + paradigm=paradigm, + datasets=datasets, + data_size=data_size, + n_perms=n_perms, + suffix="examples_lr", + overwrite=overwrite, +) + +results = evaluation.process(pipelines) + +############################################################################## +# Plot Results +# ------------ +# +# We plot the accuracy as a function of the number of training samples, for +# each pipeline + +fig, ax = plt.subplots(facecolor="white", figsize=[8, 4]) + +n_subs = len(dataset.subject_list) + +if n_subs > 1: + r = results.groupby(["pipeline", "subject", "data_size"]).mean().reset_index() +else: + r = results + +sns.pointplot(data=r, x="data_size", y="score", hue="pipeline", ax=ax, palette="Set1") + +errbar_meaning = "subjects" if n_subs > 1 else "permutations" +title_str = f"Errorbar shows Mean-CI across {errbar_meaning}" +ax.set_xlabel("Amount of training samples") +ax.set_ylabel("ROC AUC") +ax.set_title(title_str) +fig.tight_layout() +plt.show() diff --git a/docs/_downloads/a1721df1b7d19e3e027162c49fa733d4/tutorial_2_using_mulitple_datasets.py b/docs/_downloads/a1721df1b7d19e3e027162c49fa733d4/tutorial_2_using_mulitple_datasets.py new file mode 100644 index 00000000..41228092 --- /dev/null +++ b/docs/_downloads/a1721df1b7d19e3e027162c49fa733d4/tutorial_2_using_mulitple_datasets.py @@ -0,0 +1,76 @@ +""" +=================================== +Tutorial 2: Using multiple datasets +=================================== + +We extend the previous example to a case where we want to analyze the score of +a classifier with three different MI datasets instead of just one. As before, +we begin by importing all relevant libraries. +""" + +# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier +# +# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019 + +import warnings + +import matplotlib.pyplot as plt +import mne +import seaborn as sns +from mne.decoding import CSP +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.pipeline import make_pipeline + +import moabb +from moabb.datasets import BNCI2014_001, Zhou2016 +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import LeftRightImagery + + +moabb.set_log_level("info") +mne.set_log_level("CRITICAL") +warnings.filterwarnings("ignore") + +############################################################################## +# Initializing Datasets +# --------------------- +# +# We instantiate the two different datasets that follow the MI paradigm +# (with left-hand/right-hand classes) but were recorded with different number +# of electrodes, different number of trials, etc. + +datasets = [Zhou2016(), BNCI2014_001()] +subj = [1, 2, 3] +for d in datasets: + d.subject_list = subj + +############################################################################## +# The following lines go exactly as in the previous example, where we end up +# obtaining a pandas dataframe containing the results of the evaluation. We +# could set `overwrite` to False to cache the results, avoiding to restart all +# the evaluation from scratch if a problem occurs. +paradigm = LeftRightImagery() +evaluation = WithinSessionEvaluation( + paradigm=paradigm, datasets=datasets, overwrite=False +) +pipeline = make_pipeline(CSP(n_components=8), LDA()) +results = evaluation.process({"csp+lda": pipeline}) + +############################################################################## +# Plotting Results +# ---------------- +# +# We plot the results using the seaborn library. Note how easy it +# is to plot the results from the three datasets with just one line. + +results["subj"] = [str(resi).zfill(2) for resi in results["subject"]] +g = sns.catplot( + kind="bar", + x="score", + y="subj", + col="dataset", + data=results, + orient="h", + palette="viridis", +) +plt.show() diff --git a/docs/_downloads/b129d24bc810ae3a961d5bdcb7413828/plot_benchmark_grid_search.py b/docs/_downloads/b129d24bc810ae3a961d5bdcb7413828/plot_benchmark_grid_search.py new file mode 100644 index 00000000..b7d91078 --- /dev/null +++ b/docs/_downloads/b129d24bc810ae3a961d5bdcb7413828/plot_benchmark_grid_search.py @@ -0,0 +1,67 @@ +""" +======================================== +Benchmarking with MOABB with Grid Search +======================================== + +This example shows how to use MOABB to benchmark a set of pipelines +on all available datasets. In particular we run the Gridsearch to select the best hyperparameter of some pipelines +and save the gridsearch. +For this example, we will use only one dataset to keep the computation time low, but this benchmark is designed +to easily scale to many datasets. +""" + +# Authors: Igor Carrara +# +# License: BSD (3-clause) + +import matplotlib.pyplot as plt + +from moabb import benchmark, set_log_level +from moabb.analysis.plotting import score_plot + + +set_log_level("info") + +############################################################################### +# In this example, we will use only the dataset 'Zhou 2016'. +# +# Running the benchmark +# --------------------- +# +# The benchmark is run using the ``benchmark`` function. You need to specify the +# folder containing the pipelines to use, the kind of evaluation and the paradigm +# to use. By default, the benchmark will use all available datasets for all +# paradigms listed in the pipelines. You could restrict to specific evaluation and +# paradigm using the ``evaluations`` and ``paradigms`` arguments. +# +# To save computation time, the results are cached. If you want to re-run the +# benchmark, you can set the ``overwrite`` argument to ``True``. +# +# It is possible to indicate the folder to cache the results and the one to save +# the analysis & figures. By default, the results are saved in the ``results`` +# folder, and the analysis & figures are saved in the ``benchmark`` folder. + +# In the results folder we will save the gridsearch evaluation +# When write the pipeline in ylm file we need to specify the parameter that we want to test, in format +# pipeline-name__estimator-name_parameter. Note that pipeline and estimator names MUST +# be in lower case (no capital letters allowed). +# If the grid search is already implemented it will load the previous results + +results = benchmark( + pipelines="./pipelines_grid/", + evaluations=["WithinSession"], + paradigms=["LeftRightImagery"], + include_datasets=["Zhou2016"], + results="./results/", + overwrite=False, + plot=False, + output="./benchmark/", +) + +############################################################################### +# Benchmark prints a summary of the results. Detailed results are saved in a +# pandas dataframe, and can be used to generate figures. The analysis & figures +# are saved in the ``benchmark`` folder. + +score_plot(results) +plt.show() diff --git a/docs/_downloads/b298e4b36adf2bb5cb6f65682eec852f/plot_grid_search_withinsession.py b/docs/_downloads/b298e4b36adf2bb5cb6f65682eec852f/plot_grid_search_withinsession.py new file mode 100644 index 00000000..a2f1aefb --- /dev/null +++ b/docs/_downloads/b298e4b36adf2bb5cb6f65682eec852f/plot_grid_search_withinsession.py @@ -0,0 +1,175 @@ +""" +============================ +GridSearch within a session +============================ + +This example demonstrates how to make a model selection in pipelines +for finding the best model parameter, using grid search. Two models +are compared, one "vanilla" model with model tuned via grid search. +""" + +import os +from pickle import load + +import matplotlib.pyplot as plt +import seaborn as sns +from pyriemann.estimation import Covariances +from pyriemann.tangentspace import TangentSpace +from sklearn.linear_model import LogisticRegression +from sklearn.pipeline import Pipeline + +from moabb.datasets import BNCI2014_001 +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import MotorImagery + + +# Initialize parameter for the Band Pass filter +fmin = 8 +fmax = 35 +tmax = None + +# Select the Subject +subjects = [1] +# Load the dataset +dataset = BNCI2014_001() + +events = ["right_hand", "left_hand"] + +paradigm = MotorImagery( + events=events, n_classes=len(events), fmin=fmin, fmax=fmax, tmax=tmax +) + +# Create a path and folder for every subject +path = os.path.join(str("Results")) +os.makedirs(path, exist_ok=True) + +############################################################################## +# Create the Pipelines +# -------------------- +# Two pipelines implementing elastic net classifiers, one using a fixed +# l1_ratio ("VanillaEN") and the other using a range of values to select +# l1_ratio ("GridSearchEN") + +pipelines = {} +pipelines["VanillaEN"] = Pipeline( + steps=[ + ("Covariances", Covariances("cov")), + ("Tangent_Space", TangentSpace(metric="riemann")), + ( + "LogistReg", + LogisticRegression( + penalty="elasticnet", + l1_ratio=0.75, + intercept_scaling=1000.0, + solver="saga", + max_iter=1000, + ), + ), + ] +) + +pipelines["GridSearchEN"] = Pipeline( + steps=[ + ("Covariances", Covariances("cov")), + ("Tangent_Space", TangentSpace(metric="riemann")), + ( + "LogistReg", + LogisticRegression( + penalty="elasticnet", + l1_ratio=0.70, + intercept_scaling=1000.0, + solver="saga", + max_iter=1000, + ), + ), + ] +) + +############################################################################## +# The search space for parameters is defined as a dictionary, specifying the +# name of the estimator and the parameter name as a key. + +param_grid = {} +param_grid["GridSearchEN"] = { + "LogistReg__l1_ratio": [0.15, 0.30, 0.45, 0.60, 0.75], +} + +############################################################################## +# Running the Evaluation +# ---------------------- +# If a param_grid is specified during process, the specified pipelines will +# automatically be run with a grid search. + +dataset.subject_list = dataset.subject_list[:1] +evaluation = WithinSessionEvaluation( + paradigm=paradigm, + datasets=dataset, + overwrite=True, + random_state=42, + hdf5_path=path, + n_jobs=-1, + save_model=True, +) +result = evaluation.process(pipelines, param_grid) + +##################################################################### +# Plot Results +# ------------ +# The grid search allows to find better parameter during the +# evaluation, leading to better accuracy results. + +fig, axes = plt.subplots(1, 1, figsize=[8, 5], sharey=True) + +sns.stripplot( + data=result, + y="score", + x="pipeline", + ax=axes, + jitter=True, + alpha=0.5, + zorder=1, + palette="Set1", +) +sns.pointplot(data=result, y="score", x="pipeline", ax=axes, palette="Set1") +axes.set_ylabel("ROC AUC") + +########################################################## +# Load Best Model Parameter +# ------------------------- +# The best model are automatically saved in a pickle file, in the +# results directory. It is possible to load those model for each +# dataset, subject and session. Here, we could see that the grid +# search found a l1_ratio that is different from the baseline +# value. + +with open( + "./Results/Models_WithinSession/BNCI2014-001/1/1test/GridSearchEN/fitted_model_best.pkl", + "rb", +) as pickle_file: + GridSearchEN_Session_E = load(pickle_file) + +print( + "Best Parameter l1_ratio Session_E GridSearchEN ", + GridSearchEN_Session_E.best_params_["LogistReg__l1_ratio"], +) + +print( + "Best Parameter l1_ratio Session_E VanillaEN: ", + pipelines["VanillaEN"].steps[2][1].l1_ratio, +) + +with open( + "./Results/Models_WithinSession/BNCI2014-001/1/0train/GridSearchEN/fitted_model_best.pkl", + "rb", +) as pickle_file: + GridSearchEN_Session_T = load(pickle_file) + +print( + "Best Parameter l1_ratio Session_T GridSearchEN ", + GridSearchEN_Session_T.best_params_["LogistReg__l1_ratio"], +) + +print( + "Best Parameter l1_ratio Session_T VanillaEN: ", + pipelines["VanillaEN"].steps[2][1].l1_ratio, +) diff --git a/docs/_downloads/b446bb6bcfa12c42d029c4259163f668/tutorial_1_simple_example_motor_imagery.py b/docs/_downloads/b446bb6bcfa12c42d029c4259163f668/tutorial_1_simple_example_motor_imagery.py new file mode 100644 index 00000000..7d564374 --- /dev/null +++ b/docs/_downloads/b446bb6bcfa12c42d029c4259163f668/tutorial_1_simple_example_motor_imagery.py @@ -0,0 +1,171 @@ +""" +================================ +Tutorial 1: Simple Motor Imagery +================================ + +In this example, we will go through all the steps to make a simple BCI +classification task, downloading a dataset and using a standard classifier. We +choose the dataset 2a from BCI Competition IV, a motor imagery task. We will +use a CSP to enhance the signal-to-noise ratio of the EEG epochs and a LDA to +classify these signals. +""" + +# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier +# +# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019 + +import warnings + +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns +from mne.decoding import CSP +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.pipeline import make_pipeline + +import moabb +from moabb.datasets import BNCI2014_001 +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import LeftRightImagery + + +moabb.set_log_level("info") +warnings.filterwarnings("ignore") + +############################################################################## +# Instantiating Dataset +# --------------------- +# +# The first thing to do is to instantiate the dataset that we want to analyze. +# MOABB has a list of many different datasets, each one containing all the +# necessary information for describing them, such as the number of subjects, +# size of trials, names of classes, etc. +# +# The dataset class has methods for: +# +# - downloading its files from some online source (e.g. Zenodo) +# - importing the data from the files in whatever extension they might be +# (like .mat, .gdf, etc.) and instantiate a Raw object from the MNE package + +dataset = BNCI2014_001() +dataset.subject_list = [1, 2, 3] + +############################################################################## +# Accessing EEG Recording +# ----------------------- +# +# As an example, we may access the EEG recording from a given session and a +# given run as follows: + +sessions = dataset.get_data(subjects=[1]) + +############################################################################## +# This returns a MNE Raw object that can be manipulated. This might be enough +# for some users, since the pre-processing and epoching steps can be easily +# done via MNE. However, to conduct an assessment of several classifiers on +# multiple subjects, MOABB ends up being a more appropriate option. + +subject = 1 +session_name = "0train" +run_name = "0" +raw = sessions[subject][session_name][run_name] + +############################################################################## +# Choosing a Paradigm +# ------------------- +# +# Once we have instantiated a dataset, we have to choose a paradigm. This +# object is responsible for filtering the data, epoching it, and extracting +# the labels for each epoch. Note that each dataset comes with the names of +# the paradigms to which it might be associated. It would not make sense to +# process a P300 dataset with a MI paradigm object. + +print(dataset.paradigm) + +############################################################################## +# For the example below, we will consider the paradigm associated to +# left-hand/right-hand motor imagery task, but there are other options in +# MOABB for motor imagery, P300 or SSVEP. + +paradigm = LeftRightImagery() + +############################################################################## +# We may check the list of all datasets available in MOABB for using with this +# paradigm (note that BNCI2014_001 is in it) + +print(paradigm.datasets) + +############################################################################## +# The data from a list of subjects could be preprocessed and return as a 3D +# numpy array `X`, follow a scikit-like format with the associated `labels`. +# The `meta` object contains all information regarding the subject, the +# session and the run associated to each trial. +X, labels, meta = paradigm.get_data(dataset=dataset, subjects=[1]) + +############################################################################## +# Create Pipeline +# --------------- +# +# Our goal is to evaluate the performance of a given classification pipeline +# (or several of them) when it is applied to the epochs from the previously +# chosen dataset. We will consider a very simple classification pipeline in +# which the dimension of the epochs are reduced via a CSP step and then +# classified via a linear discriminant analysis. + +pipeline = make_pipeline(CSP(n_components=8), LDA()) + +############################################################################## +# Evaluation +# ---------- +# +# To evaluate the score of this pipeline, we use the `evaluation` class. When +# instantiating it, we say which paradigm we want to consider, a list with the +# datasets to analyze, and whether the scores should be recalculated each time +# we run the evaluation or if MOABB should create a cache file. +# +# Note that there are different ways of evaluating a classifier; in this +# example, we choose `WithinSessionEvaluation`, which consists of doing a +# cross-validation procedure where the training and testing partitions are from +# the same recording session of the dataset. We could have used +# `CrossSessionEvaluation`, which takes all but one session as training +# partition and the remaining one as testing partition. + +evaluation = WithinSessionEvaluation( + paradigm=paradigm, + datasets=[dataset], + overwrite=True, + hdf5_path=None, +) + +############################################################################## +# We obtain the results in the form of a pandas dataframe + +results = evaluation.process({"csp+lda": pipeline}) + +############################################################################## +# The results are stored in locally, to avoid recomputing the results each time. +# It is saved in `hdf5_path` if defined or in ~/mne_data/results otherwise. +# To export the results in CSV: + +results.to_csv("./results_part2-1.csv") + +############################################################################## +# To load previously obtained results saved in CSV + +results = pd.read_csv("./results_part2-1.csv") + +############################################################################## +# Plotting Results +# ---------------- +# +# We create a figure with the seaborn package comparing the classification +# score for each subject on each session. Note that the 'subject' field from +# the `results` is given in terms of integers, but seaborn accepts only +# strings for its labeling. This is why we create the field 'subj'. + +fig, ax = plt.subplots(figsize=(8, 7)) +results["subj"] = results["subject"].apply(str) +sns.barplot( + x="score", y="subj", hue="session", data=results, orient="h", palette="viridis", ax=ax +) +plt.show() diff --git a/docs/_downloads/b766ff8fcb1665a3edb7ffee945fcb2d/noplot_phmd_ml_spectrum.py b/docs/_downloads/b766ff8fcb1665a3edb7ffee945fcb2d/noplot_phmd_ml_spectrum.py new file mode 100644 index 00000000..74613870 --- /dev/null +++ b/docs/_downloads/b766ff8fcb1665a3edb7ffee945fcb2d/noplot_phmd_ml_spectrum.py @@ -0,0 +1,71 @@ +""" +================================ +Spectral analysis of the trials +================================ + +This example demonstrates how to perform spectral +analysis on epochs extracted from a specific subject +within the :class:`moabb.datasets.Cattan2019_PHMD` dataset. + +""" + +# Authors: Pedro Rodrigues +# Modified by: Gregoire Cattan +# License: BSD (3-clause) + +import warnings + +import matplotlib.pyplot as plt +import numpy as np + +from moabb.datasets import Cattan2019_PHMD +from moabb.paradigms import RestingStateToP300Adapter + + +warnings.filterwarnings("ignore") + +############################################################################### +# Initialization +# --------------- +# +# 1) Specify the channel and subject to compute the power spectrum. +# 2) Create an instance of the :class:`moabb.datasets.Cattan2019_PHMD` dataset. +# 3) Create an instance of the :class:`moabb.paradigms.RestingStateToP300Adapter` paradigm. +# By default, the data is filtered between 1-35 Hz, +# and epochs are extracted from 10 to 50 seconds after event tagging. + +# Select channel and subject for the remaining of the example. +channel = "Cz" +subject = 1 + +dataset = Cattan2019_PHMD() +events = ["on", "off"] +paradigm = RestingStateToP300Adapter(events=events, channels=[channel]) + +############################################################################### +# Estimate Power Spectral Density +# --------------- +# 1) Obtain the epochs for the specified subject. +# 2) Use Welch's method to estimate the power spectral density. + +f, S, _, y = paradigm.psd(subject, dataset) + +############################################################################### +# Display of the data +# --------------- +# +# Plot the averaged Power Spectral Density (PSD) for each label condition, +# using the selected channel specified at the beginning of the script. + +fig, ax = plt.subplots(facecolor="white", figsize=(8.2, 5.1)) +for condition in events: + mean_power = np.mean(S[y == condition], axis=0).flatten() + ax.plot(f, 10 * np.log10(mean_power), label=condition) + +ax.set_xlim(paradigm.fmin, paradigm.fmax) +ax.set_ylim(100, 135) +ax.set_ylabel("Spectrum Magnitude (dB)", fontsize=14) +ax.set_xlabel("Frequency (Hz)", fontsize=14) +ax.set_title("PSD for Channel " + channel, fontsize=16) +ax.legend() +fig.show() diff --git a/docs/_downloads/b9f56e19f2500dad10214cc29a2a24e4/plot_mne_and_scikit_estimators.ipynb b/docs/_downloads/b9f56e19f2500dad10214cc29a2a24e4/plot_mne_and_scikit_estimators.ipynb new file mode 100644 index 00000000..2fff5778 --- /dev/null +++ b/docs/_downloads/b9f56e19f2500dad10214cc29a2a24e4/plot_mne_and_scikit_estimators.ipynb @@ -0,0 +1,216 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# MNE Epochs-based pipelines\n\nThis example shows how to use machine learning pipeline based on MNE Epochs\ninstead of Numpy arrays. This is useful to make the most of the MNE code base\nand to embed EEG specific code inside sklearn pipelines.\n\nWe will compare different pipelines for P300:\n- Logistic regression, based on MNE Epochs\n- XDAWN and Logistic Regression (LR), based on MNE Epochs\n- XDAWN extended covariance and LR on tangent space, based on Numpy\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Sylvain Chevallier\n#\n# License: BSD (3-clause)\n# sphinx_gallery_thumbnail_number = 2\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom mne.decoding import Vectorizer\nfrom mne.preprocessing import Xdawn\nfrom pyriemann.estimation import XdawnCovariances\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.base import BaseEstimator, TransformerMixin\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.preprocessing import StandardScaler\n\nimport moabb\nfrom moabb.analysis.meta_analysis import ( # noqa: E501\n compute_dataset_statistics,\n find_significant_differences,\n)\nfrom moabb.analysis.plotting import paired_plot, summary_plot\nfrom moabb.datasets import BNCI2014_009\nfrom moabb.evaluations import CrossSessionEvaluation\nfrom moabb.paradigms import P300\n\n\nwarnings.simplefilter(action=\"ignore\", category=FutureWarning)\nwarnings.simplefilter(action=\"ignore\", category=RuntimeWarning)\nmoabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading Dataset\n\nLoad 2 subjects of BNCI 2014-009 dataset, with 3 session each\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset = BNCI2014_009()\ndataset.subject_list = dataset.subject_list[:3]\ndatasets = [dataset]\nparadigm = P300()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get Data (optional)\n\nTo get access to the EEG signals downloaded from the dataset, you could\nuse ``dataset.get_data([subject_id)`` to obtain the EEG as MNE Epochs, stored\nin a dictionary of sessions and runs.\nThe ``paradigm.get_data(dataset=dataset, subjects=[subject_id])`` allows to\nobtain the preprocessed EEG data, the labels and the meta information. By\ndefault, the EEG is return as a Numpy array. With ``return_epochs=True``, MNE\nEpochs are returned.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "subject_list = [1]\nsessions = dataset.get_data(subject_list)\nX, labels, meta = paradigm.get_data(dataset=dataset, subjects=subject_list)\nepochs, labels, meta = paradigm.get_data(\n dataset=dataset, subjects=subject_list, return_epochs=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## A Simple MNE Pipeline\n\nUsing ``return_epochs=True`` in the evaluation, it is possible to design a\npipeline based on MNE Epochs input. Let's create a simple one, that\nreshape the input data from epochs, rescale the data and uses a logistic\nregression to classify the data. We will need to write a basic Transformer\nestimator, that complies with\n[sklearn convention](https://scikit-learn.org/stable/developers/develop.html).\nThis transformer will extract the data from an input Epoch, and reshapes into\n2D array.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class MyVectorizer(BaseEstimator, TransformerMixin):\n def __init__(self):\n pass\n\n def fit(self, X, y=None):\n arr = X.get_data()\n self.features_shape_ = arr.shape[1:]\n return self\n\n def transform(self, X, y=None):\n arr = X.get_data()\n return arr.reshape(len(arr), -1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will define a pipeline that is based on this new class, using a scaler\nand a logistic regression. This pipeline is evaluated across session using\nROC-AUC metric.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "mne_ppl = {}\nmne_ppl[\"MNE LR\"] = make_pipeline(\n MyVectorizer(), StandardScaler(), LogisticRegression(penalty=\"l1\", solver=\"liblinear\")\n)\n\nmne_eval = CrossSessionEvaluation(\n paradigm=paradigm,\n datasets=datasets,\n suffix=\"examples\",\n overwrite=True,\n return_epochs=True,\n)\nmne_res = mne_eval.process(mne_ppl)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Advanced MNE Pipeline\n\nIn some case, the MNE pipeline should have access to the original labels from\nthe dataset. This is the case for the XDAWN code of MNE. One could pass\n`mne_labels` to evaluation in order to keep this label.\nAs an example, we will define a pipeline that computes an XDAWN filter, rescale,\nthen apply a logistic regression.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "mne_adv = {}\nmne_adv[\"XDAWN LR\"] = make_pipeline(\n Xdawn(n_components=5, reg=\"ledoit_wolf\", correct_overlap=False),\n Vectorizer(),\n StandardScaler(),\n LogisticRegression(penalty=\"l1\", solver=\"liblinear\"),\n)\nadv_eval = CrossSessionEvaluation(\n paradigm=paradigm,\n datasets=datasets,\n suffix=\"examples\",\n overwrite=True,\n return_epochs=True,\n mne_labels=True,\n)\nadv_res = mne_eval.process(mne_adv)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Numpy-based Pipeline\n\nFor the comparison, we will define a Numpy-based pipeline that relies on\npyriemann to estimate XDAWN-extended covariance matrices that are projected\non the tangent space and classified with a logistic regression.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sk_ppl = {}\nsk_ppl[\"RG LR\"] = make_pipeline(\n XdawnCovariances(nfilter=5, estimator=\"lwf\", xdawn_estimator=\"scm\"),\n TangentSpace(),\n LogisticRegression(penalty=\"l1\", solver=\"liblinear\"),\n)\nsk_eval = CrossSessionEvaluation(\n paradigm=paradigm,\n datasets=datasets,\n suffix=\"examples\",\n overwrite=True,\n)\nsk_res = sk_eval.process(sk_ppl)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Combining Results\n\nEven if the results have been obtained by different evaluation processes, it\nis possible to combine the resulting DataFrames to analyze and plot the\nresults.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "all_res = pd.concat([mne_res, adv_res, sk_res])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We could compare the Euclidean and Riemannian performance using a `paired_plot`\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paired_plot(all_res, \"XDAWN LR\", \"RG LR\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All the results could be compared and statistical analysis could highlight the\ndifferences between pipelines.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "stats = compute_dataset_statistics(all_res)\nP, T = find_significant_differences(stats)\nsummary_plot(P, T)\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/c0d5130414c37580257e7e0b7de777e2/plot_grid_search_withinsession.ipynb b/docs/_downloads/c0d5130414c37580257e7e0b7de777e2/plot_grid_search_withinsession.ipynb new file mode 100644 index 00000000..13e489c7 --- /dev/null +++ b/docs/_downloads/c0d5130414c37580257e7e0b7de777e2/plot_grid_search_withinsession.ipynb @@ -0,0 +1,144 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# GridSearch within a session\n\nThis example demonstrates how to make a model selection in pipelines\nfor finding the best model parameter, using grid search. Two models\nare compared, one \"vanilla\" model with model tuned via grid search.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import os\nfrom pickle import load\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom pyriemann.estimation import Covariances\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.pipeline import Pipeline\n\nfrom moabb.datasets import BNCI2014_001\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import MotorImagery\n\n\n# Initialize parameter for the Band Pass filter\nfmin = 8\nfmax = 35\ntmax = None\n\n# Select the Subject\nsubjects = [1]\n# Load the dataset\ndataset = BNCI2014_001()\n\nevents = [\"right_hand\", \"left_hand\"]\n\nparadigm = MotorImagery(\n events=events, n_classes=len(events), fmin=fmin, fmax=fmax, tmax=tmax\n)\n\n# Create a path and folder for every subject\npath = os.path.join(str(\"Results\"))\nos.makedirs(path, exist_ok=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create the Pipelines\nTwo pipelines implementing elastic net classifiers, one using a fixed\nl1_ratio (\"VanillaEN\") and the other using a range of values to select\nl1_ratio (\"GridSearchEN\")\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipelines = {}\npipelines[\"VanillaEN\"] = Pipeline(\n steps=[\n (\"Covariances\", Covariances(\"cov\")),\n (\"Tangent_Space\", TangentSpace(metric=\"riemann\")),\n (\n \"LogistReg\",\n LogisticRegression(\n penalty=\"elasticnet\",\n l1_ratio=0.75,\n intercept_scaling=1000.0,\n solver=\"saga\",\n max_iter=1000,\n ),\n ),\n ]\n)\n\npipelines[\"GridSearchEN\"] = Pipeline(\n steps=[\n (\"Covariances\", Covariances(\"cov\")),\n (\"Tangent_Space\", TangentSpace(metric=\"riemann\")),\n (\n \"LogistReg\",\n LogisticRegression(\n penalty=\"elasticnet\",\n l1_ratio=0.70,\n intercept_scaling=1000.0,\n solver=\"saga\",\n max_iter=1000,\n ),\n ),\n ]\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The search space for parameters is defined as a dictionary, specifying the\nname of the estimator and the parameter name as a key.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "param_grid = {}\nparam_grid[\"GridSearchEN\"] = {\n \"LogistReg__l1_ratio\": [0.15, 0.30, 0.45, 0.60, 0.75],\n}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running the Evaluation\nIf a param_grid is specified during process, the specified pipelines will\nautomatically be run with a grid search.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset.subject_list = dataset.subject_list[:1]\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm,\n datasets=dataset,\n overwrite=True,\n random_state=42,\n hdf5_path=path,\n n_jobs=-1,\n save_model=True,\n)\nresult = evaluation.process(pipelines, param_grid)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\nThe grid search allows to find better parameter during the\nevaluation, leading to better accuracy results.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, axes = plt.subplots(1, 1, figsize=[8, 5], sharey=True)\n\nsns.stripplot(\n data=result,\n y=\"score\",\n x=\"pipeline\",\n ax=axes,\n jitter=True,\n alpha=0.5,\n zorder=1,\n palette=\"Set1\",\n)\nsns.pointplot(data=result, y=\"score\", x=\"pipeline\", ax=axes, palette=\"Set1\")\naxes.set_ylabel(\"ROC AUC\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load Best Model Parameter\nThe best model are automatically saved in a pickle file, in the\nresults directory. It is possible to load those model for each\ndataset, subject and session. Here, we could see that the grid\nsearch found a l1_ratio that is different from the baseline\nvalue.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "with open(\n \"./Results/Models_WithinSession/BNCI2014-001/1/1test/GridSearchEN/fitted_model_best.pkl\",\n \"rb\",\n) as pickle_file:\n GridSearchEN_Session_E = load(pickle_file)\n\nprint(\n \"Best Parameter l1_ratio Session_E GridSearchEN \",\n GridSearchEN_Session_E.best_params_[\"LogistReg__l1_ratio\"],\n)\n\nprint(\n \"Best Parameter l1_ratio Session_E VanillaEN: \",\n pipelines[\"VanillaEN\"].steps[2][1].l1_ratio,\n)\n\nwith open(\n \"./Results/Models_WithinSession/BNCI2014-001/1/0train/GridSearchEN/fitted_model_best.pkl\",\n \"rb\",\n) as pickle_file:\n GridSearchEN_Session_T = load(pickle_file)\n\nprint(\n \"Best Parameter l1_ratio Session_T GridSearchEN \",\n GridSearchEN_Session_T.best_params_[\"LogistReg__l1_ratio\"],\n)\n\nprint(\n \"Best Parameter l1_ratio Session_T VanillaEN: \",\n pipelines[\"VanillaEN\"].steps[2][1].l1_ratio,\n)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/c0e8dffad0e66be84b9a762a9f24a516/plot_explore_paradigm.ipynb b/docs/_downloads/c0e8dffad0e66be84b9a762a9f24a516/plot_explore_paradigm.ipynb new file mode 100644 index 00000000..9c89c869 --- /dev/null +++ b/docs/_downloads/c0e8dffad0e66be84b9a762a9f24a516/plot_explore_paradigm.ipynb @@ -0,0 +1,288 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Explore Paradigm Object\n\nA paradigm defines how the raw data will be converted to trials ready\nto be processed by a decoding algorithm. This is a function of the paradigm\nused, i.e. in motor imagery one can have two-class, multi-class,\nor continuous paradigms; similarly, different preprocessing is necessary\nfor ERP vs ERD paradigms.\n\nA paradigm also defines the appropriate evaluation metric, for example AUC\nfor binary classification problems, accuracy for multiclass, or kappa\ncoefficients for continuous paradigms.\n\nThis tutorial explores the paradigm object, with 3 examples of paradigm :\n - MotorImagery\n - FilterBankMotorImagery\n - LeftRightImagery\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Alexandre Barachant \n# Sylvain Chevallier \n#\n# License: BSD (3-clause)\n\nimport numpy as np\n\nfrom moabb.datasets import BNCI2014_001\nfrom moabb.paradigms import FilterBankMotorImagery, LeftRightImagery, MotorImagery\n\n\nprint(__doc__)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## MotorImagery\n\nFirst, let's take an example of the MotorImagery paradigm.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = MotorImagery(n_classes=4)\n\nprint(paradigm.__doc__)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The function `get_data` allow you to access preprocessed data from a dataset.\nthis function will return 3 objects. A numpy array containing the\npreprocessed EEG data, the labels, and a dataframe with metadata.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(paradigm.get_data.__doc__)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lets take the example of the BNCI2014_001 dataset, known as the dataset IIa\nfrom the BCI competition IV. We will load the data from the subject 1.\nWhen calling `get_data`, the paradigm will retrieve the data from the\nspecified list of subjects, apply preprocessing (by default, a bandpass\nbetween 7 and 35 Hz), epoch the data (with interval specified by the dataset,\nunless superseded by the paradigm) and return the corresponding objects.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset = BNCI2014_001()\nsubjects = [1]\n\nX, y, metadata = paradigm.get_data(dataset=dataset, subjects=subjects)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The epoched data is a 3D array, with epochs on the first dimension (here\n576 trials), channels on the second (22 channels) and time sample on the last\none.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(X.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Labels contains the labels corresponding to each trial. in the case of this\ndataset, we have the 4 types of motor imagery that was performed.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(np.unique(y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Metadata have at least 3 columns: subject, session and run.\n\n- subject is the subject id of the corresponding trial\n- session is the session id. A session denotes a recording made without\n removing the EEG cap.\n- run is the individual continuous recording made during a session. A session\n may or may not contain multiple runs.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(metadata.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this data, we have one subject, 2 sessions (2 different recording days)\nand 6 runs per session.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(metadata.describe(include=\"all\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Paradigm objects can also return the list of all dataset compatible. Here\nit will return the list all the imagery datasets from the MOABB.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "compatible_datasets = paradigm.datasets\nprint([dataset.code for dataset in compatible_datasets])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## FilterBank MotorImagery\n\nFilterBankMotorImagery is the same paradigm, but with a different\npreprocessing. In this case, it applies a bank of 6 bandpass filter on the data\nbefore concatenating the output.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = FilterBankMotorImagery()\n\nprint(paradigm.__doc__)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Therefore, the output X is a 4D array, with trial x channel x time x filter\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X, y, metadata = paradigm.get_data(dataset=dataset, subjects=subjects)\n\nprint(X.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## LeftRight MotorImagery\n\nLeftRightImagery is a variation over the BaseMotorImagery paradigm,\nrestricted to left- and right-hand events.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = LeftRightImagery()\n\nprint(paradigm.__doc__)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The compatible dataset list is a subset of motor imagery dataset that\ncontains at least left and right hand events.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "compatible_datasets = paradigm.datasets\nprint([dataset.code for dataset in compatible_datasets])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So if we apply this to our original dataset, it will only return trials\ncorresponding to left- and right-hand motor imagination.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X, y, metadata = paradigm.get_data(dataset=dataset, subjects=subjects)\n\nprint(np.unique(y))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/c231a2e535b6091b8fee66bcebfa041c/changing_download_directory.ipynb b/docs/_downloads/c231a2e535b6091b8fee66bcebfa041c/changing_download_directory.ipynb new file mode 100644 index 00000000..7dc1fffc --- /dev/null +++ b/docs/_downloads/c231a2e535b6091b8fee66bcebfa041c/changing_download_directory.ipynb @@ -0,0 +1,108 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Change Download Directory\n\nThis is a minimal example to demonstrate how to change the default data\ndownload directory to a custom path/location. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Divyesh Narayanan \n#\n# License: BSD (3-clause)\n\nimport os.path as osp\n\nfrom mne import get_config\n\nfrom moabb.utils import set_download_dir" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can choose to change the download directory to any path of your choice.\nIf the path/folder doesn't exist, it will be created for you.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "original_path = get_config(\"MNE_DATA\")\nprint(f\"The download directory is currently {original_path}\")\nnew_path = osp.join(osp.expanduser(\"~\"), \"mne_data_test\")\nset_download_dir(new_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You could verify that the MNE config has been changed correctly\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "check_path = get_config(\"MNE_DATA\")\nprint(f\"Now the download directory has been changed to {check_path}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the directory back to default location\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "set_download_dir(original_path)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/c82f3928cb70181ccb714f9ce973e8e7/plot_Getting_Started.ipynb b/docs/_downloads/c82f3928cb70181ccb714f9ce973e8e7/plot_Getting_Started.ipynb new file mode 100644 index 00000000..8f9f5f8e --- /dev/null +++ b/docs/_downloads/c82f3928cb70181ccb714f9ce973e8e7/plot_Getting_Started.ipynb @@ -0,0 +1,234 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Tutorial 0: Getting Started\n\nThis tutorial takes you through a basic working example of how to use this\ncodebase, including all the different components, up to the results\ngeneration. If you'd like to know about the statistics and plotting, see the\nnext tutorial.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Vinay Jayaram \n#\n# License: BSD (3-clause)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction\nTo use the codebase you need an evaluation and a paradigm, some algorithms,\nand a list of datasets to run it all on. You can find those in the following\nsubmodules; detailed tutorials are given for each of them.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.model_selection import GridSearchCV\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.svm import SVC" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you would like to specify the logging level when it is running, you can\nuse the standard python logging commands through the top-level moabb module\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import moabb\nfrom moabb.datasets import BNCI2014_001, utils\nfrom moabb.evaluations import CrossSessionEvaluation\nfrom moabb.paradigms import LeftRightImagery\nfrom moabb.pipelines.features import LogVariance" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to create pipelines within a script, you will likely need at least\nthe make_pipeline function. They can also be specified via a .yml file. Here\nwe will make a couple pipelines just for convenience\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "moabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create pipelines\n\nWe create two pipelines: channel-wise log variance followed by LDA, and\nchannel-wise log variance followed by a cross-validated SVM (note that a\ncross-validation via scikit-learn cannot be described in a .yml file). For\nlater in the process, the pipelines need to be in a dictionary where the key\nis the name of the pipeline and the value is the Pipeline object\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipelines = {}\npipelines[\"AM+LDA\"] = make_pipeline(LogVariance(), LDA())\nparameters = {\"C\": np.logspace(-2, 2, 10)}\nclf = GridSearchCV(SVC(kernel=\"linear\"), parameters)\npipe = make_pipeline(LogVariance(), clf)\n\npipelines[\"AM+SVM\"] = pipe" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Datasets\n\nDatasets can be specified in many ways: Each paradigm has a property\n'datasets' which returns the datasets that are appropriate for that paradigm\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(LeftRightImagery().datasets)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or you can run a search through the available datasets:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(utils.dataset_search(paradigm=\"imagery\", min_subjects=6))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or you can simply make your own list (which we do here due to computational\nconstraints)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset = BNCI2014_001()\ndataset.subject_list = dataset.subject_list[:2]\ndatasets = [dataset]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Paradigm\n\nParadigms define the events, epoch time, bandpass, and other preprocessing\nparameters. They have defaults that you can read in the documentation, or you\ncan simply set them as we do here. A single paradigm defines a method for\ngoing from continuous data to trial data of a fixed size. To learn more look\nat the tutorial Exploring Paradigms\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fmin = 8\nfmax = 35\nparadigm = LeftRightImagery(fmin=fmin, fmax=fmax)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nAn evaluation defines how the training and test sets are chosen. This could\nbe cross-validated within a single recording, or across days, or sessions, or\nsubjects. This also is the correct place to specify multiple threads.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "evaluation = CrossSessionEvaluation(\n paradigm=paradigm, datasets=datasets, suffix=\"examples\", overwrite=False\n)\nresults = evaluation.process(pipelines)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Results are returned as a pandas DataFrame, and from here you can do as you\nwant with them\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(results.head())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/c9b0437022c98a63476dd3cad6cb69c7/plot_braindecode.py b/docs/_downloads/c9b0437022c98a63476dd3cad6cb69c7/plot_braindecode.py new file mode 100644 index 00000000..2bea99d1 --- /dev/null +++ b/docs/_downloads/c9b0437022c98a63476dd3cad6cb69c7/plot_braindecode.py @@ -0,0 +1,152 @@ +""" +=============================================================== +Cross-session motor imagery with deep learning EEGNet v4 model +=============================================================== +This example shows how to use BrainDecode in combination with MOABB evaluation. +In this example, we use the architecture EEGNetv4. +""" + +# Authors: Igor Carrara +# Bruno Aristimunha +# +# License: BSD (3-clause) + +import matplotlib.pyplot as plt +import mne +import seaborn as sns +import torch +from braindecode import EEGClassifier +from braindecode.models import EEGNetv4 +from sklearn.pipeline import make_pipeline +from skorch.callbacks import EarlyStopping, EpochScoring +from skorch.dataset import ValidSplit + +from moabb.datasets import BNCI2014_001 +from moabb.evaluations import CrossSessionEvaluation +from moabb.paradigms import MotorImagery +from moabb.utils import setup_seed + + +mne.set_log_level(False) + +# Print Information PyTorch +print(f"Torch Version: {torch.__version__}") + +# Set up GPU if it is there +cuda = torch.cuda.is_available() +device = "cuda" if cuda else "cpu" +print("GPU is", "AVAILABLE" if cuda else "NOT AVAILABLE") + +############################################################################### +# In this example, we will use only the dataset ``BNCI2014_001``. +# +# Running the benchmark +# --------------------- +# +# This example uses the CrossSession evaluation procedure. We focus on the dataset BNCI2014_001 and only on 1 subject +# to reduce computational time. +# +# To keep the computational time low, the epoch is reduced. In a real situation, we suggest using the following: +# EPOCH = 1000 +# PATIENCE = 300 +# +# This code is implemented to run on the CPU. If you're using a GPU, do not use multithreading +# (i.e. set n_jobs=1) + + +# Set random seed to be able to reproduce results +seed = 42 +setup_seed(seed) + +# Ensure that all operations are deterministic on GPU (if used) for reproducibility +torch.backends.cudnn.deterministic = True +torch.backends.cudnn.benchmark = False + +# Hyperparameter +LEARNING_RATE = 0.0625 * 0.01 # parameter taken from Braindecode +WEIGHT_DECAY = 0 # parameter taken from Braindecode +BATCH_SIZE = 64 # parameter taken from BrainDecode +EPOCH = 10 +PATIENCE = 3 +fmin = 4 +fmax = 100 +tmin = 0 +tmax = None + +# Load the dataset +dataset = BNCI2014_001() +events = ["right_hand", "left_hand"] +paradigm = MotorImagery( + events=events, n_classes=len(events), fmin=fmin, fmax=fmax, tmin=tmin, tmax=tmax +) +subjects = [1] +X, _, _ = paradigm.get_data(dataset=dataset, subjects=subjects) + +############################################################################## +# Create Pipelines +# ---------------- +# In order to create a pipeline, we need to load a model from braindecode. +# the second step is to define a skorch model using EEGClassifier from braindecode +# that allows converting the PyTorch model in a scikit-learn classifier. +# Here, we will use the EEGNet v4 model [1]_ . +# This model has mandatory hyperparameters (the number of channels, the number of classes, +# and the temporal length of the input) but we do not need to specify them because they will +# be set dynamically by EEGClassifier using the input data during the call to the ``.fit()`` method. + +# Define a Skorch classifier +clf = EEGClassifier( + module=EEGNetv4, + optimizer=torch.optim.Adam, + optimizer__lr=LEARNING_RATE, + batch_size=BATCH_SIZE, + max_epochs=EPOCH, + train_split=ValidSplit(0.2, random_state=seed), + device=device, + callbacks=[ + EarlyStopping(monitor="valid_loss", patience=PATIENCE), + EpochScoring( + scoring="accuracy", on_train=True, name="train_acc", lower_is_better=False + ), + EpochScoring( + scoring="accuracy", on_train=False, name="valid_acc", lower_is_better=False + ), + ], + verbose=1, # Not printing the results for each epoch +) + +# Create the pipelines +pipes = {} +pipes["EEGNetV4"] = make_pipeline(clf) + +############################################################################## +# Evaluation +# ---------- +dataset.subject_list = dataset.subject_list[:2] + +evaluation = CrossSessionEvaluation( + paradigm=paradigm, + datasets=dataset, + suffix="braindecode_example", + overwrite=True, + return_epochs=True, + n_jobs=1, +) + +results = evaluation.process(pipes) + +print(results.head()) + +############################################################################## +# Plot Results +# ---------------- +plt.figure() +sns.barplot(data=results, y="score", x="subject", palette="viridis") +plt.show() +############################################################################## +# References +# ---------- +# .. [1] Lawhern, V. J., Solon, A. J., Waytowich, N. R., Gordon, S. M., +# Hung, C. P., & Lance, B. J. (2018). `EEGNet: a compact convolutional neural +# network for EEG-based brain-computer interfaces. +# `_ +# Journal of neural engineering, 15(5), 056013. diff --git a/docs/_downloads/cab7a090c4183ca69dc0cd84d3b04413/auto_tutorials_python.zip b/docs/_downloads/cab7a090c4183ca69dc0cd84d3b04413/auto_tutorials_python.zip new file mode 100644 index 0000000000000000000000000000000000000000..ab604a390fe3cf3b4a26271cf25e34e40116c047 GIT binary patch literal 27850 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 T\n#\n# License: BSD (3-clause)\n\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport seaborn as sns\nfrom mne.decoding import CSP\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nfrom moabb.datasets import BNCI2014_001\nfrom moabb.evaluations import CrossSessionEvaluation\nfrom moabb.paradigms import FilterBankLeftRightImagery, LeftRightImagery\nfrom moabb.pipelines.utils import FilterBank\n\n\nmoabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Pipelines\n\nThe CSP implementation from MNE is used. We selected 8 CSP components, as\nusually done in the literature.\n\nThe second pipeline is the filter bank CSP. We use the FilterBank object\nwith a CSP estimator. We set up the CSP to 4 components, to compensate for\nthe higher dimensionality.\n\nThe two pipelines will be applied on two different paradigm, so they have\ntheir own dict.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipelines = {}\npipelines[\"CSP+LDA\"] = make_pipeline(CSP(n_components=8), LDA())\n\npipelines_fb = {}\npipelines_fb[\"FBCSP+LDA\"] = make_pipeline(FilterBank(CSP(n_components=4)), LDA())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nSince two different preprocessing will be applied, we have two different\nparadigm objects. We have to make sure their filter matches so the comparison\nwill be fair.\n\nThe first one is a standard `LeftRightImagery` with a 8 to 35 Hz broadband\nfilter.\n\nThe second is a `FilterBankLeftRightImagery` with a bank of 2 filters, ranging\nfrom 8 to 35 Hz.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Because this is being auto-generated we only use 2 subjects\ndataset = BNCI2014_001()\ndataset.subject_list = dataset.subject_list[:2]\ndatasets = [dataset]\noverwrite = False # set to True if we want to overwrite cached results\n\n# broadband filters\nfmin = 8\nfmax = 35\nparadigm = LeftRightImagery(fmin=fmin, fmax=fmax)\nevaluation = CrossSessionEvaluation(\n paradigm=paradigm, datasets=datasets, suffix=\"examples\", overwrite=overwrite\n)\nresults = evaluation.process(pipelines)\n\n# Bank of 2 filters\nfilters = [[8, 24], [16, 32]]\nparadigm = FilterBankLeftRightImagery(filters=filters)\nevaluation = CrossSessionEvaluation(\n paradigm=paradigm, datasets=datasets, suffix=\"examples\", overwrite=overwrite\n)\nresults_fb = evaluation.process(pipelines_fb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After processing the two, we simply concatenate the results.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "results = pd.concat([results, results_fb])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\nHere we plot the results via seaborn. We first display a pointplot\nwith the average performance of each pipeline across session and subjects.\nThe second plot is a paired scatter plot. Each point representing the score\nof a single session. An algorithm will outperform another is most of the\npoints are in its quadrant.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, axes = plt.subplots(1, 2, figsize=[8, 4], sharey=True)\n\nsns.stripplot(\n data=results,\n y=\"score\",\n x=\"pipeline\",\n ax=axes[0],\n jitter=True,\n alpha=0.5,\n zorder=1,\n palette=\"Set1\",\n)\nsns.pointplot(data=results, y=\"score\", x=\"pipeline\", ax=axes[0], palette=\"Set1\")\n\naxes[0].set_ylabel(\"ROC AUC\")\naxes[0].set_ylim(0.5, 1)\n\n# paired plot\npaired = results.pivot_table(\n values=\"score\", columns=\"pipeline\", index=[\"subject\", \"session\"]\n)\npaired = paired.reset_index()\n\nsns.regplot(data=paired, y=\"FBCSP+LDA\", x=\"CSP+LDA\", ax=axes[1], fit_reg=False)\naxes[1].plot([0, 1], [0, 1], ls=\"--\", c=\"k\")\naxes[1].set_xlim(0.5, 1)\n\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/de620aa43eea2fc28a9b3587adf0d1f8/plot_disk_cache.py b/docs/_downloads/de620aa43eea2fc28a9b3587adf0d1f8/plot_disk_cache.py new file mode 100644 index 00000000..ed0e9e92 --- /dev/null +++ b/docs/_downloads/de620aa43eea2fc28a9b3587adf0d1f8/plot_disk_cache.py @@ -0,0 +1,264 @@ +""" +================================================= +Cache on disk intermediate data processing states +================================================= + +This example shows how intermediate data processing +states can be cached on disk to speed up the loading +of this data in subsequent calls. + +When a MOABB paradigm processes a dataset, it will +first apply processing steps to the raw data, this is +called the ``raw_pipeline``. Then, it will convert the +raw data into epochs and apply processing steps on the +epochs, this is called the ``epochs_pipeline``. +Finally, it will eventually convert the epochs into arrays, +this is called the ``array_pipeline``. In summary: + +``raw_pipeline`` --> ``epochs_pipeline`` --> ``array_pipeline`` + +After each step, MOABB offers the possibility to save on disk +the result of the step. This is done by setting the ``cache_config`` +parameter of the paradigm's ``get_data`` method. +The ``cache_config`` parameter is a dictionary that can take all +the parameters of ``moabb.datasets.base.CacheConfig`` as keys, +they are the following: ``use``, ``save_raw``, ``save_epochs``, +``save_array``, ``overwrite_raw``, ``overwrite_epochs``, +``overwrite_array``, and ``path``. You can also directly pass a +``CacheConfig`` object as ``cache_config``. + +If ``use=False``, the ``save_*`` and ``overwrite_*`` +parameters are ignored. + +When trying to use the cache (i.e. ``use=True``), MOABB will +first check if there exist a cache of the result of the full +pipeline (i.e. ``raw_pipeline`` --> ``epochs_pipeline`` -> +``array_pipeline``). +If there is none, we remove the last step of the pipeline and +look for its cached result. We keep removing steps and looking +for a cached result until we find one or until we reach an +empty pipeline. +Every time, if the ``overwrite_*`` parameter +of the corresponding step is true, we first try to erase the +cache of this step. +Once a cache has been found or the empty pipeline has been reached, +depending on the case we either load the cache or the original dataset. +Then, apply the missing steps one by one and save their result +if their corresponding ``save_*`` parameter is true. + +By default, only the result of the ``raw_pipeline`` is saved. +This is usually a good compromise between speed and disk space +because, when using cached raw data, the epochs can be obtained +without preloading the whole raw signals, only the necessary +intervals. Yet, because only the raw data is cached, the epoching +parameters can be changed without creating a new cache each time. +However, if your epoching parameters are fixed, you can directly +cache the epochs or the arrays to speed up the loading and +reduce the disk space used. + +.. note:: + The ``cache_config`` parameter is also available for the ``get_data`` + method of the datasets. It works the same way as for a + paradigm except that it will save un-processed raw recordings. +""" + +# Authors: Pierre Guetschel +# +# License: BSD (3-clause) + +import shutil +import tempfile + +############################################################################### +import time +from pathlib import Path + +from moabb import set_log_level +from moabb.datasets import Zhou2016 +from moabb.paradigms import LeftRightImagery + + +set_log_level("info") + +############################################################################### +# Basic usage +# ----------- +# +# The ``cache_config`` parameter is a dictionary that has the +# following default values: +default_cache_config = dict( + save_raw=False, + save_epochs=False, + save_array=False, + use=False, + overwrite_raw=False, + overwrite_epochs=False, + overwrite_array=False, + path=None, +) + +############################################################################### +# You don not need to specify all the keys of ``cache_config``, only the ones +# you want to change. +# +# By default, the cache is saved at the MNE data directory (i.e. when +# ``path=None``). The MNE data directory can be found with +# ``mne.get_config('MNE_DATA')``. For this example, we will save it in a +# temporary directory instead: +temp_dir = Path(tempfile.mkdtemp()) + +############################################################################### +# We will use the Zhou2016 dataset and the LeftRightImagery paradigm in this +# example, but this works for any dataset and paradigm pair.: +dataset = Zhou2016() +paradigm = LeftRightImagery() + +############################################################################### +# And we will only use the first subject for this example: +subjects = [1] + +############################################################################### +# Then, saving a cache can simply be done by setting the desired parameters +# in the ``cache_config`` dictionary: +cache_config = dict( + use=True, + save_raw=True, + save_epochs=True, + save_array=True, + path=temp_dir, +) +_ = paradigm.get_data(dataset, subjects, cache_config=cache_config) + +############################################################################### +# Time comparison +# --------------- +# +# Now, we will compare the time it takes to load the with different levels of +# cache. For this, we will use the cache saved in the previous block and +# overwrite the steps results one by one so that we can compare the time it +# takes to load the data and compute the missing steps with an increasing +# number of missing steps. +# +# Using array cache: +cache_config = dict( + use=True, + path=temp_dir, + save_raw=False, + save_epochs=False, + save_array=False, + overwrite_raw=False, + overwrite_epochs=False, + overwrite_array=False, +) +t0 = time.time() +_ = paradigm.get_data(dataset, subjects, cache_config=cache_config) +t_array = time.time() - t0 + +############################################################################### +# Using epochs cache: +cache_config = dict( + use=True, + path=temp_dir, + save_raw=False, + save_epochs=False, + save_array=False, + overwrite_raw=False, + overwrite_epochs=False, + overwrite_array=True, +) +t0 = time.time() +_ = paradigm.get_data(dataset, subjects, cache_config=cache_config) +t_epochs = time.time() - t0 + +############################################################################### +# Using raw cache: +cache_config = dict( + use=True, + path=temp_dir, + save_raw=False, + save_epochs=False, + save_array=False, + overwrite_raw=False, + overwrite_epochs=True, + overwrite_array=True, +) +t0 = time.time() +_ = paradigm.get_data(dataset, subjects, cache_config=cache_config) +t_raw = time.time() - t0 + +############################################################################### +# Using no cache: +cache_config = dict( + use=False, + path=temp_dir, + save_raw=False, + save_epochs=False, + save_array=False, + overwrite_raw=False, + overwrite_epochs=False, + overwrite_array=False, +) +t0 = time.time() +_ = paradigm.get_data(dataset, subjects, cache_config=cache_config) +t_nocache = time.time() - t0 + +############################################################################### +# Time needed to load the data with different levels of cache: +print(f"Using array cache: {t_array:.2f} seconds") +print(f"Using epochs cache: {t_epochs:.2f} seconds") +print(f"Using raw cache: {t_raw:.2f} seconds") +print(f"Without cache: {t_nocache:.2f} seconds") + +############################################################################### +# As you can see, using a raw cache is more than 5 times faster than +# without cache. +# This is because when using the raw cache, the data is not preloaded, only +# the desired epochs are loaded in memory. +# +# Using the epochs cache is a little faster than the raw cache. This is because +# there are several preprocessing steps done after the epoching by the +# ``epochs_pipeline``. This difference would be greater if the ``resample`` +# argument was different that the sampling frequency of the dataset. Indeed, +# the data loading time is directly proportional to its sampling frequency +# and the resampling is done by the ``epochs_pipeline``. +# +# Finally, we observe very little difference between array and epochs cache. +# The main interest of the array cache is when the user passes a +# computationally heavy but fixed additional preprocessing (for example +# computing the covariance matrices of the epochs). This can be done by using +# the ``postprocess_pipeline`` argument. The output of this additional pipeline +# (necessary a numpy array) will be saved to avoid re-computing it each time. +# +# +# Technical details +# ----------------- +# +# Under the hood, the cache is saved on disk in a Brain Imaging Data Structure +# (BIDS) compliant format. More details on this structure can be found in the +# tutorial :doc:`./plot_bids_conversion`. +# +# However, there are two particular aspects of the way MOABB saves the data +# that are not specific to BIDS: +# +# * For each file, we set a +# `description key `_. +# This key is a code that corresponds to a hash of the +# pipeline that was used to generate the data (i.e. from raw to the state +# of the cache). This code is unique for each different pipeline and allows +# to identify all the files that were generated by the same pipeline. +# * Once we finish saving all the files for a given combination of dataset, +# subject, and pipeline, we write a file ending in ``"_lockfile.json"`` at +# the root directory of this subject. This file serves two purposes: +# +# * It indicates that the cache is complete for this subject and pipeline. +# If it is not present, it means that something went wrong during the +# saving process and the cache is incomplete. +# * The file contains the un-hashed string representation of the pipeline. +# Therefore, it can be used to identify the pipeline used without having +# to decode the description key. +# +# Cleanup +# ------- +# +# Finally, we can delete the temporary folder: +shutil.rmtree(temp_dir) diff --git a/docs/_downloads/e34acbbaad3fb8832beb7fa8e4557c94/plot_learning_curve_p300_external.ipynb b/docs/_downloads/e34acbbaad3fb8832beb7fa8e4557c94/plot_learning_curve_p300_external.ipynb new file mode 100644 index 00000000..b32284fa --- /dev/null +++ b/docs/_downloads/e34acbbaad3fb8832beb7fa8e4557c94/plot_learning_curve_p300_external.ipynb @@ -0,0 +1,108 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Within Session P300 with Learning Curve\n\nThis example shows how to perform a within session analysis while also\ncreating learning curves for a P300 dataset.\nAdditionally, we will evaluate external code. Make sure to have tdlda installed\n, which can be found in requirements_external.txt\n\nWe will compare three pipelines :\n\n- Riemannian geometry\n- Jumping Means-based Linear Discriminant Analysis\n- Time-Decoupled Linear Discriminant Analysis\n\nWe will use the P300 paradigm, which uses the AUC as metric.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Jan Sosulski\n#\n# License: BSD (3-clause)\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns\nfrom pyriemann.estimation import XdawnCovariances\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.pipeline import make_pipeline\nfrom tdlda import TimeDecoupledLda\nfrom tdlda import Vectorizer as JumpingMeansVectorizer\n\nimport moabb\nfrom moabb.datasets import BNCI2014_009\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import P300\n\n\n# getting rid of the warnings about the future (on s'en fout !)\nwarnings.simplefilter(action=\"ignore\", category=FutureWarning)\nwarnings.simplefilter(action=\"ignore\", category=RuntimeWarning)\n\nmoabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create pipelines\n\nPipelines must be a dict of sklearn pipeline transformer.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "processing_sampling_rate = 128\npipelines = {}\n\n# We have to do this because the classes are called 'Target' and 'NonTarget'\n# but the evaluation function uses a LabelEncoder, transforming them\n# to 0 and 1\nlabels_dict = {\"Target\": 1, \"NonTarget\": 0}\n\n# Riemannian geometry based classification\npipelines[\"RG+LDA\"] = make_pipeline(\n XdawnCovariances(nfilter=5, estimator=\"lwf\", xdawn_estimator=\"scm\"),\n TangentSpace(),\n LDA(solver=\"lsqr\", shrinkage=\"auto\"),\n)\n\n# Simple LDA pipeline using averaged feature values in certain time intervals\njumping_mean_ivals = [\n [0.10, 0.139],\n [0.14, 0.169],\n [0.17, 0.199],\n [0.20, 0.229],\n [0.23, 0.269],\n [0.27, 0.299],\n [0.30, 0.349],\n [0.35, 0.409],\n [0.41, 0.449],\n [0.45, 0.499],\n]\njmv = JumpingMeansVectorizer(\n fs=processing_sampling_rate, jumping_mean_ivals=jumping_mean_ivals\n)\n\npipelines[\"JM+LDA\"] = make_pipeline(jmv, LDA(solver=\"lsqr\", shrinkage=\"auto\"))\n\n# Time-decoupled Covariance classifier, needs information about number of\n# channels and time intervals\nc = TimeDecoupledLda(N_channels=16, N_times=10)\n# TD-LDA needs to know about the used jumping means intervals\nc.preproc = jmv\npipelines[\"JM+TD-LDA\"] = make_pipeline(jmv, c)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nWe define the paradigm (P300) and use the BNCI 2014-009 dataset for it.\nThe evaluation will return a dataframe containing AUCs for each permutation\nand dataset size.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = P300(resample=processing_sampling_rate)\ndataset = BNCI2014_009()\n# Remove the slicing of the subject list to evaluate multiple subjects\ndataset.subject_list = dataset.subject_list[0:1]\ndatasets = [dataset]\noverwrite = True # set to True if we want to overwrite cached results\ndata_size = dict(policy=\"ratio\", value=np.geomspace(0.02, 1, 6))\n# When the training data is sparse, perform more permutations than when we have\n# a lot of data\nn_perms = np.floor(np.geomspace(20, 2, len(data_size[\"value\"]))).astype(int)\nprint(n_perms)\n# Guarantee reproducibility\nnp.random.seed(7536298)\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm,\n datasets=datasets,\n data_size=data_size,\n n_perms=n_perms,\n suffix=\"examples_lr\",\n overwrite=overwrite,\n)\n\nresults = evaluation.process(pipelines)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\nHere we plot the results.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(facecolor=\"white\", figsize=[8, 4])\n\nn_subs = len(dataset.subject_list)\n\nif n_subs > 1:\n r = results.groupby([\"pipeline\", \"subject\", \"data_size\"]).mean().reset_index()\nelse:\n r = results\n\nsns.pointplot(data=r, x=\"data_size\", y=\"score\", hue=\"pipeline\", ax=ax, palette=\"Set1\")\n\nerrbar_meaning = \"subjects\" if n_subs > 1 else \"permutations\"\ntitle_str = f\"Errorbar shows Mean-CI across {errbar_meaning}\"\nax.set_xlabel(\"Amount of training samples\")\nax.set_ylabel(\"ROC AUC\")\nax.set_title(title_str)\nfig.tight_layout()\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/f1e72fecd296ad91b914eb3562c881ee/plot_cross_session_motor_imagery.ipynb b/docs/_downloads/f1e72fecd296ad91b914eb3562c881ee/plot_cross_session_motor_imagery.ipynb new file mode 100644 index 00000000..b12e056f --- /dev/null +++ b/docs/_downloads/f1e72fecd296ad91b914eb3562c881ee/plot_cross_session_motor_imagery.ipynb @@ -0,0 +1,108 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Cross-Session Motor Imagery\n\nThis example show how to perform a cross session motor imagery analysis on the\nvery popular dataset 2a from the BCI competition IV.\n\nWe will compare two pipelines :\n\n- CSP+LDA\n- Riemannian Geometry+Logistic Regression\n\nWe will use the LeftRightImagery paradigm. This will restrict the analysis\nto two classes (left hand versus right hand) and use AUC as metric.\n\nThe cross session evaluation context will evaluate performance using a leave\none session out cross-validation. For each session in the dataset, a model\nis trained on every other session and performance are evaluated on the current\nsession.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Alexandre Barachant \n# Sylvain Chevallier \n#\n# License: BSD (3-clause)\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom mne.decoding import CSP\nfrom pyriemann.estimation import Covariances\nfrom pyriemann.tangentspace import TangentSpace\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nfrom moabb.datasets import BNCI2014_001\nfrom moabb.evaluations import CrossSessionEvaluation\nfrom moabb.paradigms import LeftRightImagery\n\n\nmoabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Pipelines\n\nPipelines must be a dict of sklearn pipeline transformer.\n\nThe CSP implementation is based on the MNE implementation. We selected 8 CSP\ncomponents, as usually done in the literature.\n\nThe Riemannian geometry pipeline consists in covariance estimation, tangent\nspace mapping and finally a logistic regression for the classification.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pipelines = {}\n\npipelines[\"CSP+LDA\"] = make_pipeline(CSP(n_components=8), LDA())\n\npipelines[\"RG+LR\"] = make_pipeline(\n Covariances(), TangentSpace(), LogisticRegression(solver=\"lbfgs\")\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nWe define the paradigm (LeftRightImagery) and the dataset (BNCI2014_001).\nThe evaluation will return a DataFrame containing a single AUC score for\neach subject / session of the dataset, and for each pipeline.\n\nResults are saved into the database, so that if you add a new pipeline, it\nwill not run again the evaluation unless a parameter has changed. Results can\nbe overwritten if necessary.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = LeftRightImagery()\n# Because this is being auto-generated we only use 2 subjects\ndataset = BNCI2014_001()\ndataset.subject_list = dataset.subject_list[:2]\ndatasets = [dataset]\noverwrite = False # set to True if we want to overwrite cached results\nevaluation = CrossSessionEvaluation(\n paradigm=paradigm, datasets=datasets, suffix=\"examples\", overwrite=overwrite\n)\n\nresults = evaluation.process(pipelines)\n\nprint(results.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\nHere we plot the results. We first make a pointplot with the average\nperformance of each pipeline across session and subjects.\nThe second plot is a paired scatter plot. Each point representing the score\nof a single session. An algorithm will outperform another is most of the\npoints are in its quadrant.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, axes = plt.subplots(1, 2, figsize=[8, 4], sharey=True)\n\nsns.stripplot(\n data=results,\n y=\"score\",\n x=\"pipeline\",\n ax=axes[0],\n jitter=True,\n alpha=0.5,\n zorder=1,\n palette=\"Set1\",\n)\nsns.pointplot(data=results, y=\"score\", x=\"pipeline\", ax=axes[0], palette=\"Set1\")\n\naxes[0].set_ylabel(\"ROC AUC\")\naxes[0].set_ylim(0.5, 1)\n\npaired = results.pivot_table(\n values=\"score\", columns=\"pipeline\", index=[\"subject\", \"session\"]\n)\npaired = paired.reset_index()\n\nsns.regplot(data=paired, y=\"RG+LR\", x=\"CSP+LDA\", ax=axes[1], fit_reg=False)\naxes[1].plot([0, 1], [0, 1], ls=\"--\", c=\"k\")\naxes[1].set_xlim(0.5, 1)\n\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/f2d00b929c914067772799fd6f99fb75/4_adding_a_dataset.ipynb b/docs/_downloads/f2d00b929c914067772799fd6f99fb75/4_adding_a_dataset.ipynb new file mode 100644 index 00000000..e5a8bf7d --- /dev/null +++ b/docs/_downloads/f2d00b929c914067772799fd6f99fb75/4_adding_a_dataset.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Tutorial 4: Creating a dataset class\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier\n#\n# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019\n\nimport mne\nimport numpy as np\nfrom pyriemann.classification import MDM\nfrom pyriemann.estimation import Covariances\nfrom scipy.io import loadmat, savemat\nfrom sklearn.pipeline import make_pipeline\n\nfrom moabb.datasets import download as dl\nfrom moabb.datasets.base import BaseDataset\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import LeftRightImagery" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating some Data\n\nTo illustrate the creation of a dataset class in MOABB, we first create an\nexample dataset saved in .mat file. It contains a single fake recording on\n8 channels lasting for 150 seconds (sampling frequency 256 Hz). We have\nincluded the script that creates this dataset and have uploaded it online.\nThe fake dataset is available on the\n[Zenodo website](https://sandbox.zenodo.org/record/369543)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def create_example_dataset():\n \"\"\"Create a fake example for a dataset.\"\"\"\n sfreq = 256\n t_recording = 150\n t_trial = 1 # duration of a trial\n intertrial = 2 # time between end of a trial and the next one\n n_chan = 8\n\n x = np.zeros((n_chan + 1, t_recording * sfreq)) # electrodes + stimulus\n stim = np.zeros(t_recording * sfreq)\n t_offset = 1.0 # offset where the trials start\n n_trials = 40\n\n rep = np.linspace(0, 4 * t_trial, t_trial * sfreq)\n signal = np.sin(2 * np.pi / t_trial * rep)\n for n in range(n_trials):\n label = n % 2 + 1 # alternate between class 0 and class 1\n tn = int(t_offset * sfreq + n * (t_trial + intertrial) * sfreq)\n stim[tn] = label\n noise = 0.1 * np.random.randn(n_chan, len(signal))\n x[:-1, tn : (tn + t_trial * sfreq)] = label * signal + noise\n x[-1, :] = stim\n return x, sfreq\n\n\n# Create the fake data\nfor subject in [1, 2, 3]:\n x, fs = create_example_dataset()\n filename = \"subject_\" + str(subject).zfill(2) + \".mat\"\n mdict = {}\n mdict[\"x\"] = x\n mdict[\"fs\"] = fs\n savemat(filename, mdict)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating a Dataset Class\n\nWe will create now a dataset class using the fake data simulated with the\ncode from above. For this, we first need to import the right classes from\nMOABB:\n\n- ``dl`` is a very useful script that downloads automatically a dataset online\n if it is not yet available in the user's computer. The script knows where\n to download the files because we create a global variable telling the URL\n where to fetch the data.\n- ``BaseDataset`` is the basic class that we overload to create our dataset.\n\nThe global variable with the dataset's URL should specify an online\nrepository where all the files are stored.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ExampleDataset_URL = \"https://sandbox.zenodo.org/record/369543/files/\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ``ExampleDataset`` needs to implement only 3 functions:\n\n- ``__init__`` for indicating the parameter of the dataset\n- ``_get_single_subject_data`` to define how to process the data once they\n have been downloaded\n- ``data_path`` to define how the data are downloaded.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class ExampleDataset(BaseDataset):\n \"\"\"Dataset used to exemplify the creation of a dataset class in MOABB.\n\n The data samples have been simulated and has no physiological\n meaning whatsoever.\n \"\"\"\n\n def __init__(self):\n super().__init__(\n subjects=[1, 2, 3],\n sessions_per_subject=1,\n events={\"left_hand\": 1, \"right_hand\": 2},\n code=\"ExampleDataset\",\n interval=[0, 0.75],\n paradigm=\"imagery\",\n doi=\"\",\n )\n\n def _get_single_subject_data(self, subject):\n \"\"\"Return data for a single subject.\"\"\"\n file_path_list = self.data_path(subject)\n\n data = loadmat(file_path_list[0])\n x = data[\"x\"]\n fs = data[\"fs\"]\n ch_names = [\"ch\" + str(i) for i in range(8)] + [\"stim\"]\n ch_types = [\"eeg\" for i in range(8)] + [\"stim\"]\n info = mne.create_info(ch_names, fs, ch_types)\n raw = mne.io.RawArray(x, info)\n\n sessions = {}\n sessions[\"0\"] = {}\n sessions[\"0\"][\"0\"] = raw\n return sessions\n\n def data_path(\n self, subject, path=None, force_update=False, update_path=None, verbose=None\n ):\n \"\"\"Download the data from one subject.\"\"\"\n if subject not in self.subject_list:\n raise (ValueError(\"Invalid subject number\"))\n\n url = \"{:s}subject_0{:d}.mat\".format(ExampleDataset_URL, subject)\n path = dl.data_dl(url, \"ExampleDataset\")\n return [path] # it has to return a list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using the ExampleDataset\n\nNow that the `ExampleDataset` is defined, it could be instantiated directly.\nThe rest of the code follows the steps described in the previous tutorials.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset = ExampleDataset()\n\nparadigm = LeftRightImagery()\nX, labels, meta = paradigm.get_data(dataset=dataset, subjects=[1])\n\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm, datasets=dataset, overwrite=False, suffix=\"newdataset\"\n)\npipelines = {}\npipelines[\"MDM\"] = make_pipeline(Covariances(\"oas\"), MDM(metric=\"riemann\"))\nscores = evaluation.process(pipelines)\n\nprint(scores)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pushing on MOABB Github\n\nIf you want to make your dataset available to everyone, you could upload\nyour data on public server (like Zenodo or Figshare) and signal that you\nwant to add your dataset to MOABB in the [dedicated issue](https://github.com/NeuroTechX/moabb/issues/1). # noqa: E501\nYou could then follow the instructions on [how to contribute](https://github.com/NeuroTechX/moabb/blob/master/CONTRIBUTING.md) # noqa: E501\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/f3215cecaa532ec823443b1b0630d3fb/plot_within_session_ssvep.ipynb b/docs/_downloads/f3215cecaa532ec823443b1b0630d3fb/plot_within_session_ssvep.ipynb new file mode 100644 index 00000000..fdcbe75d --- /dev/null +++ b/docs/_downloads/f3215cecaa532ec823443b1b0630d3fb/plot_within_session_ssvep.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Within Session SSVEP\n\nThis Example show how to perform a within-session SSVEP analysis on the\nMAMEM dataset 3, using a CCA pipeline.\n\nThe within-session evaluation assesses the performance of a classification\npipeline using a 5-fold cross-validation. The reported metric (here, accuracy)\nis the average of all fold.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Sylvain Chevallier \n#\n# License: BSD (3-clause)\n\nimport warnings\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom sklearn.pipeline import make_pipeline\n\nimport moabb\nfrom moabb.datasets import MAMEM3\nfrom moabb.evaluations import WithinSessionEvaluation\nfrom moabb.paradigms import SSVEP\nfrom moabb.pipelines import SSVEP_CCA\n\n\nwarnings.simplefilter(action=\"ignore\", category=FutureWarning)\nwarnings.simplefilter(action=\"ignore\", category=RuntimeWarning)\nmoabb.set_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading Dataset\n\nLoad 2 subjects of MAMEM3 dataset\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "subj = [1, 3]\ndataset = MAMEM3()\ndataset.subject_list = subj" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Choose Paradigm\n\nWe select the paradigm SSVEP, applying a bandpass filter (3-15 Hz) on\nthe data and we keep only the first 3 classes, that is stimulation\nfrequency of 6.66, 7.50 and 8.57 Hz.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = SSVEP(fmin=3, fmax=15, n_classes=3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Pipelines\n\nUse a Canonical Correlation Analysis classifier\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interval = dataset.interval\nfreqs = paradigm.used_events(dataset)\n\npipeline = {}\npipeline[\"CCA\"] = make_pipeline(SSVEP_CCA(interval=interval, freqs=freqs, n_harmonics=3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get Data (optional)\n\nTo get access to the EEG signals downloaded from the dataset, you could\nuse `dataset.get_data(subjects=[subject_id])` to obtain the EEG under\nMNE format, stored in a dictionary of sessions and runs.\nOtherwise, `paradigm.get_data(dataset=dataset, subjects=[subject_id])`\nallows to obtain the EEG data in scikit format, the labels and the meta\ninformation. In `paradigm.get_data`, the EEG are preprocessed according\nto the paradigm requirement.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# sessions = dataset.get_data(subjects=[3])\n# X, labels, meta = paradigm.get_data(dataset=dataset, subjects=[3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nThe evaluation will return a DataFrame containing a single AUC score for\neach subject and pipeline.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "overwrite = True # set to True if we want to overwrite cached results\n\nevaluation = WithinSessionEvaluation(\n paradigm=paradigm, datasets=dataset, suffix=\"examples\", overwrite=overwrite\n)\nresults = evaluation.process(pipeline)\n\nprint(results.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plot Results\n\nHere we plot the results, indicating the score for each subject\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plt.figure()\nsns.barplot(data=results, y=\"score\", x=\"session\", hue=\"subject\", palette=\"viridis\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And the computation time in seconds\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plt.figure()\nax = sns.barplot(data=results, y=\"time\", x=\"session\", hue=\"subject\", palette=\"Reds\")\nax.set_ylabel(\"Time (s)\")\nplt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/f4558bdb453cb198095be347c0f12fe0/example_codecarbon.ipynb b/docs/_downloads/f4558bdb453cb198095be347c0f12fe0/example_codecarbon.ipynb new file mode 100644 index 00000000..466893ef --- /dev/null +++ b/docs/_downloads/f4558bdb453cb198095be347c0f12fe0/example_codecarbon.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Benchmarking with MOABB showing the CO2 footprint\n\nThis example shows how to use MOABB to track the CO2 footprint\nusing [CodeCarbon library](https://codecarbon.io/)_.\nFor this example, we will use only one\ndataset to keep the computation time low, but this benchmark is designed\nto easily scale to many datasets. Due to limitation of online documentation\ngeneration, the results is computed on a local cluster but could be easily\nreplicated on your infrastructure.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Igor Carrara \n# Bruno Aristimunha \n#\n# License: BSD (3-clause)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from moabb import benchmark, set_log_level\nfrom moabb.analysis.plotting import codecarbon_plot\nfrom moabb.datasets import BNCI2014_001, Zhou2016\nfrom moabb.paradigms import LeftRightImagery\n\n\nset_log_level(\"info\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading the pipelines\n\nTo run this example we use several pipelines, ML and DL (Keras) and also\npipelines that need an optimization of the hyperparameter.\nAll this different pipelines are stored in ``pipelines_codecarbon``\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Selecting the datasets (optional)\n\nIf you want to limit your benchmark on a subset of datasets, you can use the\n``include_datasets`` and ``exclude_datasets`` arguments. You will need either\nto provide the dataset's object, or a dataset's code. To get the list of\navailable dataset's code for a given paradigm, you can use the following\ncommand:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "paradigm = LeftRightImagery()\nfor d in paradigm.datasets:\n print(d.code)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, we will use only the last dataset, 'Zhou 2016', considering\nonly the first subject.\n\n## Running the benchmark\n\nThe benchmark is run using the ``benchmark`` function. You need to specify the\nfolder containing the pipelines to use, the kind of evaluation and the paradigm\nto use. By default, the benchmark will use all available datasets for all\nparadigms listed in the pipelines. You could restrict to specific evaluation\nand paradigm using the ``evaluations`` and ``paradigms`` arguments.\n\nTo save computation time, the results are cached. If you want to re-run the\nbenchmark, you can set the ``overwrite`` argument to ``True``.\n\nIt is possible to indicate the folder to cache the results and the one to\nsave the analysis & figures. By default, the results are saved in the\n``results`` folder, and the analysis & figures are saved in the ``benchmark``\nfolder.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset = Zhou2016()\ndataset2 = BNCI2014_001()\ndataset.subject_list = dataset.subject_list[:1]\ndataset2.subject_list = dataset2.subject_list[:1]\ndatasets = [dataset, dataset2]\n\nresults = benchmark(\n pipelines=\"./pipelines_codecarbon/\",\n evaluations=[\"WithinSession\"],\n paradigms=[\"LeftRightImagery\"],\n include_datasets=datasets,\n results=\"./results/\",\n overwrite=False,\n plot=False,\n output=\"./benchmark/\",\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Benchmark prints a summary of the results. Detailed results are saved in a\npandas dataframe, and can be used to generate figures. The analysis & figures\nare saved in the ``benchmark`` folder.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "results.head()\n\norder_list = [\n \"CSP + SVM\",\n \"Tangent Space LR\",\n \"EN Grid\",\n \"CSP + LDA Grid\",\n \"Keras_EEGNet_8_2\",\n]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotting the results\nWe can plot the results using the ``codecarbon_plot`` function, generated\nbelow. This function takes the dataframe returned by the ``benchmark``\nfunction as input, and returns a pyplot figure.\nThe ``order_list`` argument is used to specify the order of the pipelines in\nthe plot.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "codecarbon_plot(results, order_list, country=\"(France)\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The result expected will be the following image, but varying depending on the\n machine and the country used to run the example.\n\n .. image:: ../images/example_codecarbon.png\n :align: center\n :alt: carbon_example\n\n##############################################################################\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.19" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/docs/_downloads/fa1ca889a5b6c6678d3af932651fcf7f/plot_cross_session_multiple_datasets.py b/docs/_downloads/fa1ca889a5b6c6678d3af932651fcf7f/plot_cross_session_multiple_datasets.py new file mode 100644 index 00000000..bcf19929 --- /dev/null +++ b/docs/_downloads/fa1ca889a5b6c6678d3af932651fcf7f/plot_cross_session_multiple_datasets.py @@ -0,0 +1,118 @@ +""" +================================== +Cross-Session on Multiple Datasets +================================== + +This example shows how to perform a cross-session analysis on two MI datasets +using a CSP+LDA pipeline + +The cross session evaluation context will evaluate performance using a leave +one session out cross-validation. For each session in the dataset, a model +is trained on every other session and performance are evaluated on the current +session. +""" + +# Authors: Sylvain Chevallier +# +# License: BSD (3-clause) + +import warnings + +import matplotlib.pyplot as plt +import seaborn as sns +from mne.decoding import CSP +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.pipeline import make_pipeline + +import moabb +from moabb.datasets import BNCI2014_001, Zhou2016 +from moabb.evaluations import CrossSessionEvaluation +from moabb.paradigms import LeftRightImagery + + +warnings.simplefilter(action="ignore", category=FutureWarning) +warnings.simplefilter(action="ignore", category=RuntimeWarning) +moabb.set_log_level("info") + +############################################################################### +# Loading Dataset +# --------------- +# +# Load 2 subjects of BNCI 2014-004 and Zhou2016 datasets, with 2 session each + +subj = [1, 2] +datasets = [Zhou2016(), BNCI2014_001()] +for d in datasets: + d.subject_list = subj + +############################################################################### +# Choose Paradigm +# --------------- +# +# We select the paradigm MI, applying a bandpass filter (8-35 Hz) on +# the data and we will keep only left- and right-hand motor imagery + +paradigm = LeftRightImagery(fmin=8, fmax=35) + +############################################################################## +# Create Pipelines +# ---------------- +# +# Use the Common Spatial Patterns with 8 components and a Linear Discriminant +# Analysis classifier. + +pipeline = {} +pipeline["CSP+LDA"] = make_pipeline(CSP(n_components=8), LDA()) + +############################################################################## +# Get Data (optional) +# ------------------- +# +# To get access to the EEG signals downloaded from the dataset, you could +# use `dataset.get_data(subjects=[subject_id])` to obtain the EEG under +# an MNE format, stored in a dictionary of sessions and runs. +# Otherwise, `paradigm.get_data(dataset=dataset, subjects=[subject_id])` +# allows to obtain the EEG data in sklearn format, the labels and the meta +# information. The data are preprocessed according to the paradigm +# requirements. + +# X_all, labels_all, meta_all = [], [], [] +# for d in datasets: +# # sessions = d.get_data(subjects=[2]) +# X, labels, meta = paradigm.get_data(dataset=d, subjects=[2]) +# X_all.append(X) +# labels_all.append(labels) +# meta_all.append(meta) + +############################################################################## +# Evaluation +# ---------- +# +# The evaluation will return a DataFrame containing a single AUC score for +# each subject / session of the dataset, and for each pipeline. + +overwrite = True # set to True if we want to overwrite cached results + +evaluation = CrossSessionEvaluation( + paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite +) +results = evaluation.process(pipeline) + +print(results.head()) + +############################################################################## +# Plot Results +# ---------------- +# +# Here we plot the results, indicating the score for each session and subject + +sns.catplot( + data=results, + x="session", + y="score", + hue="subject", + col="dataset", + kind="bar", + palette="viridis", +) +plt.show() diff --git a/docs/_downloads/fb557f4e0ac4b423b8911acc0958ae76/plot_fixed_interval_windows.py b/docs/_downloads/fb557f4e0ac4b423b8911acc0958ae76/plot_fixed_interval_windows.py new file mode 100644 index 00000000..ba9b8fae --- /dev/null +++ b/docs/_downloads/fb557f4e0ac4b423b8911acc0958ae76/plot_fixed_interval_windows.py @@ -0,0 +1,128 @@ +""" +================================= +Fixed interval windows processing +================================= + +This example shows how to process a dataset using the +:class:`moabb.paradigms.FixedIntervalWindowsProcessing` paradigm. This paradigm +creates epochs at fixed intervals, ignoring the stim +channel and events of the datasets. Therefore, it is +compatible with all the datasets. Unfortunately, +this paradigm is not compatible with the MOABB evaluation +framework. However, it can be used to process datasets +for unsupervised algorithms. + +In this example, we will use the Zhou2016 dataset because +it is relatively small and can be downloaded quickly. +""" + +# Authors: Pierre Guetschel +# +# License: BSD (3-clause) + +############################################################################### +import matplotlib.pyplot as plt +import mne +import numpy as np + +from moabb import set_log_level +from moabb.datasets import Zhou2016 +from moabb.paradigms import FixedIntervalWindowsProcessing, MotorImagery + + +set_log_level("info") + +############################################################################### +# Process a dataset +# ----------------- +# +# To process a dataset with +# :class:`moabb.paradigms.FixedIntervalWindowsProcessing` , you can use the +# method as with every other paradigm. The only additional parameters are +# ``length``, ``stride``, ``start_offset``, and ``stop_offset``. They are +# all parametrised in seconds. ``length`` is the length of the epochs, +# ``stride`` is the time between the onset of two consecutive epochs, +# ``start_offset`` is the offset between each run start and their first +# epoch, and ``stop_offset`` is the offset between each run start and their +# last epoch. The default values are ``length=5``, ``stride=10``, +# ``start_offset=0``, and ``stop_offset=None`` (i.e. end of the run). +# +# An example usage of :class:`moabb.paradigms.FixedIntervalWindowsProcessing` +# with the :class:`moabb.datasets.Zhou2016` dataset: +dataset = Zhou2016() +processing = FixedIntervalWindowsProcessing( + # new parameters: + length=100, + stride=50, + start_offset=300, + stop_offset=900, # we epoch 10 minutes per run, starting at 5 minutes (i.e. 300 seconds) + # parameters common with other paradigms: + resample=100, + fmin=7, + fmax=45, + baseline=None, + channels=None, +) +X, labels, metadata = processing.get_data(dataset=dataset, subjects=[1]) + +############################################################################### +# In this dataset, there are three sessions per subject and two runs per +# session: +for column in metadata.columns: + print(f"{column}s: {metadata[column].unique()}") + +############################################################################### +# We expect to obtained ``(stop_offset - start_offset - length) / stride``; +# i.e. :math:`(900-300-100)/50=10` epochs per run. Here we have 3*2=6 runs. +# And indeed, we obtain +# a total of :math:`6*10=60` epochs: +print(f"Number of epochs: {len(X)}") + +############################################################################### +# .. note:: +# To apply a bank of bandpass filters, you can use the +# :class:`moabb.paradigms.FilterBankFixedIntervalWindowsProcessing` +# paradigm instead. +# +# Print the events +# --------------------------------- +# +# We can print the position of the created epochs within the run next to +# the original events of the dataset. For this, we will first instantiate +# a :class:`moabb.paradigms.MotorImagery` paradigm to recover the original +# events of the dataset: +paradigm = MotorImagery( + resample=100, + fmin=7, + fmax=45, + baseline=None, + channels=None, +) + +############################################################################### +# Then, we can recover the events of both paradigms using the +# ``_get_events_pipeline`` method: +events_pipeline_dataset = paradigm._get_events_pipeline(dataset) +events_pipeline_fixed = processing._get_events_pipeline(dataset) +raw = dataset.get_data(subjects=[1])[1]["0"]["0"] +events_dataset = events_pipeline_dataset.transform(raw) +events_fixed = events_pipeline_fixed.transform(raw) +events = np.concatenate([events_dataset, events_fixed]) +event_id = dict(**paradigm.used_events(dataset), **processing.used_events(dataset)) + +############################################################################### +# Finally, we can plot the events. The artificial events created by +# :class:`moabb.paradigms.FixedIntervalWindowsProcessing` are named +# ``"Windows"``: +fig = mne.viz.plot_events( + events, + sfreq=raw.info["sfreq"], + event_id=event_id, +) +fig.subplots_adjust(right=0.7) +plt.show() + +############################################################################### +# We can see that the epochs were effectively created at a fixed interval +# every 50 seconds between 300 and 900 seconds, and ignoring +# the original events of the dataset. diff --git a/docs/_downloads/fc103af82bd37a6a36f57f863e9fd4aa/plot_statistical_analysis.py b/docs/_downloads/fc103af82bd37a6a36f57f863e9fd4aa/plot_statistical_analysis.py new file mode 100644 index 00000000..4b41d6b8 --- /dev/null +++ b/docs/_downloads/fc103af82bd37a6a36f57f863e9fd4aa/plot_statistical_analysis.py @@ -0,0 +1,138 @@ +""" +======================= +Statistical Analysis +======================= + +The MOABB codebase comes with convenience plotting utilities and some +statistical testing. This tutorial focuses on what those exactly are and how +they can be used. + +""" + +# Authors: Vinay Jayaram +# +# License: BSD (3-clause) +# sphinx_gallery_thumbnail_number = -2 + +import matplotlib.pyplot as plt +from mne.decoding import CSP +from pyriemann.estimation import Covariances +from pyriemann.tangentspace import TangentSpace +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.linear_model import LogisticRegression +from sklearn.pipeline import make_pipeline + +import moabb +import moabb.analysis.plotting as moabb_plt +from moabb.analysis.meta_analysis import ( # noqa: E501 + compute_dataset_statistics, + find_significant_differences, +) +from moabb.datasets import BNCI2014_001 +from moabb.evaluations import CrossSessionEvaluation +from moabb.paradigms import LeftRightImagery + + +moabb.set_log_level("info") + +print(__doc__) + +############################################################################### +# Results Generation +# --------------------- +# +# First we need to set up a paradigm, dataset list, and some pipelines to +# test. This is explored more in the examples -- we choose left vs right +# imagery paradigm with a single bandpass. There is only one dataset here but +# any number can be added without changing this workflow. +# +# Create Pipelines +# ---------------- +# +# Pipelines must be a dict of sklearn pipeline transformer. +# +# The CSP implementation from MNE is used. We selected 8 CSP components, as +# usually done in the literature. +# +# The Riemannian geometry pipeline consists in covariance estimation, tangent +# space mapping and finally a logistic regression for the classification. + +pipelines = {} + +pipelines["CSP+LDA"] = make_pipeline(CSP(n_components=8), LDA()) + +pipelines["RG+LR"] = make_pipeline(Covariances(), TangentSpace(), LogisticRegression()) + +pipelines["CSP+LR"] = make_pipeline(CSP(n_components=8), LogisticRegression()) + +pipelines["RG+LDA"] = make_pipeline(Covariances(), TangentSpace(), LDA()) + +############################################################################## +# Evaluation +# ---------- +# +# We define the paradigm (LeftRightImagery) and the dataset (BNCI2014_001). +# The evaluation will return a DataFrame containing a single AUC score for +# each subject / session of the dataset, and for each pipeline. +# +# Results are saved into the database, so that if you add a new pipeline, it +# will not run again the evaluation unless a parameter has changed. Results can +# be overwritten if necessary. + +paradigm = LeftRightImagery() +dataset = BNCI2014_001() +dataset.subject_list = dataset.subject_list[:4] +datasets = [dataset] +overwrite = True # set to False if we want to use cached results +evaluation = CrossSessionEvaluation( + paradigm=paradigm, datasets=datasets, suffix="stats", overwrite=overwrite +) + +results = evaluation.process(pipelines) + +############################################################################## +# MOABB Plotting +# ---------------- +# +# Here we plot the results using some of the convenience methods within the +# toolkit. The score_plot visualizes all the data with one score per subject +# for every dataset and pipeline. + +fig = moabb_plt.score_plot(results) +plt.show() + +############################################################################### +# For a comparison of two algorithms, there is the paired_plot, which plots +# performance in one versus the performance in the other over all chosen +# datasets. Note that there is only one score per subject, regardless of the +# number of sessions. + +fig = moabb_plt.paired_plot(results, "CSP+LDA", "RG+LDA") +plt.show() + +############################################################################### +# Statistical Testing and Further Plots +# ---------------------------------------- +# +# If the statistical significance of results is of interest, the method +# compute_dataset_statistics allows one to show a meta-analysis style plot as +# well. For an overview of how all algorithms perform in comparison with each +# other, the method find_significant_differences and the summary_plot are +# possible. + +stats = compute_dataset_statistics(results) +P, T = find_significant_differences(stats) + +############################################################################### +# The meta-analysis style plot shows the standardized mean difference within +# each tested dataset for the two algorithms in question, in addition to a +# meta-effect and significance both per-dataset and overall. +fig = moabb_plt.meta_analysis_plot(stats, "CSP+LDA", "RG+LDA") +plt.show() + +############################################################################### +# The summary plot shows the effect and significance related to the hypothesis +# that the algorithm on the y-axis significantly outperformed the algorithm on +# the x-axis over all datasets +moabb_plt.summary_plot(P, T) +plt.show() diff --git a/docs/_downloads/fe7c33d68ac9fa4d60c0efbc341f93f3/tutorial_3_benchmarking_multiple_pipelines.py b/docs/_downloads/fe7c33d68ac9fa4d60c0efbc341f93f3/tutorial_3_benchmarking_multiple_pipelines.py new file mode 100644 index 00000000..dcb84ff4 --- /dev/null +++ b/docs/_downloads/fe7c33d68ac9fa4d60c0efbc341f93f3/tutorial_3_benchmarking_multiple_pipelines.py @@ -0,0 +1,93 @@ +""" +=========================================== +Tutorial 3: Benchmarking multiple pipelines +=========================================== + +In this last part, we extend the previous example by assessing the +classification score of not one but three classification pipelines. +""" + +# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier +# +# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019 + +import warnings + +import matplotlib.pyplot as plt +import mne +import seaborn as sns +from mne.decoding import CSP +from pyriemann.classification import MDM +from pyriemann.estimation import Covariances +from pyriemann.tangentspace import TangentSpace +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from sklearn.pipeline import make_pipeline +from sklearn.svm import SVC + +import moabb +from moabb.datasets import BNCI2014_001, Zhou2016 +from moabb.evaluations import WithinSessionEvaluation +from moabb.paradigms import LeftRightImagery + + +mne.set_log_level("CRITICAL") +moabb.set_log_level("info") +warnings.filterwarnings("ignore") + +############################################################################## +# Creating Pipelines +# ------------------ +# +# We instantiate the three different classiciation pipelines to be considered +# in the analysis. The object that gathers each pipeline is a dictionary. The +# first pipeline is the CSP+LDA that we have seen in the previous parts. The +# other two pipelines rely on Riemannian geometry, using an SVM classification +# in the tangent space of the covariance matrices estimated from the EEG or a +# MDM classifier that works directly on covariance matrices. + +pipelines = {} +pipelines["csp+lda"] = make_pipeline(CSP(n_components=8), LDA()) +pipelines["tgsp+svm"] = make_pipeline( + Covariances("oas"), TangentSpace(metric="riemann"), SVC(kernel="linear") +) +pipelines["MDM"] = make_pipeline(Covariances("oas"), MDM(metric="riemann")) + +############################################################################## +# The following lines go exactly as in the previous tutorial, where we end up +# obtaining a pandas dataframe containing the results of the evaluation. +datasets = [BNCI2014_001(), Zhou2016()] +subj = [1, 2, 3] +for d in datasets: + d.subject_list = subj +paradigm = LeftRightImagery() +evaluation = WithinSessionEvaluation( + paradigm=paradigm, datasets=datasets, overwrite=False +) +results = evaluation.process(pipelines) + +############################################################################## +# As `overwrite` is set to False, the results from the previous tutorial are reused and +# only the new pipelines are evaluated. The results from "csp+lda" are not recomputed. +# The results are saved in ~/mne_data/results if the parameter `hdf5_path` is not set. + +############################################################################## +# Plotting Results +# ---------------- +# +# The following plot shows a comparison of the three classification pipelines +# for each subject of each dataset. + +results["subj"] = [str(resi).zfill(2) for resi in results["subject"]] +g = sns.catplot( + kind="bar", + x="score", + y="subj", + hue="pipeline", + col="dataset", + height=12, + aspect=0.5, + data=results, + orient="h", + palette="viridis", +) +plt.show() diff --git a/docs/_images/architecture.png b/docs/_images/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..7bbaf1217dc5522f5f78c0e85c787bf3080a79d6 GIT binary patch literal 159821 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

~A=^`qyS=f*!8_(+$T})dhkSpE$KqD|?!;(; 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≪RyH3e>`<*%rE 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 I;rZad0GNn;a{vGU literal 0 HcmV?d00001 diff --git a/docs/_images/example_codecarbon.png b/docs/_images/example_codecarbon.png new file mode 100644 index 0000000000000000000000000000000000000000..5febc6d4c8668086d2ff8cd3719c0e0e35af0420 GIT binary patch literal 35627 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 CuO#3A literal 0 HcmV?d00001 diff --git a/docs/_images/moabb_install.png b/docs/_images/moabb_install.png new file mode 100644 index 0000000000000000000000000000000000000000..fabea0e15406c0d11663e2fa72ae6e14e22df91c GIT binary patch literal 59980 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

B?LBm5ERJc9*C+3XxZibT3Jc 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_changing_download_directory_thumb.png b/docs/_images/sphx_glr_changing_download_directory_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbcfce4c3363b2114a3e00c070917d972c5e269 GIT binary patch literal 10252 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_example_codecarbon_thumb.png b/docs/_images/sphx_glr_example_codecarbon_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbcfce4c3363b2114a3e00c070917d972c5e269 GIT binary patch literal 10252 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_load_model_thumb.png b/docs/_images/sphx_glr_load_model_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbcfce4c3363b2114a3e00c070917d972c5e269 GIT binary patch literal 10252 zcmeHtXHZi?-*4!lM^Hd|2c<|Aq)3a>1w@)i2~|Lkk46jA=qup7~|&F8HTCn+UysfSa$F+;eb;B(===LJjnZZ!+GLV$R~- z)}eEhu%*k=kwjA!hvK4O|&T5#F> z@#gT7NK4uZi;?}|&m8m>rLWz-W#Y1rDemyerP27dLyyvL>{^5lzn{e1;^fZPrYAy1 zM<5dRpyLE@zCVpsY_T}w&{6LW?{(n{G->Bpd#1Mn-%r!9|gSlp#D7@2c zLLlD=?(iWY5KuxCb?qRMxf3}{M}#b<26I7T1*-O!1T;SX8u6}JkmpwQYZv!EP=W&Br}#4D$L-hu%JcfJ4oB>gu)a_U;-T*M&q8BFqn_yiF0 zM+wgjxHnaT0yi>bwK2NMsh;j2|5Fw=sYIqRp zQvV4G!bSWG9Ujaf&%#52s3KE^J|xx1)@;1*W0ccAYI=)1GM$m&y|?T5j3&s^9eJn% z1rhP?zf|S4F^y(s=!hhl*&`rKL(^Dzw2<7G`1cP_3DHR&T+3QBdt+PNh8*1ae-CTl z|G!<`q9d5$JSXF#Ab+dj0oEL#(TqPH_SfId3ZW!VR3FZ}36eACdPx`9>?Lm-0x<}W z>n=Oojc3S{GKk8Bt#>bcM?#;~9azz?FZJu+_>@GI=+gz_$|vPxV)qj4f{Kqi$e=p*sYK&eJ9U&bEdSM(cYDJY0$ioZFx1`m!n>6!2 zZb&Jv1fRK9_EbVHV&Q?1AtBgCh^nFr5^oap<8vbfm~v^V>Ua%Cq&Gd+ zLP+e1JMt+yJR#^1UjpXJbt3!-X?rB)?AllM!N&mg%6Q{RM1Alc+b%onhR|I>{eT=H zzU|DL&SQ7#6Z}2txw!Jk6B*%Lq#Bs5Tf%MbJ;R|q7T{2yxOggZ?^;!msM{~$M2)=s zQf8F_==XPJVBOs6YUV>fIyy!ZAq$z2LPG;{qY7QkJLYWf4LUoL+^+Pq-}2;c`5!Lk zQ^rKQahGT8THGS!{Ilz}C7DpiSpFyKvc^Xo{-VKwh@rxdEE25}tzg#572+oxI_H3i zHZRf*1&MC^auRS3U+a`u#`9S4va*QUWp}mUuACv@t@THE^g}*>lRQ0oB3{})h4Pi| zI0fxH%Z+q#*slht*#u&53zwR_@&Ogh;-Fn)tiS1SbLrq`)IU5YSN^>k?B0Qu0(1TO zqT+1ge>z8)Fje8rZc?!;4)E>llPHP=h1=2p0G|5)3h=`n`HyMwE@jm4oXHKDZ&6z{ z(^S*?XF2QA(x1QCTkU)in)lG0*O(5KZpA)7m;b7iHSDf91t$P~ob=v!aIyF;sd{Fr z*7&4`rK$F0c4)7EFx}{>s+8xDt6A%g=OGonRn$2*6DM0{65ThrIPZJS)*Buc}>0)%rBkuGt zw@txlqyZC(`zFOC!lE|OrL1QR&R6Q|?{ z0`Zz#Y_4u*4Ec#wR@q4yC+Fw%Q$mGM?sTZDMS1t}V32WJwLSzje&LJ8p0{Su1hMKw zHG0s%;QBL4zg5APC+QnsUd}XuiJNUF$7)g5oFT#2lLcuCuvay{^QbqqNy^;mUG#ca zqO& zS9U}y6nNv_LZh|y;&&#=K*6FHlI-0JO=mf&7dT_uv)|3`*tmt$t>9}?U>wABiE3R7 zs&YX}=TVim^FLq}*Dtt;*IQetS`mBpX+@(ebF3C)5EOKz0AWJ4?R$$K#SyM)tKKd( zMESk7{FQC1-30UHg*!e(Lv{zZ^Rd8*nIiwj(dOi>@C#h`C(i(GZGo+c zZrKA818ttcIkL##;j=`z+_rpP1(x^ORnc{&LMM%U9hBULp1f&8zacyLIg7hdMYy?8 z!&Em^Pe6;2VKlKE9phLxaQ$7qZ(i*zjk#D-13-j!z*{b&&g6TzCr{L!H`gIWgsM=9DPZwjj;${xS$2e;>!2e zf8RHCl1HUtOp%6#_JVh#J0x_8g)3PHzH)vo+JJmYf_!X?i^nZ%$6ph%Uo7i=aa(2J zedYsKy07^;}>VPB*Jjp5W86LLR8U=It` zTTvzqq9^@Wzs?ml1|p;=Cm#fCDr;^T%4lU3Z6~pItn=K@WUCSLqPtx$ZUt4B%0ox< zZ6)q}{vZ|GXj)}Q!hYW4Tje!GiVRml5)y#960|-iYVZReE-DwTp_Zpv` zdVHcBkTNiZbeBjLo}R?xNtCYQtqSt1``tI6Gjq>?lAqcvL}h$&#B(9TR5UVKW~+rM z5wz?bk-Fyhm_%Jfg6pXWpVN14$E|W^YjCEYu_O8QAu+j)qLKSomyFZZZ&H<-$E&?E zvLU{#WHC^}zGwYqIiUPy2wepr6rtfKP&bN zPt*jI?Zvk zQniOu2c5LEs>5I^u`H*rij$3=S+}p;@?a%vM0eJ@%Eo1Ek!%&m^nUS}xjQfS=5C|U z-u%k`MIf+VK!HI&chh78h+lmU3Kw2d^eY!-=#4RStlH}wn*M^|pi+xUqRX=e*{>!0 zt>A{2d|NNgV%byHa>2T~=x=JHvaj0m~i$0k&#L%(J;aoR~)xfGLwhbWJ=B+NgEUAUmJX@7s~ zn%Gr)o!CpD#Kip+q;xfmf9zULlV=S@VJENV-^}T}<4~kq&YUoApkaR) z<~tb_qBMkHL(sCS^6peTy?a-P>K^b6V+0<$Xpe?w>M23F7aZ@991L*yBC73WRIVbSsdTN#%IgM z2;ff@va@ic!UITbV>D82y53$sE=wUI$mFD??rCY>pBHz;ZTr8ac@1?r49I)!5C>gF zIUfEA>&BoWlEkR#<#9XR7@{aK=V{23Pre}5j{E@RL1Y|jZ=aMZthvQY`o8-ji3mLe z)#oaf9Ry?V7b>%6BK?%)!P*8ooV(yBl~$iCdY%#bPOkq7VCNy8#}^MjJfq%nQ} zhQ&$%u;U+%L^yvOw=F*36FJzcB)ssJS*jI zrMpuYJl`ApmocwalypqWfF%|-en6+gti%lRSlpQdGz@3*6CS3o9<|M^?!uOP3*QQk z)l5Z_o771`(DnGQGMR!mXoyD|3=P&NTusREACMtRYTSHbp`49ygPe;zZAv0!AR*>= z1&k@}HJ0jVe~zr=8O6tUdnE)Hp}!&fQYwR)F2gNFjMZfZ6vK4 zx8(R}?%+m+X$yN)d=6A>Nw;Hia?)lN{=oyEDet9PdiLdbC(FMU&7(!S+J3R#A=Yw6 zpzB9TV*I_1!2VWpP&fkijaSN|7f=*melJLaqtvQ)r8q<70Xdz$(4?Xj15+cl`O|e6 z-Ms=L?r0Zd5Vi~jR#>j%w#OI6#J^EhUM2zLT>8eAp}KQEZBkS(KSug-hqe=4*jl%i zNi1rXQMgn!&wJ@*i*}=1E&%;{VBBUgTE@gjbZ#*Y|5X@Hpt^BGIKA9f@5pkmhTeZqDx|6CAWP8f1K)|cij zmyZ?N|D&U}xCO)wDpG5CnomjfxH$8X!q);%a(y8$A|4&vMZI}7*KSewv(3f*Ugs9j zQC<4AMy8GoN{-Hc;bidox7ch1tvAhct!+nj}6Cf6&L^N5WK z&=M}}qY%Czt0|E!&iUn!fm&DAhe3n`7>n3r4!2McB-Z~kp@R3~3k45cmaD{uS}G|i z*g{#E(^a0yQUYA#mKmnhd`clahD2jc&oHE~X1-H?5QrkuUS*CIIvPB;+}pJefzEo0*)4&f++6M&B+jqN8=Agolb(dbn1bRt zT|axSj631s4e&Ke zxveAnitLNu8gt+^dXCe4g!0EP34%Ypsg|9Rf7fLKb{c^MNq`O*&_sQ3Xh;N%FWdv? zDzh5e#6<*v zg@lfH6h-{`TiLEyZpx+3`2MCI^zq@tv~ItLe*0r>I7&y4?tlsA|z*K+yEqGrx`6ZzXdVHj8UCWzEwE2|USZ2Nsi! zUmqti5dp9k=qj5VWF-d+^Gb_IX%{_ZBB_{{IL=1j|Lx;x=cF1t*kDIOic8Tdv$ZgX z`@E%*nkR3PC!{fUK|eEdo({234PVDB>XGrUjjtp&+ zm3w>NiFl$?mb#}HR}Kz8Y`%CF0_Bcz%aR9}YcC9qt&n?GslCDNedjLJ>=B>T5Hin2 z*6)-F=x|5g$RkvlBg;sqdOQLlO-N9G@Z^)o-sHq$;vPNWKXY(CWDeUTmC|kVWF7o| z#(%UmLEjdk_h|6`N68|~sKbKC)3EJ}^mCDY>Nu!fVvi zHSQcPR4Rp;1IT43_of}UtHoIIjQN(4^mL;wBZIJ6C~fVla3oaFnk&oaplnewJoHUv zM|nn3HQ6r$G38>X^v8$V0MN=X+*60cMF1=LB>N%C-(B>v6kYoOpyCCYK)jGxzJs#| zbp>`y%E8%rXWY#_P3lwV&4n_7C)p3MY;11n(=EYDaXAVoHw(F`jIZvfouCAuy74}5 zc7h{a=Ax0R^`*nN7@Gx>pV)SPgv-7ux|!%fj3y3Kp)7(~pKX7`ywD{&P5^bZb5c+i zT$hTENqOvaX_h~4Vh19Luf>e--{f11F&zXmkCoMvMbh3zBHVH!tR9{r6prTy0O*SZ z=v8N>Pf0P}h5y}QDzVJ5;w@-FG_)gH>afwWTT!gpj&mL3BN=q|+tBa4d&*i~)Z0*9 z*OkpOU{&Nr@DMSy6DGRRGAOQGtcf`@X#yfu)hYQ>-Lu$|}e^j6tTAV%P9A5+Y_3!P4n$A&v< zvwAipJ|ROwV4GDEdL-jg)aWGB#%;yGy*P7EqkYSvNkvJLH9bs|ZuwHbr6Z^H@@VTh zx6j^8l#$D#x>P>TOS9?k2-=e!CFE#ll+=t6M78bb&XGG>ft-_-V&zNa!*><(zP79D zyWnjCrpCB`6B75Gs6Jq@*rD=+sB0$lGruM|m@5w}_t3Yu0;o6BA(XJ)8dT^wP<6TR z4NNSI|2l6r=H9lstagP_k7YR@#Jc4?ppGChn6CBBHk7^D(M;lQ`?r>DL~4j*)~WAp z{`~8#yJcmEmu2qx&DH%GdZ9SGE+E8OEq!QmTIpL@H*7mGOD%iacO$q2jr*<|_rqpDEu?XEy=6lgCf)iH;I`bpRUtzQzy4I{4`L zormFoH(lAY@SG~&0+SLRvws~AyxpO+UXrdJd4FGt${R<^|O?SGF7v2Txr3-#$WU~70k#URosdfD{cK@l*s*=y_3A>70k3NE_<);6w9l+>m7T~J`7Ohv0YnURDM47A#QV`Gug z$wq3fHg}TL2&F%tRX!KW4{`WN8eU%LU6Z#U7%pOU zxv(5&?-!J~3b8oTY{ahaWo^O-d@C&=5A~{$IF+3m0!zQId-Ra z_0k+^OQ@n$``0q9EKd%!EynaM3}bhjaLQ9H2mPWVwdF+{=9_=oKzR;p_n#I-(slz} z)0?v~L?%ICGk0Ik_io2R-O!P-j6F+_@%^}&9;d;ByweOaj<(k8DZB%7Am>dAo1u%0 zgVe=S(Vzoda4ay}cvxvB5bh~;Hd-s*TV|K*TN?+TQ>~)-iFGD}h@NxB!3Fe;tSmqm=+SCI{QxqWPIgdy9rateR{1eVX$&mfGo_;nTD*51f^@;r2!r5iNyoTE8@4iw< zWe_$;3|qwFu`x6zUW_-2e#}!P!E&_{L;NH)1$NaVl2+#-e!{MR)DYa^xMGj(9<8Y- zyIvz(d_26j02q32-M{$nu)pfl^~XF&H7<8cf%J}D$M34U6O*kG3l(*zf;cD6%deI7#&sRt`Eb~u5zB>C-sn(O5Zj15Z=vm$ z097V#|0)41`R%xbBmoYHZnH5Gz!eWcVtLoqWB{^8e;L*1n}`SC?mp(d8MZ1bC{o!r zx+>ra*zZVKt{C(2{yXfpjo|HRS|$8-oyYOC0kE0Tcwh{-->}X`zzLo@u@DFW$|7`y zeZgY@WoT{YP_`k&YQp`}3}B6l>8djxylh&H{VhNLcJtHaMZ86UcGkDS#~q7GGPL(v z4}HSb992QJtGSIu42}ar2|7g(6!I!&&yPDMOoKT7dV&#VmZDTXVa-HNU@>;U(fWpY z)Po7_&7$yN25tdtxh%c%CwW?ugfF(%rH}4@zd2t5ro|u_-%{ky|1aY2uBNtVt3DX2 ze2C0Iw~`VPCVGGk(OJdw7eA8cHgEdwN9J6v+HU&VyI(G!nRpa66OQVGi|li2jF8Xd zP@TO`mX?+at}mo?!=0D~?+PDnNIPR~AcXbs^Jjrr7ptDMOuqIXqS$)37MgMa``kUap$A|G&!NgiXboPzRc>0tzLsqCZ!aMf zl%IG&lC#{1xxoSGEmcsbHtA~K@NoA|#^*ejji1N-;Vo@{F}PWCZ39Mm-&dM2skdfh zMcmBP7YL5$Q=9?u6T1sF0&W@N)QDi5I_MxS{DD6yB|~MGm6BiZ&u@suShUmi-Op8{ zgB+uS$lBHV;@IwlC!b+Vr2HtBh+d8}ZJivsnG6j^MmNjB6S<>IYjTz$omxlZz?ryM zQ{l*Gvyp(E3YdQxxGF>o>q+Xnb{t!aCs2(Rpf4_|2zQ;+;C&k1O^2dU%3N%dIof9i z(A0T*J3(t^M4Gx5+vdq^HJa2!WikZ^QYg|+EmGJN=F0Tzt6P)qvtfF1*~)M@wa4C| z3J7zi1Nc4I_(*%b>p68=!0yE6OaY=LAcuo{&Ue2%tXn8SgTG}NZAvwz_c2;?6`Rvo z)*jh z;||zS(;td`@O4Jf$}G9cj(ZIxd51&Fl zt_jntS#GEo9;1I7HIZlkb7<8MPpiAv?zDr$l+wLEL5fLjZ|PeR1N+d$yWYj1WiwMK s^b-;|TLIMqPU8H}<^Opce&dOp9|<@u?f9htr~E*gkDfr$s@7ru1?OT?VgLXD literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_noplot_bids_conversion_thumb.png b/docs/_images/sphx_glr_noplot_bids_conversion_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbcfce4c3363b2114a3e00c070917d972c5e269 GIT binary patch literal 10252 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_noplot_phmd_ml_spectrum_thumb.png b/docs/_images/sphx_glr_noplot_phmd_ml_spectrum_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbcfce4c3363b2114a3e00c070917d972c5e269 GIT binary patch literal 10252 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_noplot_tutorial_5_build_a_custom_dataset_thumb.png b/docs/_images/sphx_glr_noplot_tutorial_5_build_a_custom_dataset_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbcfce4c3363b2114a3e00c070917d972c5e269 GIT binary patch literal 10252 zcmeHtXHZi?-*4!lM^Hd|2c<|Aq)3a>1w@)i2~|Lkk46jA=qup7~|&F8HTCn+UysfSa$F+;eb;B(===LJjnZZ!+GLV$R~- z)}eEhu%*k=kwjA!hvK4O|&T5#F> z@#gT7NK4uZi;?}|&m8m>rLWz-W#Y1rDemyerP27dLyyvL>{^5lzn{e1;^fZPrYAy1 zM<5dRpyLE@zCVpsY_T}w&{6LW?{(n{G->Bpd#1Mn-%r!9|gSlp#D7@2c zLLlD=?(iWY5KuxCb?qRMxf3}{M}#b<26I7T1*-O!1T;SX8u6}JkmpwQYZv!EP=W&Br}#4D$L-hu%JcfJ4oB>gu)a_U;-T*M&q8BFqn_yiF0 zM+wgjxHnaT0yi>bwK2NMsh;j2|5Fw=sYIqRp zQvV4G!bSWG9Ujaf&%#52s3KE^J|xx1)@;1*W0ccAYI=)1GM$m&y|?T5j3&s^9eJn% z1rhP?zf|S4F^y(s=!hhl*&`rKL(^Dzw2<7G`1cP_3DHR&T+3QBdt+PNh8*1ae-CTl z|G!<`q9d5$JSXF#Ab+dj0oEL#(TqPH_SfId3ZW!VR3FZ}36eACdPx`9>?Lm-0x<}W z>n=Oojc3S{GKk8Bt#>bcM?#;~9azz?FZJu+_>@GI=+gz_$|vPxV)qj4f{Kqi$e=p*sYK&eJ9U&bEdSM(cYDJY0$ioZFx1`m!n>6!2 zZb&Jv1fRK9_EbVHV&Q?1AtBgCh^nFr5^oap<8vbfm~v^V>Ua%Cq&Gd+ zLP+e1JMt+yJR#^1UjpXJbt3!-X?rB)?AllM!N&mg%6Q{RM1Alc+b%onhR|I>{eT=H zzU|DL&SQ7#6Z}2txw!Jk6B*%Lq#Bs5Tf%MbJ;R|q7T{2yxOggZ?^;!msM{~$M2)=s zQf8F_==XPJVBOs6YUV>fIyy!ZAq$z2LPG;{qY7QkJLYWf4LUoL+^+Pq-}2;c`5!Lk zQ^rKQahGT8THGS!{Ilz}C7DpiSpFyKvc^Xo{-VKwh@rxdEE25}tzg#572+oxI_H3i zHZRf*1&MC^auRS3U+a`u#`9S4va*QUWp}mUuACv@t@THE^g}*>lRQ0oB3{})h4Pi| zI0fxH%Z+q#*slht*#u&53zwR_@&Ogh;-Fn)tiS1SbLrq`)IU5YSN^>k?B0Qu0(1TO zqT+1ge>z8)Fje8rZc?!;4)E>llPHP=h1=2p0G|5)3h=`n`HyMwE@jm4oXHKDZ&6z{ z(^S*?XF2QA(x1QCTkU)in)lG0*O(5KZpA)7m;b7iHSDf91t$P~ob=v!aIyF;sd{Fr z*7&4`rK$F0c4)7EFx}{>s+8xDt6A%g=OGonRn$2*6DM0{65ThrIPZJS)*Buc}>0)%rBkuGt zw@txlqyZC(`zFOC!lE|OrL1QR&R6Q|?{ z0`Zz#Y_4u*4Ec#wR@q4yC+Fw%Q$mGM?sTZDMS1t}V32WJwLSzje&LJ8p0{Su1hMKw zHG0s%;QBL4zg5APC+QnsUd}XuiJNUF$7)g5oFT#2lLcuCuvay{^QbqqNy^;mUG#ca zqO& zS9U}y6nNv_LZh|y;&&#=K*6FHlI-0JO=mf&7dT_uv)|3`*tmt$t>9}?U>wABiE3R7 zs&YX}=TVim^FLq}*Dtt;*IQetS`mBpX+@(ebF3C)5EOKz0AWJ4?R$$K#SyM)tKKd( zMESk7{FQC1-30UHg*!e(Lv{zZ^Rd8*nIiwj(dOi>@C#h`C(i(GZGo+c zZrKA818ttcIkL##;j=`z+_rpP1(x^ORnc{&LMM%U9hBULp1f&8zacyLIg7hdMYy?8 z!&Em^Pe6;2VKlKE9phLxaQ$7qZ(i*zjk#D-13-j!z*{b&&g6TzCr{L!H`gIWgsM=9DPZwjj;${xS$2e;>!2e zf8RHCl1HUtOp%6#_JVh#J0x_8g)3PHzH)vo+JJmYf_!X?i^nZ%$6ph%Uo7i=aa(2J zedYsKy07^;}>VPB*Jjp5W86LLR8U=It` zTTvzqq9^@Wzs?ml1|p;=Cm#fCDr;^T%4lU3Z6~pItn=K@WUCSLqPtx$ZUt4B%0ox< zZ6)q}{vZ|GXj)}Q!hYW4Tje!GiVRml5)y#960|-iYVZReE-DwTp_Zpv` zdVHcBkTNiZbeBjLo}R?xNtCYQtqSt1``tI6Gjq>?lAqcvL}h$&#B(9TR5UVKW~+rM z5wz?bk-Fyhm_%Jfg6pXWpVN14$E|W^YjCEYu_O8QAu+j)qLKSomyFZZZ&H<-$E&?E zvLU{#WHC^}zGwYqIiUPy2wepr6rtfKP&bN zPt*jI?Zvk zQniOu2c5LEs>5I^u`H*rij$3=S+}p;@?a%vM0eJ@%Eo1Ek!%&m^nUS}xjQfS=5C|U z-u%k`MIf+VK!HI&chh78h+lmU3Kw2d^eY!-=#4RStlH}wn*M^|pi+xUqRX=e*{>!0 zt>A{2d|NNgV%byHa>2T~=x=JHvaj0m~i$0k&#L%(J;aoR~)xfGLwhbWJ=B+NgEUAUmJX@7s~ zn%Gr)o!CpD#Kip+q;xfmf9zULlV=S@VJENV-^}T}<4~kq&YUoApkaR) z<~tb_qBMkHL(sCS^6peTy?a-P>K^b6V+0<$Xpe?w>M23F7aZ@991L*yBC73WRIVbSsdTN#%IgM z2;ff@va@ic!UITbV>D82y53$sE=wUI$mFD??rCY>pBHz;ZTr8ac@1?r49I)!5C>gF zIUfEA>&BoWlEkR#<#9XR7@{aK=V{23Pre}5j{E@RL1Y|jZ=aMZthvQY`o8-ji3mLe z)#oaf9Ry?V7b>%6BK?%)!P*8ooV(yBl~$iCdY%#bPOkq7VCNy8#}^MjJfq%nQ} zhQ&$%u;U+%L^yvOw=F*36FJzcB)ssJS*jI zrMpuYJl`ApmocwalypqWfF%|-en6+gti%lRSlpQdGz@3*6CS3o9<|M^?!uOP3*QQk z)l5Z_o771`(DnGQGMR!mXoyD|3=P&NTusREACMtRYTSHbp`49ygPe;zZAv0!AR*>= z1&k@}HJ0jVe~zr=8O6tUdnE)Hp}!&fQYwR)F2gNFjMZfZ6vK4 zx8(R}?%+m+X$yN)d=6A>Nw;Hia?)lN{=oyEDet9PdiLdbC(FMU&7(!S+J3R#A=Yw6 zpzB9TV*I_1!2VWpP&fkijaSN|7f=*melJLaqtvQ)r8q<70Xdz$(4?Xj15+cl`O|e6 z-Ms=L?r0Zd5Vi~jR#>j%w#OI6#J^EhUM2zLT>8eAp}KQEZBkS(KSug-hqe=4*jl%i zNi1rXQMgn!&wJ@*i*}=1E&%;{VBBUgTE@gjbZ#*Y|5X@Hpt^BGIKA9f@5pkmhTeZqDx|6CAWP8f1K)|cij zmyZ?N|D&U}xCO)wDpG5CnomjfxH$8X!q);%a(y8$A|4&vMZI}7*KSewv(3f*Ugs9j zQC<4AMy8GoN{-Hc;bidox7ch1tvAhct!+nj}6Cf6&L^N5WK z&=M}}qY%Czt0|E!&iUn!fm&DAhe3n`7>n3r4!2McB-Z~kp@R3~3k45cmaD{uS}G|i z*g{#E(^a0yQUYA#mKmnhd`clahD2jc&oHE~X1-H?5QrkuUS*CIIvPB;+}pJefzEo0*)4&f++6M&B+jqN8=Agolb(dbn1bRt zT|axSj631s4e&Ke zxveAnitLNu8gt+^dXCe4g!0EP34%Ypsg|9Rf7fLKb{c^MNq`O*&_sQ3Xh;N%FWdv? zDzh5e#6<*v zg@lfH6h-{`TiLEyZpx+3`2MCI^zq@tv~ItLe*0r>I7&y4?tlsA|z*K+yEqGrx`6ZzXdVHj8UCWzEwE2|USZ2Nsi! zUmqti5dp9k=qj5VWF-d+^Gb_IX%{_ZBB_{{IL=1j|Lx;x=cF1t*kDIOic8Tdv$ZgX z`@E%*nkR3PC!{fUK|eEdo({234PVDB>XGrUjjtp&+ zm3w>NiFl$?mb#}HR}Kz8Y`%CF0_Bcz%aR9}YcC9qt&n?GslCDNedjLJ>=B>T5Hin2 z*6)-F=x|5g$RkvlBg;sqdOQLlO-N9G@Z^)o-sHq$;vPNWKXY(CWDeUTmC|kVWF7o| z#(%UmLEjdk_h|6`N68|~sKbKC)3EJ}^mCDY>Nu!fVvi zHSQcPR4Rp;1IT43_of}UtHoIIjQN(4^mL;wBZIJ6C~fVla3oaFnk&oaplnewJoHUv zM|nn3HQ6r$G38>X^v8$V0MN=X+*60cMF1=LB>N%C-(B>v6kYoOpyCCYK)jGxzJs#| zbp>`y%E8%rXWY#_P3lwV&4n_7C)p3MY;11n(=EYDaXAVoHw(F`jIZvfouCAuy74}5 zc7h{a=Ax0R^`*nN7@Gx>pV)SPgv-7ux|!%fj3y3Kp)7(~pKX7`ywD{&P5^bZb5c+i zT$hTENqOvaX_h~4Vh19Luf>e--{f11F&zXmkCoMvMbh3zBHVH!tR9{r6prTy0O*SZ z=v8N>Pf0P}h5y}QDzVJ5;w@-FG_)gH>afwWTT!gpj&mL3BN=q|+tBa4d&*i~)Z0*9 z*OkpOU{&Nr@DMSy6DGRRGAOQGtcf`@X#yfu)hYQ>-Lu$|}e^j6tTAV%P9A5+Y_3!P4n$A&v< zvwAipJ|ROwV4GDEdL-jg)aWGB#%;yGy*P7EqkYSvNkvJLH9bs|ZuwHbr6Z^H@@VTh zx6j^8l#$D#x>P>TOS9?k2-=e!CFE#ll+=t6M78bb&XGG>ft-_-V&zNa!*><(zP79D zyWnjCrpCB`6B75Gs6Jq@*rD=+sB0$lGruM|m@5w}_t3Yu0;o6BA(XJ)8dT^wP<6TR z4NNSI|2l6r=H9lstagP_k7YR@#Jc4?ppGChn6CBBHk7^D(M;lQ`?r>DL~4j*)~WAp z{`~8#yJcmEmu2qx&DH%GdZ9SGE+E8OEq!QmTIpL@H*7mGOD%iacO$q2jr*<|_rqpDEu?XEy=6lgCf)iH;I`bpRUtzQzy4I{4`L zormFoH(lAY@SG~&0+SLRvws~AyxpO+UXrdJd4FGt${R<^|O?SGF7v2Txr3-#$WU~70k#URosdfD{cK@l*s*=y_3A>70k3NE_<);6w9l+>m7T~J`7Ohv0YnURDM47A#QV`Gug z$wq3fHg}TL2&F%tRX!KW4{`WN8eU%LU6Z#U7%pOU zxv(5&?-!J~3b8oTY{ahaWo^O-d@C&=5A~{$IF+3m0!zQId-Ra z_0k+^OQ@n$``0q9EKd%!EynaM3}bhjaLQ9H2mPWVwdF+{=9_=oKzR;p_n#I-(slz} z)0?v~L?%ICGk0Ik_io2R-O!P-j6F+_@%^}&9;d;ByweOaj<(k8DZB%7Am>dAo1u%0 zgVe=S(Vzoda4ay}cvxvB5bh~;Hd-s*TV|K*TN?+TQ>~)-iFGD}h@NxB!3Fe;tSmqm=+SCI{QxqWPIgdy9rateR{1eVX$&mfGo_;nTD*51f^@;r2!r5iNyoTE8@4iw< zWe_$;3|qwFu`x6zUW_-2e#}!P!E&_{L;NH)1$NaVl2+#-e!{MR)DYa^xMGj(9<8Y- zyIvz(d_26j02q32-M{$nu)pfl^~XF&H7<8cf%J}D$M34U6O*kG3l(*zf;cD6%deI7#&sRt`Eb~u5zB>C-sn(O5Zj15Z=vm$ z097V#|0)41`R%xbBmoYHZnH5Gz!eWcVtLoqWB{^8e;L*1n}`SC?mp(d8MZ1bC{o!r zx+>ra*zZVKt{C(2{yXfpjo|HRS|$8-oyYOC0kE0Tcwh{-->}X`zzLo@u@DFW$|7`y zeZgY@WoT{YP_`k&YQp`}3}B6l>8djxylh&H{VhNLcJtHaMZ86UcGkDS#~q7GGPL(v z4}HSb992QJtGSIu42}ar2|7g(6!I!&&yPDMOoKT7dV&#VmZDTXVa-HNU@>;U(fWpY z)Po7_&7$yN25tdtxh%c%CwW?ugfF(%rH}4@zd2t5ro|u_-%{ky|1aY2uBNtVt3DX2 ze2C0Iw~`VPCVGGk(OJdw7eA8cHgEdwN9J6v+HU&VyI(G!nRpa66OQVGi|li2jF8Xd zP@TO`mX?+at}mo?!=0D~?+PDnNIPR~AcXbs^Jjrr7ptDMOuqIXqS$)37MgMa``kUap$A|G&!NgiXboPzRc>0tzLsqCZ!aMf zl%IG&lC#{1xxoSGEmcsbHtA~K@NoA|#^*ejji1N-;Vo@{F}PWCZ39Mm-&dM2skdfh zMcmBP7YL5$Q=9?u6T1sF0&W@N)QDi5I_MxS{DD6yB|~MGm6BiZ&u@suShUmi-Op8{ zgB+uS$lBHV;@IwlC!b+Vr2HtBh+d8}ZJivsnG6j^MmNjB6S<>IYjTz$omxlZz?ryM zQ{l*Gvyp(E3YdQxxGF>o>q+Xnb{t!aCs2(Rpf4_|2zQ;+;C&k1O^2dU%3N%dIof9i z(A0T*J3(t^M4Gx5+vdq^HJa2!WikZ^QYg|+EmGJN=F0Tzt6P)qvtfF1*~)M@wa4C| z3J7zi1Nc4I_(*%b>p68=!0yE6OaY=LAcuo{&Ue2%tXn8SgTG}NZAvwz_c2;?6`Rvo z)*jh z;||zS(;td`@O4Jf$}G9cj(ZIxd51&Fl zt_jntS#GEo9;1I7HIZlkb7<8MPpiAv?zDr$l+wLEL5fLjZ|PeR1N+d$yWYj1WiwMK s^b-;|TLIMqPU8H}<^Opce&dOp9|<@u?f9htr~E*gkDfr$s@7ru1?OT?VgLXD literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_noplot_vr_pc_p300_different_epoch_size_thumb.png b/docs/_images/sphx_glr_noplot_vr_pc_p300_different_epoch_size_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbcfce4c3363b2114a3e00c070917d972c5e269 GIT binary patch literal 10252 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_Getting_Started_thumb.png b/docs/_images/sphx_glr_plot_Getting_Started_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbcfce4c3363b2114a3e00c070917d972c5e269 GIT binary patch literal 10252 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_benchmark_001.png b/docs/_images/sphx_glr_plot_benchmark_001.png new file mode 100644 index 0000000000000000000000000000000000000000..39676c02ccb50267d46e0c3def88e3a8b53206e5 GIT binary patch literal 26587 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_benchmark_DL_001.png b/docs/_images/sphx_glr_plot_benchmark_DL_001.png new file mode 100644 index 0000000000000000000000000000000000000000..32723120c9cfb875f1be93317fc21159d06d371a GIT binary patch literal 38917 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_benchmark_DL_thumb.png b/docs/_images/sphx_glr_plot_benchmark_DL_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..91a4b642825649151cc740f774f99bd965ed1136 GIT binary patch literal 12822 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

jqf*>~Y zJ?^ryi(k|bsL_x#bFB{8ci!1TBeSp{j+bWWXXIlF;D9u;EBt*{%=g$E}$5)7s}4N?G`2`wl!RZdTsrjW{vcrbBm4jSp%orL4)xV}0MpEx*}u6X)c z`tLZlRc|=jK#Zv$p9y>0i`B_HEsYmZCKP^>UWuF3(nuWP{I8AotUdYu{i@qCxySIY za* xr8?ti9Bi}E&^smJlFbS?D`j^F@Mefp0z(Yj$;{>P(>Bl=8VU#mLC)Csoq$! zF49`OjV|)|;_za?MX{7Xw)KTdj1H=@UN6~|1DN*2cZVnXKy?vE1WH`^yL5YaB2a;= z1Tme%+T!rxW5+hX$juFhGZCn_@`GuNoI`VuNI&>oe=13>{4RsTg1|;^sVR&gcCrhf zXb|UB;1K7FCi~`>9ap9*DXa>*RtC6bU*_jW_N-3W<2hkwI{xtC*37f!1RE~nr$WTy zFx#lGSZC>02D(Hd*d7slISvFVKu3SdWodr0p+7*jex^aT0a_P96{z~m z$Bi^Z;YPzJHzJFOc3N!&;o>7|03!Wk_V`G#?C*~o;jH1T?r&j*5}VG7UFBISmPNf? zzH(){RznGz|%-vV4)8cos8qr*W-*d8KMvBkM`_d0(TNm96st3=O2g{TAZK&h#4 zxMk+^8t#D5Pk%j4BR{`-t!IhR(Q$F*&(B!eZCcT{w@#<8FQpUFh5P!vd!>*Hgq-8A zsvhyAX;jW`(7fPdJzjLn;qtzxp!7-N>;YZuKrX*WC&GH_^2}Liw!dm z*;ej_aH|>Otnh-M=&6WQJWiUUXMJs6KqZ9xxdZ!>v@?#Yqr_d72&Cb+g@#r%xUbm| zv+qjk)w$&F;UG0cS+lw=7$Bj7Qt5PGUq$ry`LAf{dL%BO37oiDO_s&n$n8&7 zYz7QR!ZSgiIyyQMh0s^BzFg7)Bbx*{Hyn#%Ui_)%e(uhlsia$$vZ;X5vmB?Oj>qjJ zB{tm2(gTEQgM*bVM;Uf~B zJ6N`Te0uoOO-#;A9vBbapv`b1kdNq-MPT%EaB-c<`FZY~XYiNnu@?SmJ;O77b_KhI zZl0et!GShXc8*Hh9Fnx^JwbwLeHP9$2{asv8+vf|W?5H>yE_Ee zIW|ZB_&*BsuBd#N2q#ZcSOoYk z8ZjQPm44K+vUYv=djH=qVWvdnf^OC7%3J zTk9ud!Awa+og%s$DXCE4$IaSOMv9aE2E^<0uJ(D533wb8`jVaiSlsaXu3kHH=8SF6 zs+%ln^XAPY!jXet!%WU5lnTs5R2QOP0N}r(U~qjqTQ*qJR(aZu?QJkK=A6FN)c9Hm z;yBSNGA?4U3YjT!dG85l7*g5hc)VXN$#C}(@=Pqll%*v5MJ`Wx|7%493ny~pJEhtEz{x<5>>}k2%qJ6JCaOQ^0 zXKYs?gg|<+fDk9Eq^S6bpX%}B$HeV59FJb~7{5&xupK$C+~s4%${CVd=?sd z+;-&a&9bBH8tGP+k_z@KOcS|slxizUnqfBbW~QbFurfNGMpNAvzsirc|C+JcPq>C{ zZ5Jo}H~Bn|;$p>Tg#F=0fWI!zFlqdOcy?TQWJ>;r>wnH6xv-U8A>Y z&guP{A)#al3{_xr6><{e4)dZ{IM-3q$1TL7yLa@W+$&}KeLCiqHzf)~Llk;GWv6O} zaWH)yrm+6iau_=xIMaSeRxqDM2IVl(C4~X&;ArvS`$ol8_g;|&(wfW;rBS-N(G_9f z!9Wo(sfR#4uV<+$<5By`=IocshR~Uvd%* zV;Mcm64bTDN=L&_{GEGBO&)1udb(bUFMO}3{?yCf>g|tQ-|u+4c0EOjmi8xoevC8Q z9TjGuhz^>A>($YW{brj6ekJkp1eqc4pm%OLU;8QVYo+M-khig5xqA%bIr@t4oJpw( zeETT>-G7qI{)e^<3a6|>=G>8I!yP(Ta_Pzyb#>Dnwn(B+)NX+LH}mUldZtMOD{T5r zCy>mk$*u||sm1#9nvA$fBV|hn-+b2IUeqEdYH?<``P(;dW39raUvHszFX-vfe1to7 z+SK$gZ`jfQ5R(4Ppv2xC!QeU~reu~#?^2Psz4jk-v}OozjlapaPm9Pj=c_WgJB zw0U$3!;zj5iP88tCpJyMj00U|L#%DD*~3Wu@idiTJB6eus4~=)!%>k07>s*PR=+o{{}SSo~}|J zPeh`Ru~r6e|6>zoO0duuNl8g+IrLd1Fd@hkq})h2;TYT|Cn7PxLLmt?Lk!VGQzE2z zdog_v{8?=6U?J>`on7`RIo_k#n1K2dbYF9E72(?uP+5j3d&zchg}hswOl!5>*te4a zgAgti@MLT(5ezV=%Wf~G0aF(5;yRHX1|B#)yHst=&9E)QW>_^*HD(Wt1iK3PYZrJn z%0+`s`LHIqb{Ykp-9*lgbA5^bhSls^T|QOXXEiHsvd-co$FCyzeKVIejE!b8*}1zR z$(#&cja?0^p)BJ_u0+S7%PB-PE+)&wx|?f>r~CflZ0q=Wv=&Q?$!Td^aBQ&yiICT) zW{_P}GzN zd;uG+=H|zURDNh^I)TsC2LY}>n{0iwxXmHtu;4OC+JmoI1rv)g%+I7VWjw7RAyLdr4ItvRIR7dB8Jd5N7Asxp1VdJuOR)`RDW zWr!c2ec?PJjklSp6U91IEtY(+yk~;Y3o_`q^Pk&D1F>U7xSv>wymjkUW@a#ULZ(0S zxdpYp)v%c!P_!tTyMhq+Beo6rRYE2vCh(ry88%n#ssR7;^@SuuGoiGqapHtok8?#V z0Rt2Q@@ZHY;Xc5|k9!#s9)5QJ&KG#q05@C~c8idZ(9Ufha4q_O_mvSV5_3*O&B(|+ z$C8wil5g>g=?o-r&>KnkHL!H(fwORDBO)U9N!t10GH@C|0RLrD5N-k7ReUM2tYBtl zHmim;USzrOTX*j8LL(x{4*}yxa+#gYC??oD1dDE1d&7QLH62Zj@E<=6|4ek%#4CoJ zRaLzK#%*h7cN~#10&96(6pI-8V3vdnjD;9t(@)T3$Fpb82r75GD}NV~Q1bW?+xiq6 zk^Ufn`Yfb^Sb^9Vz-HSfeT)De?OZI&?tvyC5>IR-2)OMUuolK*8&MM2B*hvCHh>t& z*;?=PDMs7VO)xSDkS{Nn!(DhF(;S|;aQSjM;DpGMk7}e5`5@xe;+dGqcL<_Tz9eEh z6ZPAV#oixCZHWq!oXFjXU0THUyJcJ){Pgad`KrG1_13<|`(4o%n@)eHeozTJLPOm6 z$hxG2#6O!hxX(F)xFqJ}p4ZbO7F7UzL{;E= zSgT7ky@;r|qpL+m(-6Prz T(S_LQCn?IS%B7vsfAGHmP8Id= literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_benchmark_grid_search_001.png b/docs/_images/sphx_glr_plot_benchmark_grid_search_001.png new file mode 100644 index 0000000000000000000000000000000000000000..11f96e44182c6eb08acf89f9a0a449aaa17358be GIT binary patch literal 26565 zcmeIb2UL}3+Ah4+s7VYmiKE1VB#IK1q97pBVq)9WNRci!nlxo2NY^ojL{uV3Z#F=r zcj>56I!KpJq)A8mrtSZ_cV_0yS#!SsoH^h3t@ZzFP1XuF_Ph7{yw7u&tK9tZgW55k zPd9zaU@&-?#}8{T7$2!H7%MbBUWLE$a5m_`FEaK=bnP{5P3;}e*qJa?&)8qIvbDFe zIQx}@i5<(r)!lUV%C5E22oo(GqDfh;d;2pCl`h`~RHtWpppM$SH8Twe9<>4`V&Tj4X`)faYH^IKr zTJ&-vE24^>JDO$xF8@FuOR2{$YYRRJV?cYq<1+e9*`{ls;FoW&6@G+Y?tgoFIez)! ztG)D(-~1^MUm1V?7|X$6eEQK&`eo(vb@+O9`Tx<&uI@P7`s~s!Kc%d>f!L6odp!*$ zLJ^@FF=^!^qg~nfJI&pG;x?_%UX9HEwoYA`{em%T_(dQisg*rbzzIwASRCwc%W>4t zv1gwp-4d8b1na-TxpA%$C3JFaeApW z8P+Y42m5@++g(N@wPR1lJQ=eU*`F6AVP<+`{mJ7dCMLW0>G-du#0Wv-|DyW8L^; z3H}dih&M3nEWGB_d2RKE_w%ne+jbYO;8mF!Y17o!_PgAmC!}-A$>h4iOq-*zQlv&g z!O~pl#TTFGSw#BLTBw9bSwE0e2@>BiKU(0?oM{`emjB@Sg2ide$$?+-G>w})IE%H3 z#sz6MZ3pF@CyTGG-Wr(M;hvLUMH@q4@%=HTPrloHl-6!Z-NtuMV-rdRC zvAQ=Z#76&q$HM4HgMn=YR@;CRcI(T1XRqb+D$JgiYBqmFHxQeUeZhSqq{H<*kHECI z$HMlG+1Ju3rMqM6I2#w1W(p#jQq9EdhK8C_S#>9lMJfk~S~MmYIW(CB3rRLHQq zeK$|K4a7u`_lSAONJ>i5lW}OV4mc*@mUbwDZRy>L1(O*{dRY^1kQtXdUdq!R!Z8x7 zOpcH+Q~QZmAUwe+hqhX=P0p}C?kDz81n%;DbeKaa?l|Dk^;MCoAyVuYeEGlP`HL~_ zCMu-+))>!zx5#k_cOHm&rI5i8E-*Z^ywEPvakSm3`|h#va*3+*ZI>Gti}RyH?Ud9M z*xj@`GE;S$wNJHU7bYS&uw)q(ULB2 z#czz;JIOt)q&;7`u(TP zcC^6QB7DZKmmJ=n@syi>dv2=e%)8%yX|k_X9rSqYINU7hG2hZLK5XkDTN|ZXR((vM z?Q{edN?$+yf}gi{Cm=zQ1c0;U*Pe9@~mFKn80>5mLZX*}i9Lq|VX9`P3~Y;9_YH|iUV98xbK|diIrncI;*bs6dO6VX(zA#wHt06+DhhaXV zN*SxK()!J)B8RP>_3+`t+!mW0KTAu?&AB@GPc)#chv~c1&mjGRcDwuh@aD;^u@`H~ zn57gj-C9l>SZk|k zum`7k@SI1lAbu+pe&u2QFrK-Z+)g4HnZpqVvC&9c=xKV87#Zq{Pb{Hs%gb; zTx2|NrrkhIW27MN5K8jh`<&$nLxlR+M1~yqHGE6oC>{DA?D-YVH_#>k6 z6IYbHX5>2uTOuz z{iyJpd?c%TnavksZ;V);kgN=o&CDIi9`w&_b7)yL%q)%9Pv2dD+n=&lS6sBmb+AXC z*lw1x(#^U&*wCY6?3SKCoYfb;hnAhMFOhYdKUJdgz$3%mew&6Skk&3F6(HsL`QGzZ zn0vqK+zgIB77e?w?*8kO@%nzo?(Ckq3!B-S!%pA z9x&&QM`<}QFkpwQB|4T^JRuP4TqQqqexx-^2JvF^qzsOprlzJZ;$+_QXNYiHE*381 zX|_R{h)ZwK@9!w^*r^_F$Z1Au@D;?{+xpaXd^g#r$dSQ07no=9Zk0Q*V)fd%j#DOn z+9`txIlcJYD%RH4r9E~_lhKMMePNDjS%x-0l)ZWIy~O2#Iyqz>p6RR(_j$?>UZL}M zWJivBZ4eo68+Fgjk55SvKepAWd%2rpZUNp-%vVUg5-BlQa7}r^UV-+ax)@CfY&)y; z`jbvQemdf~q98{$9M9UI9S8U546Ez5bd=ltG`l7szpnGjXIl>Jt*@`2>ZlO<@cX6? zq$ZWHgOaofA4Ob3?$E+o_j`jI-8a?3-?iKk4b|PE++dnRk)(GsbW>h2XtRgSKGaNcgl3LrI@|qgvZ7B ztlnUrW&{O4_r*DpvFldY75beSew>9qMapfph-|A8B^z|NmvA;bY{PX^5rg~gUtg<) z$emiW)ukJiMb}wRq1eRyx#iZDamhzbD}w#7rS{n7O`Syf>w}GFbxpt5Q|{G~O9%lu zx~u|}*8QkHp2o&*PUG`7@X1B^VzlZYXEx6IcWj8nG`)jJn>@dobc9jP`bo;>u>ucx4&%M5- zo_>7HI*EvBBD$UKFLKW3X*qmc+_#}T+y?A zT}9qiOY@@v$GE(?^GaE`gK3@p2rOb-@JKq<&tn*M)L)pj1K3)`0`-M*lK5# z3h{OI^*!m0r!3#(Kl8}n5P4si#TH}g0Enn^VEg3yaQXWRtZ>AOL3w8 zsWw$^R%z8o_0HXvv@2Y;x*G*A2r}M>DG(iXCSDxUT!psm@|IYw_2=Yt|4=ik%1t)v-BrkgV0!Ig#=p^hEB7; zdrmwOSo~(QRnj3m3Mx+dQJo~eco1OhF4JP2X*4%88i9QyjSs67dotdxh~KeWr(jNd zQ32JpO?H126%_12V@@y(Zl7RflNZJ=Ny@BUy3OqQp z1DtSfQ#ecW9uM~f2Y;uz$kuP|%1m-so||1U*0f{qvQE~SH}?-QeQ*dQm?;BKW1|uh zL=npjrQV*teza(Eq)nD7Zdx9=Dsy9bn5;A&dBv|^f4@Oy6qzQNIx)KG>n*D`X`VQ7 zcQ~U(l>S^PKhwH^^H7D<65%qM=XjU3h}foge;8$;N=t_IpvP>cWuqw0sh9RlQFV^v z=&da>;u5Ci<`?}+kh_ub(U3^kbr(}JC-dRAb&4s|H~3=?NbDL&U&V3Sm}C*j#P&1g02N#@r_Iu?4RC#Y*1FB3EF z%tHuhROIgtb8Oe^Tx1_o`|#oAZOT=f;=DiL=6k9Q&U*3b9>J33 z-aBoq1n@D8zPfb9nRs$-m&-$sCFx;^8e6P)R?J=vNa1^l+V(&W-QRJtS8iCiS4yT*5md) zZ187?T+Ve2Pq)}cpd_oB^8QFo;fi=If$SACd$2XDZth74L`kxp zg4CrV{s0P$vO`JVQ%84eqr^^XJ}APt4jOdmpO;4+rM`qRsrSwIycHHJ}qIMLQfp_zK=c2kk^op+cY7X_ti$MP}ae)5j4(Qt=4Ps3k#& zO2O~BEj3R0-7>KPxwh=fu?5cGFx}Ar^blr2tE;VJBv~7+Ueyy|93C7T?Ao)(m^uFZ zpil?9($VhqMziyi@2i_oCD*2yl;PxaN^VQH2ToKeDjIX<8V3i_A}NojMl1@)#%Jhf zUmiSJaM89JB}yR0N?LNy%C&gJc|w7W}MnKv??W`GAzP#+#XiR7yR@}ewy*-ad20)93$!R z0{YB70#`b(^R|`d4be?(KXylW6aYrgdL6^$Rs@Z4>|)(^tYev2{_MMLiY%Y;-#rCR zExi<2`r(w@RDGE?b~`@P{yE*cU)Blv14bLOOFWfVidJ5D=6&^}T;x7Kv7DilIfV&< zJ+4R?qIM%}YI(*L=7%&BVq$h>+IHmURw>NiivYy1a_gRjxxvH$M}&Gi;Af@7Etz5- zU7I_;;Q-__>ij$%prk9#o1c!pMWo%4BS)?ut5^aavMUiqP7eU7fceROP3}$RkC*P* zJn1xEB2vduuXE#PWdQ@;^Z!N7TN)fDjjZ4-{XOt{tY!O zqV$gOqY`Ic{5X!?q-%o^E>p5iV4v%&^*VJPe2eolV#X*%*T|)08ZLD>>eM0CjN{H4 z?+>F$5#!x*Ac@w{uE2eqR$_HzFNSLGy9I$L-F>o zZEtx{&r4p#+}0S)Xgd_^PH&UW^Z+Hf=X;NW>?*ei*YT2Z)Lmt$k9&|8{4<+OLsof@ ziv)0H4s^cW%5Hso?gpR35MM?F+rwRPp|6126Mo0mOV`+&WS5X(MTB-mptD{xxw>;A zQcKjJ`csBN8A9t?JUPQFzu%}Z`ZQwQqhsEcSC_3A_f%Z?no=w)UGlwsP?)q4!RO>ROYPQ_bOM4@hq_2$s(9vouB7k&g~m&KZleCo@)$4|*C_eFQ$xjQAp znH}K>pHcbNh;GIAc4>;A{q5(-A9m1tKZoFAOSWAp{Q zT4&pcr-V4m1kwTQ+FvUMFDum05Dkz(8$d8^%#+z!>9?-ED||m$xAU>f%m`0&w&Q3x z8c37rp(gxNvHTq24pgZq#~#MZ?+4`~oarGJC{91Cay>oH+=8b|E3r6@Mk^J7VmFeS zGD5b*NpKRbn`|rGCB#%VhRqE2M%k)zCSy*$)b1XWkpvV<3x_>Ff4EC=;u_O?tGqZO z%_{44LTV~_{UeX;4Yi7_#s2QmuHbdB0_Rl>#+%Ux%B(w;nJM*B&r#Y*vq zloN9q#;HNOS182#XBB-~g&jnj77@qSb?j|t^`m2E3$q`9j)j?`fs7yZ zK;zPj6j?(35wQI=S+noFCMd6>6q^Zo9kW)`O2N@avu(_`s~YJ5%~m}1gzpW-QXltd~(r`P5sXFnH+AB z22|}ri69QRHya@;sAFk5b0ZLv)H+_qe(!!;`9|~k&>&xNvt9$bv_zd;z~S`*AGRjB>PDKT*QE{o zYQc)$Z!YGyd;EszW@+^k`(vA%n{zqtT{`^9uI5cCL@xxqT?)tod(-LrKJDGnAgK>Q zE1O#`>unb?$h7_G=GDlU6s@4d#7jRcO-AgIxLhgA^f~DlFOfE*Q=6rlX_{~+GR9EU z?8T3t1c{p{u>xLbAQpMzES>vBct{vDkpCKf=eUTGSodANub1R|vYQ2&A;EsNgKJzQ zS$K{$tQ)6ftQI3o7t#X8-P`8%B2DYPbG1EtY8R3oqd~D~$%q#c6p029L2WA#vK>rk z9E5Hbg2vUJqg9d)Dgo^VroA~`H7S=>PriQ>ou$0oKjo&zk-0SEM_Fa}gMb7yc8D$bq%a23 z1=Ze;Ag&bIVV1I-e&=Zr-V#|RkY{PK18+4nj^e4QK@w)Z$jHDuP`asOJx zapA0zWPOG1Mh0WSyXB&SqJOtzUb+0qFLfR8?+*^?`UnQe$fk1^bSC}`)-35qe1=yi z-KPowM(nC`7VB}0j+C>0y*l&#t%zUk+Fl5(UORTF;!0o7Eti3(xwB(gPK#L~;${sk z6-Hk$gg+-%!l^H;@$o!?o)T7XljeqLlYj%T_pSWk)ak$Fbh6)`-5TzLZQXe?9Lvyy z+xx3`T&myx=5UnCm4jVJjl=FKetgzUl|N#at%6_uY7a$i>zw_zml$t;+lt^zjh(Xn zoeJ-4RN6Qw!JkdXtJ~; zBxd(%Cvlhd@?7z$8@ZB$6}_S>eFRbd8ol$Xa~P=Gg-B!YkR|N>(ayqmu}>Dh+RsjU zdU98Kf>M-z08 z`7scltp2DFAcTmJWdM&WP$hpIcJOj3p%s_9Ub}&t$=?x;>YfeEB76m}++KX>vfZ(9 z1e*+LRwT=TaP*3=OF5!sbTFzeRaq%a_HkVvYj?IIkQ|>4s`DRVW4-l@qor?kqVw*x6rJk0rTxL_Lr%w{sEB@AG3X9|Dr)<} zU2NP5uTA5qquz8KwlprQRaXo{0Wa$^lzc24U5%iCoPy)~HxGy+BE-4-f#+5w6b!^> zpp|w^ww$AY14gF@G)O5C2BRpsH%geQV3X(x?OnFP;MIj#L8g+3K~&mzA@`o@yCt>d zv6P1Whui`R`@TPN#LIppUGLH8<>AFwk%l};a!zyc9#YLq5snchLrxL_c9O2`ls?e$ zB&GmYFeR?w?y;>w1W2zL=G?Y*-A-L{gYLQ8p$^R!8~2<4Ao{HHFM=gJ(yhOu`dOIH zEU4hiAG<-IWfs5zarcE;%IaQ5wL0h{x8Pp%tkdi5%J&sL1|gCKSS7^%PSwF{*p9pB z;sQ&j8dVe~<0dpb9W0XT@0-Sbs@pzkc&^BPIOp~d-9qW1~vCiHo)@jWO zh1%Y_N}II2P&@o;F)44po7e>|%>i&hwdl99SvGSd ze64m^@Plo$=c#L=R)gr*&O8u8qSNj-)hoam#l*&1*2pLf;w%-Nd}HmeCf-GGtga}(MXeGHmO$Rm z?{?yf+4qmUDN|Y}$)7H~Dp>NAJ0{rx!HpHtIrL;f7`o zHF{Hx#t|>q$_f+03otGKAwZT%G_>4U;R-^v#_JQ^xoxP@p7?t}n-WSAR_SeGxo)^u zIw7#MAcF{!mS)?b0N7&D(2b3cQ07Z}0Y$YcDCOGh%U#|v#?8b>StUJRB{P~ku_4wY zMynL4u@6ugk?L%JK7pw)kLHd!o05N&Oz6HOIfXxwuA}FsGB3PNdAa^ymrpPlr#J3J zv$6%4O+T0%lx;P!I*HWRZ>#8 zCj&>;(c}5{P*#Fyy4Y>?Vc)9A>BtYe#JWA*G>Ls%wRTHj0cUYk29U?Zs0T-O`_Ws) zQY}`#=zQdu;|S^|0MnI$3EKgr=!N>C3T?O_TGD+GCs-vFpqUe*W?%$&My&(UCK4v4 z_g+2i>GoBxMDNw{IKtMG-=P>uEC^w}$JS%sfLapQQJ0P~bR74bCVC~`%Oc>&K_?;e z?&s}xASR?N_yvx6nT8;fGyD&wbDZ~$c8H4y9bELdJ=_x6W7868mnZ389EvOJqGQ^M zU`)w!YMAr`Yq5<4OTfzAL+{p$md9E@ZML(|6+43(4&kH%kX+HnytnqFHsy*4z|gV* zW(1*v61_XeM}#y)4#$1s(rT2NF23YRMXEBzN|X_SdwuP}C;6ka4nW6tbu5lJ(m(eC ze*`{n?eAQXKq8#0oWyBkvEId4Tk9|V1xxDsoj3yqn)8W#A+D9ckA!HY(Z9EUg{-|a zEJ~UR!aM+7JvI~-n_lYk!OpU?FeEZ$il-v{JUDa%lev$Uv~(m`YpiB6iJ$-n^*a0Mz|*<=EN1EdK&vp=2kBTzbVSn@1Cqxuln(mb#|b1P0@>%;9~>>Qt2bS^}2hAb%q|0b)tgh z7AI?o{;kP#nK?ScCOrmGPKn3@eO#D4&4^VY88ILss)E~y(R$iJXhJGZXk&+68d7vG zGHxjlt=z-CoNpSa^kq);s#Fd>E3>aX|UTt~0yn$GQci0!SMxnU>k zxwl%GaV7Uh3`}doTcl()o97UAs1OixFxu zh?u54KBqvuLIa2@`;k`m_K4HIg4b8^l%o3?%p~DV9{{pqG4~H%a~U^oh(t7?tcb{W zQ=H|@&@LcqwjJl0YNIJPV5%%^{$4Dd@is}}TX>+lz2zYi@?r{evE^Y?YHlq#s1vmt zT4cjcZmGNFw@kS8u^y))UCc1l>GG%$GpfQ(+QVa5EJ#yU)?lVNCMfn?a-Ej6b-^q2 zqtT!7AKXv4+ns|0PgXYUL*G#P-S^(0U`;?Y7kUU#=0=(%?g7B_811N8} zZ_S*Y@8E=caOOMMq>mA#=aPb_(1#EKW*v#8lyoAYfQ@3};tU^3x&?ASeD2i13La>t zm?%+;79{yyK06+Bwtvy&lhc>v6@I@qm-P71{BIuTQ`Z;VJL#ug@xyw7V@C@7e5Z#M z<}yOp4lBHG{7p3b{X;7pP|77N^jxMSD50YQu)2>VE3~3u))YH%i6w;lb6trNIg^9!R{aMllmtSPwN1UBei0y zn<1L!dDbh!RG~|;ArRwCsLARX6)y@?!Q7EAp#&k59wf{rDI8oz-qcX zioPpWeP;e91NB=kop~R+BchT(57*$FaeH6Vh5#fLgNT8^p>X%Penar@Yld<_`ZfUp zreiH!U-(#S=|F6ma5NsjKQwe^19dU@&tk-m(aExHeIF~)Q&GJpEnxTV)Jm!7s3Wl} z1+qSV(|Yt)-o8gW<)3})GFU1lbKzxeP0B+P39TtM>Fi7Z`t-MC+Ctv7_{$81Ld7fk zm7aak;3KfS7O#Nhl( zn-FP73)kg%ZdwT$=(7(=pzUCkJyzRe8@hInO<-2)&gdht18L^ToJ>+U#sv`a$tpu}^+_O_T#4S_QzguLAJ1hxU7u}IQQ>~iW--I)>;$e6 ziR8Yn#^w%ehV;o8CAvCbO%tUi2>87IlG^j*j$| zMerfEZ~A^*r^YRpDjWW zGZxqmvAYLnuNv6loxWnmW*7yhb@*r)8HGhaLqb7?Fiz8W6Q`Zr%0!UDaQ&xk3MuON zTAN&Sb%!_yjEFcY)>VlmzMBhzd$4p&u<@+n^hVLU`dmHnw?2>2Gf7I%S09@y4h~t| z8+o%7F9d5-1NrT$MAGV1=Ywr12cYjy%=<5O-)WGhsaN!27HT6A5C~OBMEI|^wTGU< zC%O2xjj|3_wBo3PJ>D&<;JILNn|L-{jn{wR($G5O+23H>67`MW&hZl+?C8aK+iD%W zcJ^01ZPi8vgPyie)J;a>N-XL#ln+jSne-bSdO_}u{zcMVA%L4rr?2w>Us>1zSw{)6sZg%; zKq6@H{#h2QZzq#FW+<%OhMW}3^#72NCkZ=s7i?#}k}&HVp4nNSdD*5-q~p}gv5mR! z9F(ov(YF9m?AksL%HZoPh`?B+bJ&Bkbar?KT80XeOc78*f=0J_0%wr2q6|eFGs8fS zka~?pB4w%tNfiRD!3yb{KInjL7J-5Ji^H}k;YJAYCgO0Y%cIjIbPugVC&z_8Tf;g< z8#<#cqj`R*;j@>vvPX+epAM}+zN$ds7YqPf6mWo-WG~i58Nb6qB^~V$^Hbub zT!0Rs6bx=Cihb#Wrs$ojQ2Y9WOOcjtv)6?D{2d6%nCkopZSF}cUY+^7;fL}jX6fzR z`9m#!RiUZB*;Hkr3&n|Q>zo2Q;d;%TI1W;9S|((fCQr|UK8*sTWl{akLpmrFT@g=j z(80?W7F|#~R-mz(|Ln`XUqJwV>d`#lq$PjiUkUP{28_xK9H6C-BAmI&ig8u2s$j8h zxsLySt;+71oxSW#zP#fDLdkz6OL$H}p!qC8iZSK*yDma=ioyDAYGbEaydWu&A zvaYjZh7d+jjNxl?MEhBFomU|c`aMM)aupu}?D!AblU}sloF54d&&)@V-@wtL#$8zh z55gS`E!DDBI2np5qj<_eKp})rK1(@39{`P?N!^nZQ`WRy(Rc)(=ahZQ4YPuJu@hJA zu@#vXU&|}?*JQgi49K1SrCbq$c$L7t51w0&ci%9sz@GGcjBSvG`bg2P;QDIbN?!M| z>kFN$6^qAye>u^4owpYaTLqyjw8%J|>(_e;@W!EfZNiZq4;ytAB0ZPHg}Nu?Fd&lW z>}Xf&A7%>XZe>6AbhhFg$KchQ?(4%V8W+#tuawU(K{ol=tSX%66p{Sj&1YIQiIW}~ zHBR1h6AsOq7)n>xq&8X@d-)7U>%QWM1<$9iv?RoWymtO6R^Se@C5 z<(=y@EpKXAZ2N01wZUyA@;on{>ZWIX4NgnL(c>d7zO~7h1LEqP3ctun`O(A|1v|_l zxI?|nvirTF*GDwQ3*IbA;~jMB-zII#!7b%jc#B zD#uU+43(Hj%{56wF1D|KtgCbpv%YXr?Z}OZ4Z>@{h>W-mCpx*lTS0u3Qsm9JTBp+v zLpd(`TKgBbf4@xOW&uAV;&|KOI?eevngSQTi5`h;^wBs%n)3ngT$vR29K(b%315M#PeqWcb=!LR9I5707aFBvY;x|!F4L7uAFVQc?=qqAPX2WNd(G6N zkA`E@3`G1IHZAuTzxK)4FIsUq`bw`(Kh{#}c|913r>}m3;g$5AXMW5RtNQmY!v_u=>$7`DmTIH0AR%rfdENf@fN`<=`Aq^JEgBdX{BRzGh&a#mi)*8Ta zwd@D$P*MtOnUqQOXT84T)WtT~l&0f&YWr}G$Ah4!%Xnr#;KT8{eZREqka`M)bI{>z+NbY{5+;9oO%{TILNx%kFFqV}muBKwZ2 zRFfcB`nSiX6@k4HDS@??>aUO0$p_rn2YA^)sh&&ohnR@&CGEoJB?NX{TgR!Nk^(N|;30T*(xmrzrHz zSpX_F4|B#|@|r-ckdRFA>ctxrsv+ycz#?(*IigsC(!i^ARNZ-OA`@& zq|PFN7%_oFWs_3l#vQJR8DieKMiev|f8GO$0mJ`tS>5`bQ2jC?)7z;Q`u4sXyfg%K zJ~~JF*c6JBl0&Qc?+J3fMG#r`QkO&mP6!$$9-!ibYEE)-HLe8;nJxzXQz@zjQfba* zpn@X_CvvTgeL0MD8$LdQxa%tjV!UKMt$=W*f6N{gpYv!=nrsUe#m(Q`w}Kp=Ab6@t z=-DuR0Ch|6iBHoYJ%u3G-vMk<8t_H&&JZgf2y}KSLcU4rwZ_##^hpGY#QC^2t`mwV zlH;3#_@*+FG$3;~P8WF#badYIS*Ld3Yh-yU&e{PN*~2@8lAWcdxH#E6_c5+hXl58Q zl<$Y<^-s+RBccY)MS)5@)HC3Qh5yqYN?hgt11Iyp#~=Fdd;70)+Wvbb{~K1a?EGoF z>LYxSpw%oun@YiuMy?NmCXdp4yU34Qi-rqv&g8aaLopNcJ839QP(Qc6>e&hf=F5NmLFao%=%>_&ojrb7gBy zt-uv4Mr)TEjH7Hyg7D@?Z*TJZ`um^iGPSj|Nb!cN9oxh|LA^h9LEx3bk#)?#-c~>< zJ^|!g)IJyqLOqBghC;Vdy{}7H*PhK$JHabo<29zK+rj?;VO^FiDPXAj03enAA`~77P2u_LJW|C#%Le%V z!VhQW?%hiP6C~RJ4`fDFkr@#iM0j)AazH!5f4f{HtZp_V+k#u7-J~S&21!=zw1TOC zEH2>32oB+PZvWLI0PsHlPG4ArZ_H~7&m(NGAq)>8u!$bOPd9Au<)BEb@73aaAdwXb zzHkg&Q2|-9NSe^~`gR!v#i77;dwN4`D`!7+O@KqokBOr4Lib_t(5Jq?zw|UCJPJoN z0>1R@{6#=(N?Rd5j|!$@?({E~DTUqSU~tTz2wT}qI%~o|VxkDm)O{B$ycg%76ez(4 za}S`v|S2?6uWPoHh9(bB}XF@)Ev zei4`pY!q;c>QV2lVRZaZxjJbMZNNX@*V|tr0zF$sIl+aHMMk})n)ln(3n`K+WPL_e zuULYztyU|CPN?|?)r_A?P(TM#T?icKtn9-t8QeneB-lsziFn~4P@8CMC7Y#{yo)SqzyhO(CL%AI8B zfVSW+PO=!FuH!y5A)&=8Rh8x^pt?-|`_mNOD+Bp4;p}o?_P390pS?vOO$d;_& z?)2IcAn2{QbOj1dy#hDbUV7>@)s4EJk$;g`-OXvk=*hD1(D-Dgftyuw?YY(@qh}%h&}&O({Yir!h@&jtWB@Adg$>5A`|Ub) zxqXCdEl!jC113!K?EzbVa)Z1RYy`Nhd(6d=L* zDr?C5tFS$BV~~JVp!v}%kOyQp1i+VWtV)sN3gSekz-=U}k8~JD-3R(U?)!Ngec@%@ zxp?OrJA9el`^R7YtnPT{No=e^Tozwc$#P$SdEICOEyff}NryxPIXSDMf=z#MM!U$@ z6pci;CJn*afJ}B9WE?1oX27X^_O`MQ5|Y&0aImarZ!eDh;+#)9`sCMA(?7pQ#20RO zOUT&UaB182vmOoD>#JH|e$$Oh1`}d@-+H{e#7h!#%$PN4A~t#Gj`U8uTq=?}S@iB! z7~J8@N&RgYm;9>WE6U&wd2sJrCdtFIufCwy0p;ndO(atieKQSBg)};ELCD|bJLgryHzPx)Gx;=FJP5Pox{>NXQEeYSgAri}g#tzxm?%Fif zAOl)v7Ot{=wR_3Ss~r5_t4#rd=n5|+wc&8R+GJp4l=rPc(H(w1 zODjl)Hkc1qKPuW*w1Wu;;AX2#^Xjw7ik4_cuMZ>tzS`6RoyW@NZ2SHc-E*5|mxuK)`v#Fs;o_K>l7rXGvuaUC;6fm^ zS2mwCy!7hTT)+cREBoKt)IY7qN^8W_oz97hGEIJc@YsQ4f0n@)*Fe^ftiyNlKW^lJEshRf^_GTKk(sWFkzsax}bwI7_+m#4&z95+JNeGlm_6OcEh~zua

(B+9y*6C{ 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 H$c3 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 CZMU@m literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_braindecode_thumb.png b/docs/_images/sphx_glr_plot_braindecode_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..7231aa15e136d47da3c85fc682328a9dce5453ab GIT binary patch literal 6081 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_cross_session_motor_imagery_thumb.png b/docs/_images/sphx_glr_plot_cross_session_motor_imagery_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..951e8d0f11f6fbd63e6d23cdaddc7bf5557f232b GIT binary patch literal 12811 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_cross_session_multiple_datasets_001.png b/docs/_images/sphx_glr_plot_cross_session_multiple_datasets_001.png new file mode 100644 index 0000000000000000000000000000000000000000..37fa973f78b3ce2ca28b8b121044713b98cc2a42 GIT binary patch literal 17676 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_cross_subject_ssvep_001.png b/docs/_images/sphx_glr_plot_cross_subject_ssvep_001.png new file mode 100644 index 0000000000000000000000000000000000000000..e5ca73d1895f8114d5a5964da4a7c25fcd892884 GIT binary patch literal 14978 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_disk_cache_thumb.png b/docs/_images/sphx_glr_plot_disk_cache_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbcfce4c3363b2114a3e00c070917d972c5e269 GIT binary patch literal 10252 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_explore_paradigm_thumb.png b/docs/_images/sphx_glr_plot_explore_paradigm_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..dcbcfce4c3363b2114a3e00c070917d972c5e269 GIT binary patch literal 10252 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_filterbank_csp_vs_csp_001.png b/docs/_images/sphx_glr_plot_filterbank_csp_vs_csp_001.png new file mode 100644 index 0000000000000000000000000000000000000000..12869fb2bd06808dcffac4aa0022d76b0e48d646 GIT binary patch literal 24975 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%0AYC}-Ht`0% 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

5~oEAsssRbs5Rcn^Ms052yTTTQQh4 zaJvxw3_5gpc=+F>p&B#zWn*I_(Ty9I#K1Fl*;{#%+1m|c4q(oU!N3pf6RA2N=zfZb z_yu~Rr`!#1IK?shQS<(@FCG>UIglPO=MmPsI1A)8Gb;;6R8$lK{+XsGwLiga-OexE zfWbhf2vW?vd-tvnKrrXsB}r(B$XpeiZq0NIfZ%(tf0%uRq=RY%Q1$$1u#WlRL#Rk# z*JJI6%Q-so!QcuZ$e55lRZL0Hn&iMnb=zue#M~%=UCey-rtqTk11atD#3K_h4aX$$h~EqHfO#$Ktv z9yDDCQ`zp(Y`M@!Z4|vz?tb4pE|`+Rq)G;{$H@m%JobijWHDX`wCD4w_#_DpJLh7|Z#&IcpHwz(mV) zG*efPqsCB0qSUwp8m0h~zXZnxe{gwRi}V2Z<_+i^!4?LZr@gT{+tLDVnj5BvW$cWq7g+Z ziO4_`gyf&fh|#_S;s7*e`_&OiXag7c>{lp)Za$p$BiF|ITeV(0ljtz<6);qSuuC-f z5|Pl*0l|g|?@_>1U97vGInatqq8{DrwSI;c3% zc8~^xV1*egKA6A*QPAoV1l4SXx-_mB{iRwC!mvQTY<&# zDqd(by+?C_RCh#0lMlD&IYI7(n)M8vfG(kJJirbA02#D^9Z@s83)|9#G({djBkT;l zQLWCsMi6PzFl6pku( z9IAAfg#!Sv4YVUNDoPTv3x;N(U_&@|E$7$$-di1&k(1Md#6TQ0(?K@)0N9ln3dN>f zja;cd2kaFO8AOAV86#hQL7E|3=0j9E3FHbiC)-EHg!uT#OdK*}25h3pq@M+HVW`H1 z7f@e4u(=`wpiJuZa32`pE{@B&Ww6Q?lprs2;IxQ~2pd}{lvOBvYQ={5V89{h`IXsi z26W7hm^d&1^j`ykFgvE*B(E9jCWh$Gms=$?ZQ|EC-hb( zxE@$$JbV=puSZjz+u@5ME91NE5MzNsL2d2r^=3RT)zqFzNqum6`9isd0age^2#Ofs zQwDnaUo{FamyVzy7}SBeqk1S_d^WQ_biGy()C`NeGnHt)y}biMLXe@& zwRvufu~;}nBoCmDT!11r2a)?1h$}K<4yRrOqiz$9Gx$Jfz&yH$O-M5f)3y2lqt$X% z5w#MqQ}&9l$mVF?#dm+N-%ogeDzM0w&nYq0wP4HjtRf|#sRTKJWy?%$S0+tkz)v{L{}z{w<}q(FBV zYZ+6j&}3V&uX2eeh{4QFT+`0%C8nWSn=s?z;_9nGg$|oZ?_Vab>k`TueAVCPr4e>t7z*&FzhcHUdl9iy=Nh2};%~hF8|xKmh5!Hn literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_fixed_interval_windows_001.png b/docs/_images/sphx_glr_plot_fixed_interval_windows_001.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9a32dd75a59f2560ceefbe00354d1b8126f515 GIT binary patch literal 18776 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

(;-<6*D*Moo9 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_grid_search_withinsession_001.png b/docs/_images/sphx_glr_plot_grid_search_withinsession_001.png new file mode 100644 index 0000000000000000000000000000000000000000..b907bac35234075e0ac420703002ec49803e0a11 GIT binary patch literal 17116 zcmeHv2UL|=y6i#BinQ7oK*4|_AkZQ~M1mPa1j!kdoZ|t>sI9grq6Y!>AfN)0k(@zA zi6Tgpj3Ocj0VPU)we6m{GxyEBH8VG?yViZP)_`z+{C;sVPV=h$ufI6Z6^wa^(^^6Q;f_L3kv0s zy!?@aYUe`-+TFA?sB`n*npn!V(Q__rxw7J#*y5chEIXaOi&qME$Lz5*^)r8b^Bk{H z)Fv8mfxFypx5bU`MDIWg}5ooV*6BACh`wku7y95?^m|^l5fAPWFnvY zo?W_y{J8Qkg&cKe!-A#c$Ks!4$+rzxC=2lI*)RY9Pyd@rkK$h%RRjg9TTj89>0ZS9?qkSDm5|7J-Id3pK9c(!%dkB)q*s#6duh`e}l!PsEC zF281ynw*@RzvcM&c<^YuPmQ#+bk=tk+(|?xPQ<%wSDAaq6^`CpOvdfG)Dv=YH7kVj zBg)F;1oU&&-oAai-+eSjC(~Lx)<;E!hD(mtDhTn4h^Wm^H5G|Ce^&MyF6UviWW;m# z-7^b&TM@*cVOquB?lsZglINQI;lqcI{r&N!oE|4>qfJF~>ORx0o#{9r!=_ck>C@}e z&d%wpxTJTxx=!>r&U)SY_U+q`d0%hTCg?MAa^3Y;=Z3af>KYqI=DH3g^;Cu^OxfBV zRaU+ged=XVJRDAGpz4d->dy}fk`+^Ioc z7?lMJ7K~n%nK`)E^z|)nwsq?&s;iZf3#Z~Z-9JCcI8?6%W+$AJbZK{XUA3b(VLsAgux6gCP)_wXWTqfDiZ~5fp zWOMrTv*CY|CkszIN>zpP*pluglh|DJw@z4;2~WoTBba2w2!l+LulEil`mXWXFu~ z?)DsLlxW-Z18c_C{{b?a99J#vD%)+ERx$qN^yHK9a>uc_&>`#XSsevEZTUF`3MgRN zf=Rv^*>M<;cM zDQ5wVMHGs%Q`^NwB3n+mirfy3o3rX~yCJa!4>GqMck`QScZp*`Z`g@}ovyB;%j4Tt z;rLGb73*rAWzXg(pEL;LoBuL06n3#8+P}?xf)<#S^~Y^4SX%S!ZfNMobsKrJ%H%vk zfTQ-s*^5@-h5dib{lECdA8^&xbtWe-k6&0=B@b0O)6UH;XWeeCi1C5e%Jz2svuDp% zl$Aa0Tf1q~?!a<2i+jQ*ei=#z24TknI0bxseB9jK866%&4Odt=7+*Gk&iGy_*~(m& zOYOgN>sEx@$R`WbAOeNJhBskSx+e3Hk=%(o87FvodG~vMf4Wogek3X^9ZJ9O4i=MSLagR z<^9&OZsW$-!S+0>$>AOvHx_k7#1_Q|`_)mW66$5JT+_^|Gjr~*Ub}WXD=RCiy}Cq6 zx2{scM~@!WZVe3$ z1>8hEkc^jp%O@ZZl$V#MNWXgZs>_#mrw2AzSXi)&+lGpI%Bdt96r|g>@AsM>$U@C? z?@!E9Q&D*Yw9=5YJ$?Fi72$;Ygi%L(tHU*q9=$v>Gh^K{J2L~)pxGk^XxGU@cyRbr}-yL;~P<;z7}zG%_MvpT(XQJ*Xu6YjOOwTU=+K!JznNnBA_ zL%e3Z&-~o-rAwb$gzq)GiOZzhw2BS1=V_uCvrBtsOHY4E6#fx;WX_rK;ltV)KUk^oj<>cg) zS5*y|va;cl=JuNgm;Z)Gz}$>}{raR8z1dm=DDOW0Wiqfe7faxmUzBl`I!tAe^IyA8 zc&VtWHl&&;ux#2_6FmzqL{saFyN26+Z8}oLiK0a5QYNS5-oeeiOH52-_3G7(w~wy| z3+l&x_;Bvkt5@<Y8mM>)6I2X!YO(&K(I1IDE{!(RfIJxUb#W}Nhv9wB0sO1 z~er)7R!RAU0r;`Bh<6b3A-09Y8c;Rm>;v^v61@ia67%Tm|mGjC`_B$dNfr`3eSJb zoqfGth~dbHry2t1vlCa#QkIzRp;LPjsiK2EJylu8lkWv|Fdi8)z_7 z{Q1cd;rW+||5duoeHVM=NT7hTv~tkzv*J^mJw4&7D+Da^`^_XBNKqaq?@i z=-`k9A@N?cS%n1$s70miYRiSsftP+}CSbRewNWfamaU zfrbjAK2nNrs_t*p+K6**UQOP~<2MiL9b3gFxuv&CNY2|`PD}G#6Ruoo(^?;+$}`Od zVq?p(@TV@Z_idxA++^nNhU#Wa8S2JsbY_Sa6yFSDqWHEh`xChl^G(1yfByWrqpPbX zS_+q;4t*QaX9;LMl^tl!3PGhsLAZ1K_Srg~efzX_2FBJ3n^gQv_m*@Wte>CunO6!6 z3qwJF%glNpB3?7Ov3w7yu`K?F7vG}xH}Y=XdXO|3 z8Kk13;{5&VS;hMz@>nhn7nqkMc#VH)e%#ik*Pn{TDqs8bY;l4Y+KX84*{MFwqNyO< zVWO1B_%3N_gHxwgO^TBKQT(-Wiq`IN!AF_sCgMCM26YNObGXZ`#rSvak|X8v^}W6P zW2{S;)_iGBvq>_2`SN91aq(f`hWgDtHZ3Bk2}jYgq!o(4FPt8%6Y`lHYhMz)CgAV>&wbOZ+*^Sh&op!_+l2g3(XL z8WgyfqXqMt8jW?~!gDUaK&(w`X5ZW6Tp1R2W1X)2&Vy~u(FGXIiZ^eP z9NVa@N#O+%m50M-)T)(92`5Xp5J zxG!e?F5>y6C7O)D`}gC51#~UDo?Q?dz#0Gq*MKG2v=pIbZFlQ^pnkLW)2E$WTwHXJ zZHm3I;J9FfAot(HDO$;mjgQfTL84HgrKYCd2@HJv^{ai)$B*W7Gn1erCr+MBZ%zhY zT3W`PGcxM=aBjNc-pQR(-(Ido`xu6G_A@7ElBiYVXLP;py$@V(NZ8}L5n)bc6yb9( zmp+hmJ>}H@9j68F>UtYQMvWU(sQToOwn`)X&qvvPx+l z0@B}k@F3BlyF^`L5Oj?YqQ1H({jGLInAdkRZQJ9(Qk$AneyrPThYOcPKKzhV`^$nM zRI9E}4uvlLn`~E+cFA|@`u_$|?VYHvnwr|@IwhF~%zFOBJjWhC>Df_LOnXT+(uhY0 z;*bQqVA9ye$6G~F(UlVh+Ht;{ z`<>HQG6BNpXPyui7ZbDV@|7zmXg4=WJi?NTbsg#;QiPNO(3PTm9j9amy+PqnQV8Dt zmcuUpVSx0M98@*ec528vLA@A@y6D)`kB^P-CbuptkZMJ_UAST^8gDY;U3u|K3gfOm zvm90F+3@IS!f^W*@+)?+yiqMWtr()rQC!d|32q`yKad)3mY+%Ki_dRmwkgce! z9Q%@1%_l58d?iai%l5&VHETrdIt~nU78#-e^t*YJh!ZH#5HZx_HF$UIIC_u2YV|=hZUL#QlgR96cY%J%`5ai>d zLG?l#+SA?b#C&{Zy`F)wl6t7LfV`t^yUv`p}Y1$@BYJ$v?G z{?xN{UIffVMJbxe(XYj!(yO=WUIt?I_5p)F7#r-8ZMgwR27!C0um^*rpbrcj7 z)OB<$XZ6~zZzS{Y_-VUdUv!-oJrzNIzx@_7k^-!V##+N-sc2|Whc4@P{d!=aYJ*`l z&eBliG0D*~0(NQsJ`Y%X1qJlk+k%+}F!?_{@9xb4ux;hp$yt zlA;y|*3kc2LDclnRlB}U;119neb9pgZYsxbZn_;35(3dnGj^yvkOz9PnAFtg$6^EX za}!0>nePsw7PUuEXB-_S2S2EsJb7bkd_cD+JI%C81(TjCL1omlZ05%;)YQBiTbD2d zWcu8oX{Zi3LeuH|?ZeT6ZzUY)IKQ*VD3V8n_^pcGjyjz6dy|K@)yGlS)zx*;;>B_K z`FccY{QAC_e@tFcQN1!)K-9iVmOf52=;b@~bDiJPb|{FL*F^A@IypH7(&?=%n>LfH zKW!HEwSM>XAfb!U1|mTYt=>L5%IGXAIv^$00MU`|eaGg|p^E@Xw$-a2a!R?I_ti#0 z#>*@`?e+TZp5-f7syRBQazly!n@S{o_I{OVRCF|-m{_CxLEtxhR zs-@a76e-bgOiAP^KG zi21Tf##;~iNkbCrvSn|-b(gXvEcNBqer@Uzf+IHF(KkHu`O6n#J;gwLR!@>~`g9{S z^ezwUhMtzbI==S8!)$P+>a$byii>)?@f49kgHhChu0hBX?RmX-l?ilty!%(!e}Vv0Et)%8Rl=dktz$vsBs*g1+d2) zRQNu$z0Ld!ZMjUQClqA9dwee#zI4@?S0LjsI)!Jeo3ZlX$?Vve5|V1Txh*AdG27)K(JMlv7lgZ8l9f92=D4DsKGY*73&4-F)79X zZvFkqMZvGmoer1wBBe6^cmU_PAglepH;Fpxv%TvC)F2l}&FvHymvHmoP~pI^dG3UX zl;XPj`>8+oH(EV;r@=Y|cPTrx^at5yIZhW%_ms#0Hn&_G$!Iw?51xtzdbYR1xAm%O;7-c}!&`#}+M=wUC{>nMD)_%B{y3Eu-kc|bmnQqg zdlC1ZJ*TUsCPKkc6P#pka>*pYi8BXncK>wG?2C5TL%Dj4<`~Bh08x5Q zit7dSYCzhlU%L(xaZe}J_}bifR#9I@lR=uc>YnH&$KeME1qw}gNDkAs`V%iiI7SbYLyf~DTo&7o4XEvVG zXU4%J*lgEMQ4D##9qBLgmi#2Y-)kzpG1)K~P%Tdz%RY!4asEtyH_mbaAj=WNur1YFnN^pZHP)Fi*vWr>Y1u09nY7!)V zPw^F&ZmBKgVCEDo`y%fG1CIgG*-zp{Z+pXik~{`;juV9tg0->my)S<%Xy9w7!le^! z+jHe<-s5TE&>R&(?RY$KBFd_YB&Ntmj}C!oH&z4UhKGk!js7$!cF$9_cC$;mBtVVj zmIwDmRi*(+Y^H45vfpz4iA}O>Nl8f&3+HnCxLQ)3(B)@KQFLNsW5+jflAC?b7`VO^ zuaL5j^FJ=d?X#w6r<}Wd@zN#q{YkKn2RaJ!S_;v;>pVSkp(V>s2rvpQoEH!itz>Wi z^yE&}C=)ogv`D+6Sq-$g>S)n>K+(i(T0WyvsDeU1;N-#W)!f==Ows<&;g=_A&Yxay zd;l|^tV`+n8K(lQZg>?n-@kSD&-vnY_%43&PpB)2ntQofnu&sXt}4SrDF`9@Ry%R1$dw2dnYK!qO;J; z&(AM46P6<{AKwY+P6>{5n7Oc9TGIi6#B6T3c{?~bnzXna(%jnf#R-C*cY=dK49iT( zfNr{1yy(_QZ*@Fo5d3ek0ek^lk9VX)kRme{rwDAeZfs1{&44K0^XZdDvy7CK{-Q;T zFs;5QHGZpCRkC>T>#~M%`9G{*!sq6gezeSYadLW!b+hp0Uw_?&6aeO^UqFDSo*rC_ zxH)%?WP?O79R4j^A}Yr4uz{(p!f};Q{CeI0m|T+R zXc!`>uTtba3rdqnKn=ZFLnGs_l#G8}DG6!>-u+PGAhp0y`gCIC1n%0mwSA1Ms-E(9 zRs4Te9pP8pJumI4m*aR8GM!jpg>Jg}Rv7HeH#gyGF`b))eQ#{obEx;tgSxgHryyiL zAhnnn8*A}IPYX4KDn${psu}oNK$b8y%73+x4h=OP0t?wXn5!1BNGnIPwmz;yM7|U#zyyiU+;t2 zk6(;ajZA#IxA>A}Z1aM#+v<#YUw6{_(&HVYg)W)VU~nhY&^g2k(<#=e7P&oXTlMNneiR zo;gPJccs&H-qRNxV>YIF<$7}!RdH&FTh{|YY{nA+4iKj)fgSY$w2hc}@TkC$+HKDA|C zhu3Q^`?nHCG)SozFJ2U(GSsR&G}>5YV@G;#5zE);@X~j-OrC?p}>14zkhFg{g9br z-?}mNSy^;b<-rY)+jz1zf0o15>yy8iWQq zj+hN#rzOScc!p7ARFnnQxA47_v`AC zskf|+l=m+c5D-*v%)l~{|rgk)4yA~ zPEk*kkSO|phl&2ZSUxc^p{cEX4;{Vbfxm$M-IG!y~!uhu0}h`^<$ zrNwV<0!>4FPK-F5U1ca!vigYDDO+17Y}>Z2{_$~El9>b86Rm{Xf8*X`|E!feGB(x# zG7^L!1Oh}ArKQISIf77THM(#&xu{DQa(XX+TMbbCXL@&=sAWAMz^X1TnJ{8Bd$OT! z-VO{5gfgZECJbgEH9s>#bqU2aWDj@W8e+1DIiG}9M*QZ4?=!g{jt`xgl%$BcA7$p#20#3 z@!9F$Kl|B0ps69%kA0#@N8{n6_#Ud(YF~~Y(8qEme#AdKS0wkE4W)kb+_42fnBvyQ zw=e3RZ_M^-T^BYyZm#xkXNowmVYS*wVY^kwdfz=Hks5JuQZcJBx3Y6OcXn`iqA|il zmqQsRKltOJ{XDjt32bgxbj=!1%&cxt^vZB{7S9oP6niR65q*Ddh`e@NHB}+;f_>5| zk^v9uzGSh+j<&c4v{0QKYG1rR%h*_Z=*_8}lA6mR_t%h zIgGiR0?W8$rH+vc{*Q*0e=6_1YU7Xi>_3u6im4YumLlN5@Nf4;t#%^PL+z_Q3imW4 zsmOCO6$(c~F4YPQI|inc`}@o586UsnP5EA_fGPQ}MU&PG8K^;?YKS?#eRd>#zW#mj zRidJ_JCts2lt$VGjfXOfQKa1zKwK3ev9{#9IX&Roi|f`X-$i8gRmai#XtYyQ7}ZEw zgmA-^0Zq4H)W;%xVH!2Z#Kd$T7Bi&!b2itnUAqlm0csbwJPBKta`_}cb^`6L_8#Bs z5B`X}ZAvD5YDE;}CKw{U>gworn8gqy|1BW`VzzBDaM7*85tlTFf{o1O+oHKKp;<`9O-2Dy z(Xbh{rXwRG$>3VH=VlP&G}%yw#C}*0e3i`@+sVUI+0@jOyKvE>_7CE?JY_uUYd5V49Pg%LgAG@lZ#{sZLEJF*ED8CIirT#M4)c3=M9RGwBZmEi+A-*Kc%y`nr@nv#)S~ExS4^5m# zTce+Ce~^qeGB?n~%?9e?)cJ|1YMO^;$^s$;EfNYdBfw|oF?#4ogbPm426K8jHy=2! zOuF4FfwM9n(G`h{XVIk%@O%*u9Wb82^nW;E>pn4<2n(-ebRLqJGaTC!Q-h~TlP{*J z$X(vttZkY$sliI1(SE}!>Y^ivGG#-AfSsTmz$umP+@}H$onKJ!6ivkR^#-Wwd=e7c zG<3aDp`n|I0F5buzBL5$`?+(EsNvvlnuxfKj@BtzegFEN2wMi8-;Nf1|8Skg4WD|f zukN_gfp5Qpk&(M$6tl|ITO}7nLzLy1|DoNE-2v+%N;JAAqT+yT64Uv{jg|c`N1=4l z`Pm?#AooNBNs{JcVqR=M(2@a~b1g#&CM5{eP6YcDR;=5tjPc9BGx)QMRk1di+()wXD3{c&L`L!Iy&4ztSmc^nT{1vbPPx%jH$H zFKbU1PHKcGB=udW33f?Z<-7VvT6M!GIosQ!o-;Km`P9co=8aOcxaA=)xFnJORDE*pz`*o~Slhk@a#D_cwL9chutVShKknd} zQjT*U4HoEt{;^BOsXuixSdg7VdHnOHjb|5r-vl9t>^UtUAOJRiuWrc@`wi^OamKk| zbCs1}YhEdSiGR!3Z=g&%S++Jq!uA}f*YD?JnD+hb-E?MQl4l$HIjGHlwI!$R3Q0`D z6h)}8Iqzpm4BJc+6U&mo8uDs3T;bnBj{h4wdL*a1F0n!_M21`0CS23dOC9rSPeQcr z9-lc+ER@!~m6TO)jD>lj+R#Q($d4n9x`dVUj#^r$I%OP;#quC@SfZ*@Ki3>YukeRc zlHu5MLO;hbs%3ywVcZ;t`@_=+hRzL#6cI584TWV(dhE9C+sB40g_=qp*5{-cl~xcp zcxtTQY~c4qZzPIav$Z6mL}Q3jbonvW*GC+@WIZQ1UxRFgiSWHq)WnYAeRyiPT=N1$ zy&f}yOeG%_KR**7p$$?;km3DIDksDnRHf)@>FJX~h2I}7U}hepcg{rDx}dB$QmH{j zMe{8F6HjDj<>3?64);_NOhKfd1V(|c35kc}RKWjH&#g=hXQ#$gVecun25>#-gAmCR z?x}*N?`-0YWf6n^Trvi5XNjgvMlekfYA@oKxxHZ?wr-&uv+W7XyhAA6_KOx~A4Rl2 z7}h&6g#p^}py0@oJ|M0;>@Cepi&vpYwtWBMvU&&KR}@CFAHcFL zJLSr%&2jK8-rdMT4p}kmfHrEhDryKxhQZRYf)UUtjZF>6&|0=;CZdS_j89xU+)8r` zq1+*)KMCk%D+2{c0ExQ~vOl|oW8{4?8$Kl^rK3lV?BeII zG;PhWYT|>_4~-ogTdtBROdqqgwS}RarH%B#D!TOAohNG$Wf}!obT6J?&vZrzV42+T z=;#Wfhl&k^2pKkFyvYS&nyH|NArF-6-1i6$U0t*tM9Q&uMghDqIPkC-qay5!u&e96 znsr9M8e1ZgB%@yrtvSQJV5$8ILA~qkC){>kkK^yVujFWgiC7h z3dYK|2WZVVys;LG2er|G{*L`b3D{Wi0}DI6r)}u7#-^r>&u3B-VOxV1?{z^ZkAwsT$^Z}2wXG%FI+!`QC% zd@2V+6^yMcozVo51(c*GBgfLXE72YkhCB=nQ;S=B)uw%CQndKylNyarVi_ClS+X#O z8JiP=A#}%_evBU1(k9@y-@ca*5W3B>d4GL$BJw9>pMp1b&ZLo{B3VW*pP3Zcw%b|Q zMdV;RHB<@}B_tQk=^&BxmLw(Vv*0VlIBl%v*GQ=0PtJb?9-&|0t`4;(DC`XU{PlD< zE)-)mkirHGlV!kGtj3Oxj>c-@Z6g$8Gc_~QE7OE@xJ^r3iy1f`@x`hz!LcPM#^oes z>^OF4kqWJ8;C2*xP6I5sMBJU#^NWih^Vg8D6N%-+B*0WswXldq9?Lo{fUA0KEW*F3z06?cwYzqzpE(mz<)r0~ zC#Kx#Jw2efslDpk@Ng|QZKm75e{mwPnW_$q4%u%Be!3dUQkNd674ReJ8b5ew%5 zEz(sY&`37Bd5tw_QgsycZ02SE$Co|O^FQbGhSdRa(>*60>8;7!eK3O)gLi8`N=VpELNQ#PUoW87dz3ertMKsQ z!{PDq#v2>=ig-;qW2@e=(g3a|crPT7fPP1gcIeQdbk`vR6q@;3kccP=r%&cklA03j zP$>WhO}Dll9{pCz)sJ**%hR)$5IlA}+^LP}1fFaij2f-k>H{ALhE)TCa1MvNDNk8p zFOXJ}#B7k-D7m?rzb~&d49O2hppx|45JT@+P-#9HnW9rxv3++5?t^e6lPaQdayno1NK96iQ zAPf*@Pr2L25=*a(IW=gg)6|O8c=T;(OO6c2q>L z8Y(u20E#Db$I#3%U}vk69M73&6f*C8CMykXcNxp896NReacz^dHlO*~hH<<4nA^BR z-k>{o+G_SuzL)`~a?gKz^yu+pY`xnePr3(UlS4uybZCl|of;c$G@Q3^L#c7fOqYZk zA$iJIvlkE*=bzu9t-gHKszx}{R@89RqYSrYdO%-MY{Ajl%uG=(%6XRu#cP&?6#y)a zeH(xoYS1hh&MWb2qN%CHLYAgVAA?-o?@507LO_dRPiM4dC6kRgTwFp3FpJuC=s_L0 z{p#FpwaInZwH1jdTAa`P96WX9JePsdHZl&z~IQd+Nl(l z0G2R;y~^f^H<>6;xnOFym0;1Q8<(%4V&fD!F>XJ@xSVD=&B`Hm60y!0k|`kBchaI_ z-!-=d)+gCXHQ5tF3OSMQ;g}x%)o0w?vTIf%v{Vk^l{mYX}Bs>|acI<_(?C zo+A&q59Xc_j(usd7_eB(_=-7{%!JWNxT4slQ;T9QU}uLtb8h9>*$D!rj<6NVkU{r- zQil4&6?X>C%+69#h{+hAksXJd>C%P*n|Y1W^6Wayl92Npk+M9}#LG-6#Q9H9S4@xh=5s*s>!(hY(}HQ$O9V z@GV|c1ljG4FltheyZ;7E(kwFfvr@37_A^o%WWN(OFOOj~t$vuy^L62Kky#z?3SiwD zVELn;=yq|?X=st4C;g8Dq-#-GV#xpyrx%Fi{q4G8eM`gg?IloY1Oj`emlQHnZ23`Q z)X$&KuF8}4_A588#RL^GF1xiqaRsI8-M`z=S&Sus|E(-0ed~Yfe`;Y)#>O@(l%X3H QKu#=w^wg20LuW4jA6MsqfdBvi literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_grid_search_withinsession_thumb.png b/docs/_images/sphx_glr_plot_grid_search_withinsession_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..89fda7f60b7191188b5bb2f93680552e1c4a0ca7 GIT binary patch literal 9276 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_learning_curve_motor_imagery_thumb.png b/docs/_images/sphx_glr_plot_learning_curve_motor_imagery_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..d22da1dedcbd0b38fb2ee98eb5ebaed9400b099f GIT binary patch literal 21333 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_learning_curve_p300_001.png b/docs/_images/sphx_glr_plot_learning_curve_p300_001.png new file mode 100644 index 0000000000000000000000000000000000000000..6dd4d22676d50b9d2aeb5aecc42579f41a42cebd GIT binary patch literal 39868 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 as7Gp&4k$QX8l>Q7@6H1n_tlPH{C@xtRt@U_ literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_learning_curve_p300_external_001.png b/docs/_images/sphx_glr_plot_learning_curve_p300_external_001.png new file mode 100644 index 0000000000000000000000000000000000000000..ad5d4a5c96349d5a9bd2496e06ded096105936be GIT binary patch literal 48265 zcmcfpWmuJK)HMt*x=ShPQV^ApM!H3m4gqN;7Tq1vk_spWCEZ;Tf+(N}NFyNK-5~kR z<-VW$cz(R!`}6(b-s^zHx~}Uy=Q-z?V~n{X)gCDl;nUzF5D23CN^%+q1O^iVffkR8 z4L{Mjj>!-I6LFQ-bJcWs=IUYU{1oxf)YZ|}!PVBK|I3WUe&=(QtTQPFl zoNd)BcbV3kawA^6h`_4N)&gir5vwB7j+dt!9$)ELYmq%ye7A^d3e zE*^pZUXt$4rX&9QDQUk22jc&{;~Kscyb<-5hhgady;DXhA>;pxxAKb+hX-Hdd&ch} zR8Vcz$KohVH@~QAfyhx;z`mc{uGT?0uOc;rFS&LFrw~`RUP6 z@86}gfRf7YJGOLJXaUFC4quN@sidTF@K0(>@`#H2Db9j~rGm|j@Ou5N-4>i$LB zZz#t?=Dt1}^mlIwY0G`PA=d-(?Tvs#-&F7s(5|yuGq6ZB(S5(}M_%C@0uaUXQGrtf;6T=PFQ z<>smeEma$&2Gmh4;n*=M?__{;*59`1oJ? zG8F|5bF;FhQ#>Yv($W~CV`5Cr&4XXED$ZVTjF} zT%I3oA0359M&cC}75&P7KxI4C{G{-SsVOrHE32usH68&0fl8{_wS|QR8au+jsdDo2 zt?ljD(YyyWN0UAzbi_DQen%zWoENJR_V+%ib_pvk)0( z!zWL8t^3&y_)CwEJ>f*GPt;%CTj~vuiXu=^QBgBABt(oh`3OCK{@ldYme9b!KqZ+6 zZDnPJW~B4y&#&{}6JTZVGt_X|+1Ux{MYS>|mwM9_Jw1hO?d(k954gFxRo>psZucoZ z@e=dgW)gK<#eAt0;=VD)eB*|~Qd7@60Rnq_ds6&RtDypl*WAX$*&6xw=ABz{aDq&} zgy5Bxl?A4x&{N*lL$p&fhqN^k(DhE zxb)A;%F4^7_4f8gM?hGXJI=^pVqvv@`GRg%PTk~v@MWegTwt@cr-v9(=DA~bAVPUZ zA5-dxCVuSV;-3GR@blnc<|~oY8yhiq3~H>Z624pLHG1;;`uV|6O&~-d@>m1~Yfjh` z<1Ohz4@1OqU%Yrxwb(``|U~ZwL2>B1&JVJ zSN#-Y=~_#kG;Cj-Zpp%KhBNxNq)P`o9~zJzkzx;1dx^cND^4t(AmL|wzb- z90Wv!TRCnskD>q#x*%tlNn9EgU2jZk}de{~?2q<>&wXV}1@_0J!A zcGc9cjb3}(+cUDo2b4qS7u4e3{9`qCQI{7-pGQ9jNJ?CuxjtGC!`|N*S=KI(A z>}0Jpna`5g$b04b0di6;&Hv;k1Y-Q_*I}?PXo241nodrzP@8n zwOMc3o2tU~W@P`4nQS=m(~FCXp_=>?21q{g=BL{;ZEs^@Vou64rV`fIZLtH-x7$df zdE4;`2(G>9dJ5;$f|!_ib#5}?((jp_U3a2#cB|h|_UhkrSmWOZYa`bXP?34tsm+li zB~Np5av=Lh%gf2}l<{=m)0m+)9m&&qb>;B0-g93DY2jzQaj zZ{H`s7w+O3LPt%_cfX9KSqSOj?m$s2FF-a^Wl za}-|xe0g5#?ISIX#wRHF40e3gPFu3~`}glOOT{M)j1sg5|LYQ;lF|)T=5#ukWN;iE9es4V zHMqLuVdq|KjtSZB2mJ>3J7(tQ0vG216!bR~qNy`d!?vqd26B;N7gLuPI8p*B%l8?5 zx6u$Lmlx+W<4ui?qznutdlP>?xyh=j#h;WnG~5d#rhfrP90xxX9l<{w)oF2eeqkX4 z4nbK})z@!PRMkBqc4Pe8o?mlhe+42yXU&B zR!qhwB~YNQrx#If-oYXyqy!HiK0-7t?OpSm6Riy) zK0dzfSR(V~HDqt9I4&-33xr5@&(1!Fs+?R%yH{_TWE_NR<6h4_8iETP5{76&yRkfD z#`gAhQe4c4xHv@!gPseWn8Y*4;ql)ss+)~1EiGewc!Y#HvhF81uJm8Gc=ilk?IFb) zJSGG!f9hpf84m|JezEl{$TFzYJ7~P;DdxJ;j}^@e2VHwE_3Z2{J~2^i?KGb_u0yj_ zUY#?kv$r?gkW29m*Av%fK_d0>sep~KYFPj$gK-<{>s6aWkR*ldC)6&_uI_#W*dM>7 z<><)s<;xfTi-V1E-NKX-mB%NC*;!eET?;l(`<-1~Ltq;;G&Be$YD-H?hid={Wi~d_ ziHL|G0$;qqzin8jCQkKdc$gAWE645Ia_Z{p#hVNF0SWV}JbXw-M@MLEY}|Od*&ysR z8`4v=xw%ObS6oztkUGCnE;yB7)a0F?s|SgU@X04vX}E0@JG&UjHW_tw)Vd{xeVzjv z@0)cjA*G|R&E}tma3}z)Db3mk3VFt#{UI$59D8g}OIui47LG42EtxO=eCz1w7+7A; zyS~0Y*c()`l$*2l)Zbs?E+5~}WkHXry*)94;w!%^*`e6IOiT}d`h?N*N%1t%mVoJ;|lLCc%W!)U2Sj@Y>M3gmCB zb&(!;b@u|=^w^w0!7ZjMk!2>W=v8*(ln@{2>E1EtfQ5wJR>@KA+y1^QR1Pd@X=#o- zcZ&Di(z3KTc}-dnDZPHSwnaKu0#`S6NA~PGdlQ<|vI}0S%c3yO%a<>=cXp&*UHMUk z9st7r+DK_nuie9QpLfhhV+|e-Y&UM0wS^H`O*M<7>ay$R#I?@=3Y$)plpZKX{la6$ z1_%(Sk^l8igGXPDox#B&Bp-50$}eqgZPP9*@0=Z%dgzmrlk;+2&){w&A|ifuzG8i; zq^75*cl6#I%@OM5KMg{# zwm6V5BEFf$3Vp0z~5u+?Cf}+Zqy#+P#x^-pdkSD6-piqXQ!tloSd9cK?*f1 zZ_+3&pY4`T(XV4yh_h=59*a)W+Xgj+<27~zxIL>~zee7~#gRY{YLtuA62AmcyF5~w z*4`Wvf?1q)jgb+OdMnN`)CEUCimt1Jc<@;*5KDu0kR)FK)}2M&`{Bkoum71RbS0YR zKN7f(HveFltIQF(YNK@&d_|X#kU;IvVZDQ`HmkX+B#CMq58@;^2#y&2SxQQj%o`O7x{Sb>!(gfzHm_s1-H z!jB|`*4`MA+v?!WnEFu?2C)`MK0$E!3M575cRcl3iQpoB#S(Z!3oHEP=s^g`h#2NY z!!B#cJ@K90-RICi=@jc@y;TWg5cfu?Vch@}j%tVds*$=e)9K8oCxE}_Dtjf`;DF`U zK7^j>XLt9`!W-jNv4Eldx`L(Um8Dz>?fl^9&-rr*Ymg(vfi_LQ0QGNoaep?MYWCCb z(ALp0>-iv3-JF_HT1v*MF#RLxmj2^d#KviWJ}T=uIK%;XL8>I3KwItv4aUJ5D$QPr zl$+Co9Y}urHb3qb2gk2ZMu4OcE$P;J*REZoIfAY)8d{%pK!}d6u9)dGL(sO7U;JHS zES`e~m-$T>vhk6hHdd=@iI6%6`SD6_TGiN#Z)Pc)1+GmJy&pt^;V-SL3iWZGc81fy z%9s8akemY81U+6->%c0mmrfrpE^}}G=gSM)T8F9OvB@SM59nw|Rz3is0AbytDtR9A z<%`Vz$^Z@&-EYwS^V*K`q##xHt>N&%c@XH|Mpx6ljvc6L>_=fxYabdKiZxb^42LVv z{K}Bk&ksQ&r(1&H{^jBr#HXjH1K~}k-R}gb#XKF0sYFK(efkS^xl!#dy{M~NK>v8X z3+f%kkofAa8Hi5NXqr10a=^D zDfB$vHZ4X5QJAV4H}wv7=+!blAJ zotT(74J1}reSQ5&x04%Gm6&|Z+*x>JC~hrbM6~fqNue>cLN*g?X#p3Ju(H}IcWa7@ z2uDhuv;iFvdwR5mES|Bl0(8ARR(%V0CH(Bn7y1%&cpA~*wDfeQ^|5LKsMek<*>8X& zd%-LlHVtHqyow4T+(ay}7_1^9*B~z{Hn?x_=M-L}rOkZO;67T7q(T)rBoYbztkKfD zw6L>t-E8;`E)kKuni^?Qak10InHMVS!TKu{_sVzjWs7Jykjc=fx>Gcy@NO>Bt6&4#TCyYU)cz!5jd z@gJL*q$_woY}c~pgI4S(6ydk|`8NqjNGu^dpD{2nhz_{Zyi47O5@Z1!%QGl`Djei@ zVNDOAdRBb=_>tx_&L@o!niFwTl_Yd3gb(CTftv8pP+r7sF0PVc=q5fb9o<*Wohf#P zU8iJV=(&CScCr$i8RW3rckgPjx;g9X(?D+{Tv=6R0c4^rgu-oBR@qy{)^^QrhHi3m zTTc1z5&6KvCd0j5#l`$NGV-PgXr*;HJpx8s*3e8)o8RW#0ea`L zoE&CXcei%HXG9s)m9@rUNUnM&CQMiHLw}Bqy^CR#OwG>D&OcgOT&(bz@_SQlJrEZ8 z&Fq<}X{(Hk%qZ0S9DA3YS$RR|lzO|2P zs@Qknr;??ZetB+4q=daGKe@bEg9aP^#hvUx#P%s;{vdt1>nA-3dK8Rq5P& z(WXZ<*MXv=y>h&~y+8V$9v%ZP^RD3*{0#ZOOm+DGBU5cf^gm2?*7skK&i;|wS>M$V zC?*^}(fY1d#4jo3>?@E{dHDD+!rQDjH~(Y2`)^a516mBKtmLbk7>l!1LztyUM-$f7 z*9&+E{m);M0ojGn)g94iR78si`uX!GBCok`adEMGg7&`)yi5bc~pKb?HW?cQBHxpt(eM7yDzafkEzc>4fCLTLSjRW%5y9U~uVdUdW06}VM zW+w9u-;m?o0`y85Sy02zVnMSNPZiG=j`)~OW@S87{m6gc-Z+n0t zU^kJ2$bYNJkJC<_tX1G&bemIVAvDS)TEM(iUl3m^)g>b%12Pphph+~SnWJN4X06Y$ zRvBO9=9)MO(-j%i5~EmmV4Y`xXap?rWbOkBW#p-6ngEXsi4f>i@}sS((i#%gN3Fa2 z`(NJ}`$yi?%xU@glMosnRMlN|Bl@?cIX50CN%c(YX8ioF?qGiXdgtF>wRu8+ii(hs zXX{V86VzB9q&-{JtMUL z^9f5T$yr!TjPBX9XTrek0U3s-si}$59+Hxhu#c?2y`Wg`&n5tVJ;Y`H~e_AO{5EHP@3D0H1wST!NrffeZK6O8(AKX;a zr&x+w8!uj{kshF}Uz|uP|GvbeLGwa$-5ArJlb-@k9=d*AhrUKw4Qufd8nk-n1$<}~ zaiD2We)sMR=q?Zn@k(q;Dk}VSs?cm|1$56iPA@M$5hn9 zj?Gh{kH|ZE(v1E)yX)aZ+v^wwDW&4X*RNSPIB-8-oD>dA+`D%#xOdN0=QeRTMz+T9 z^pStZHlL`ST2K8YXYpp63ddbOZDZZ@%VngFo>t+W&e8zpKB^!qjl|-$UkaD(KT?WfCneNa^*RYh^uzD626yNe7}NH zY1pnXGch4hl$}-OfAU&P0AyS1^>Hg+4NXll3W`tw|A1aFAl${D^?b;$J%1FAV*hMhG#Nfc6(>&B1e0IwIl7-j<1+v?Cg$T%{og~d;GJboIE{Q4_AM;ncgW< zR#sBNMKQ!hk1Mee=~|pKi;H0>DGI`1$YyJOJsOZU`Bw93iT8K}87pW!(eQw1YOoUH zwIpx2jZ0iUzle&03J~=1BTKPR>y=1MU<9|J!BJu>*b|_UwX))X?jTEjEmIWaEuW*! zZ)K)!G}Xqv?_ZzMpn_MQ1!C89W-edN`*~D>ie^j<@+nqHCadS8M{yS-1sCGwG3L*( zA>7-O3wk;-Lzf41T`?53az1fKQm;u0XG?H@)@*TkgH`zH=v$bTdK&^VP@UrpI-t+o z$@T?jGD^xYK>aIX3YC@3Fy}c1Ee}Y%`Ph9(yb3JjRpP8J<&7k5jmv`1Wy} zB6me4T7BcrJyudNd?q?qOsYo(WJEsq98-TZ|0X^5_viRihw;GO`1z|nNv-Td(`l2* zU#h^W)-#q%%kGsO0`cZ1zF=zrShTDW1Spg&P351*_#X! zA$Nsp@1J}ji%P@gq~j09Us5zScpTJbm-<2Z{_kwhqbb|O2zrxD^Goq^jLCB$T1oGu zFXNL{-%m$gRp%kT0y8MaK=SzUW18{GiVDcNd3)55IZ-hS0SdU^(cQfrk_yz;;v>=5 zuV15ddB`=nwcXGOkWx@&`x}C^DI`>@KS_qF5)t_3gzJ&NDSmup(K4#T^`Bi$XQlX!&h+{}rD0GS@AEM5TEIb&HqSURYbg zm(F?S`Gr`Hmz_I*n~@Qz!$~=&;u-Q-Ou!KUpA-=lrOEwVhcgNFA~$GA5k%Z?->~k! zB?R`Y6{`P!&7C`Ur)5cY62noGV`NzEVYGUD$Qw*o+MlEf{T_5sX;+AgLX$5bxu?BrX<8XsyN{T>) zl$I7b3kwTM^2Wr$F+W%x0uiwdP$cjLTJe!0?pT#ugRX3n`_?pQC^KR z>3BIaZgA-X=u}~Z*U(8wNI>kL2G#=u*!9tJ^Y;r3D3rK68-JaR$?_Pt>GuZ<-4Ygf zHM;R9lOlvCU#og@Hd6gX!R3%BTZ03}E*l#yUOf-!dD^!-LixAl zyvlaZ=?z)`1koFRAi6a*rS5p-M%R?|5Uum7{=_W{ptd@{e{cN~O7QaS+sH>LqB9^v zu7G@b+!FyBtffhh(Jg1J^T6V z-oomN{E*+terxx8p+fN~P;+PtkZ@(COdp23*PHSZ7Z%hO7iHeQ$C0-u=Hxci8hMeo zGx}2{(c#bVwBM}0fh2{R*vscNHuE2`N^7ki!5NEaco|to`?fAkGiTD?;uT)A@OZk* z_P57s_zdV)Q%X&~hgF^b^%7avO_Z-EVqq1ev#?XWXjE*Ke?*+< zo86AXkjs;pm?o24Ka-l6cv>xJLjQh`dW`GWKb>;U+P_+pT9rN!G&>PTN4qeUDU}R~ zguaeMVDtN0rm2(vGYrj#e&OUy|AottO3bO1N%dnwjAL&XkzKKJ?A|CxER5R)7zsvKIkKnfa$-t2v6%{}>G=byitx7MGM; z58QCOg68)sA>rT44GM-hoCgmcpm>(jrbC)Z|I-bc%2&`gnhh5{P8LAE9&QGPq^+y# z!TBh_LjdW(UVMYfJH576==Kv5Bud>zfoOP}(DWmSe14o9Et$u9S@>+u&KaG4{46gM zFy!qg=QiTdiFEYGCY}s;S?pUS_g>0rPt9T(IrNclE+x)hmP~#vPegVW`XX58=%{}$ zwDe>bEe0dMC#q^rq{^Ww5vV1-+gcI%n2j7Bz9(R82aJy?P&6oX9L<>BnV`gm@+D3D z`BNw^2qpnoi-_px!BGkCeJi*;Qbxu& zfIf7@L66;3URS@c|ii^sSzt$diod??C9(3 z>+I|dtgLitDtU;@{MAu~C5VNa@rNQS*^7w@MdU4KZE5+T!$w2c{r5SmH4>Yk2PNOZ#DBBYt7=#wN}>Hf9+{bo>vy>SMGP@+PLv3XR_sd zmaWtCae@5&aA4i*rMW;1?6xQ&54TnQu3KVL90==Y2lu;2s6{gE$SmsLkh95W@2M>35lw!gIN&qG%rU|$fj?eab*9OBm zfe>2V^YQU9?~G?&p871A^C;y7d@yK^hys0H;JUtmoePzAKna>jP?g9Zsm5cTmj~kv{c{o9821FWQyM+lobfiP*je*=$nMMEuS@cvTFK5=n~h}B#--Mme9}VEGVtZ< zB&Ec5#dcV2sF2uCvF-1XUUj;jwe53$cMLMCwFi9T&x+C!S=WYc2pCHb;*_1PUB0sr zcK?xhbF|JWQxx$V)PEo#i;{wh@~f-|uu;vcnVH!teV|xO*Mb=cWYoZ2aT(SHPEVU4 z{s96&G%dZoBv)^!w7?nQahMdNA!ZNZ|Fl^2`iVhN#g!k89nx(HQRM=|I`fNp3O6mf zg-KGoutpR-5E<93MxR@n5154Rf={YQr?}{_O#v~j_YYxF9?{jhe(PspqrA?X&!JB5 zXpxvRV&gh{|AvBDRfR2^zAI&Qe)!c{37nYy|`&$)=bTJ zulM89!AOdNoT2T zC;3G~3rOA2U|caMgs9HleOesm%2 z7${DYkLI;VvSfZtZ<}|~n=n80_XAz12%S6wuB%P(qgem#n*E@Z@|4!r=MD8Zua8b> z3b{-AMXt;uf78HI!VeWwPLCTu!p>?B?h?6yD~|s@!VIbyP_gD<3NeW`1x>%Kx_Zdw z2>5_m&=!0rKEJ^KAmOK<8P)~$25ETD47WY`gzC${Nb!~cwWgo4hT8>nav#KfC;{(d zrN5&Tgv24IsHh3tmoUR8~Q!c%Q`+Nn%E zi{^KpeO88Ov{QP#o{W(x$pcp1#`%8A(i5DI#j*L*)eH8UK@@&Erpu}7fqj|eKk?C; zHya3xi_ez5hJw-KpJm-H`opeRZD-5~ra5(-E0C&&em^_eU!fMTNj%vBYbVOAh$8D( z?TD%!PeC7B72r@cu5BJcIf@W@y^QqqMD>OxPDbt2Kz2gf#~>hx@_qscH&v(bW__h( zV0X`kiMDj;Fw2G_K_w#=O;K5ywY?1EOErO}e9pYGO01D~1q!9n-vyMmx-lAh0D1>f zS9cph5uFx$+4mA@+Q-ItyT(GbbVP|$Sw?xsuQSo@eMv{6Sm!NU=F+m@q6y+%{Cl47 zd{}-?5uKmWPupvbFDwdxe*@t&d#73hQ*sSFV<}5`SWMj!$j1#r6{zP8#wL<^`t&*+ zCeTjYYRYSB!Va#!6-AjIK_mj2R=~>GeyTYJ1BcjTve8Sl)PNC~OE4?aH-h7Wni{v> zFcu^s6X1QQg&ors#!cJ8OrbMRmhkfqHhd2>-=K~1X40)r+qJ1q@dAdCAIcOwqoZQP z4EvZAbXTvQkS8O48J4~@Obp5TB4?5KOe*rz&|~!%?ga{KeGZez!-x#NoJl{|79=stcN&~IC zXzt?}YF>138&II!qoBGEAL-yRa|{0s#))T$4QG>JcvTlbdv-?mfFQ-~=3r3R#@tPH zI!#TQY%7*;sqUSHo!E%&=#6*vLI=5Oobfs*QcWC<&1(X}(_f-3Nvz)z?e5+lYQ@%E z?onQ}b9ixaLA<=Qh0BdEntBbkF!Oc%JMMe;49*uDa`2a6;S1eAXFRUhuQsT%A_MQG z#V--pda!L)pB7TS*Il{<)UdxvKuj#SOcz4>k)SXyaDU%giI_2nUxH!x>sQgVsHII} zX~*r%^x4S1$O8GX;o)gqOrlXAnSx>D#E6oYLD~V0FBfC#qLCxNyP|v~(UpO(N=jrb z55AWk3UlA%JvlAR(e?UW8=W59wUEdD%Bi0G=ST?Thhf9~zhG!`oc)RiHtm5#7D#89 z(Y&2kuMTC>^$+Btnkoz;lP33Wg3q3B`Af{KUwW&1YPYDv1);2EUy8?tWS4BG#Scfb+Oa;H0ePWbg}go#=^ zXTj@-H2n!{0t~rL#Z%ry2IdBC=`#n*0X|oK<`b2ij-OGwf9U=?G&oPwJ7;=JAs_(9 z?N{HcTs*F=b2k@{nYS_k9KqYpv`jZ@k!GbmR0s5ph6g;q{X_`Ak-!giuT3$gHzU4G zZwRDKm_qzynejI;{5xXfry3N8D(+|Y8E-FnbPlJ=ZU?N5WhhzfA z(#)SXUr%pW-~ReXII55YUwuI3nFsCFq5Xox*lp_>X`K9f|7HW?_0{I7q`cSjY;1;J zW~x22q;;hmX=V8MOAS|6mU(sPs^P6$G3Q!$-t)8N8$O?BA4alKU1!Zcmf%csyT$)~ zX?MnSGoR*nnbyPXUH+rzol03lg0*rl+JyMXJXi^IH3)17MJEcL69*_(Ij5)3$xHo{ zLo|qT)PSw#WD6&ebrxo*=z60*caIY>y~pgiay{ZCOop5WKeNWp#@AdP9`y;iE~TV; zr>a1~OQTmty$3Xtal^KG3WA2+hNfSKE^By8;exdlq#mqS-)Pzpiy9UeJ}1UG7Jb); zJjMD?f7vCM*P&!nj4jB~p%<}n6mUv?Pb&vYx=xF4dbBzHZrH#4wsx1lKW{t#U4^6{ z%1-w#1<#7k2)!|SsAV6?_hg!|mP-#KM4 zfgM)d-}8_|;)@zt{cE$lX3Bpk1Hpl~e@3Q6(jn_U7iNm{B81d^t0Yzb>HLPgLqWu& z{BJk){G2H8v#?g}7IvL|UH37nD)zq>^;FK-U(`94csD7izxvd!AX_xDt)ZHs@i4Q3 z)Mliq;E{hm`A%(xwsgn2F9#A=)UYVJZ>w*gQ<5EDGy?yh{$!-Ii$lT`Bl%JJrOz3r zUcRZrdbF<}GvP)i%?d6tc88uv5Wh@87G>`AoH^s_ogR&6J3tFZoyUsF?LrWdhRb1D$J4F4W4^+AD5;Qdwd z`hLw^LN3fskg~;pFyrE*ha3AneI~PipF^po=}QBVa|!zhQVWZY_y#f2;j_yz2HdKiu|R zAQ_MR9Rt(EXstt9&pDV0lR|NQFoUI#c_}e zEH$ZO5^EtrRvVR?Mts~=rt_-GnQKIo4sW|E9WIGQpB1Zbfv9lb(Dyw*K#dm2LHpQz zdEoH9i=3jsM#%yI0S(l_a*Sj6Z^Q3 zo&3GW^mB@A!|-;?g2pfD)!c7bOweJ<07W-kY8)3IPg-QuL<3Z_l9EzjQ><#%;{RXS zf(;!5W6iZECo%EKi`tL9>2e=WNfwKv%^E5Euq7W6SywU1agcw3Arr(j=muaq{Mz1b z25qm>!-ptdg9kZ$yU4I!W3CP`#VnYc91$Cib%UuLj1pm>Z-7}WV#GLr-d~k` z{zYtTdkEgu7HU~=$-$8k%LQI3o=*IbLw=Ktqmm|v)Z~F#EjP%-QZ_e>=h29>+h-kD zKhwM|vFRH6S*-p%ZWjMq>|{@S#@buqH;KCDzf3K;`)l;9`Zb_W)Yc`^cUV*h!{w1d(t zVa!POPbswhA4J{od3kxEw*p%v94z%I9On7o*<6^%R*ACifA6OAr?=yyt^ zg&Q9~#_=X;&hvzqPFXx+{BJGo{D&tgp9DL-0z0I`ZL(NNoaKq6!{3qu+(%`djVE_* zE;GgC0IB@{riBz~BM|21=5&(&jXg`YoIv_kW}(0IaJYlx&s@7njmwo zr_;zMhck{GE#2%!)5hcnZOXOaNaOlFCj;c z1*S(9bm3YVlI20yrU;v!oKD+pYKw8)FW#AGeqG!*_M^1jeduO>{EU^1;6>BRP`=1| z0c`pj$fC%lK>v%_64fH>|t=8 z>U{s+1%jIlrsyt=a&vM%LfTk$hqVLtK1a0??RY*xb^AMe+F(O(G_Tuda(pb57ZC5IF9m_xo~{lu+}m>iFJ zeR#u(S&GqtW`QY&rIv;2GKb+y#-MEHZJ)eadK@~;F%O004n&BsJ62jpX*n@2BI2*v z&vmiFN2OC5k%S#roE?|FbEKuiWAde*(8WI|?x)k<FH-hFc)7g$dee$*zI>2z5~4 ze5jS~ae;jkv?u#?qg5T2mjX6EvS0(MvKhh;v|&R@yFlJ0i@I^bB$T?AR>;qvDhC`9 zK$YuP+hDP>cE5=OI}57&@`rveSls7u8iGsPp|Yl?#3NvDcQ-yE0R!wKh!)gf9vEzk z1sK7w4~|l59uuji()&sevOSMUUsP2sZYrd74)ilnp^LdsY|8`|>x*+?QeTk?McmJP zdDB8T!HXtb!^}zK^h)9{$%9_?^$?yTo_)79l6zP0#rSP5GU!dNA&Z*plr5EwjJt-D ze|x=FxW4}`@&3H4Db05m4}Q;MKOx+Bak7T`OPFtqg|P%}pCVvfMdQ&BaFD2JX_2-_T-2_>1Qobc zu%)VxeSaqN>OU@TKAt7`uP+4vz;>luCeVYZFs6kpN`L@OaC^%Pq;IX{h`K@9hyX|G z>lIg;HbTUhy@ikDk~^f1$B%XIdC&Y`jEH)@O{Pp>=_!{i@|I+RoIIqiPWa&cgKUjRcmX$;Ic6@;LIxTd zScl3idl{l>1PY9n$nisCj1)h5(E8Ylq}qC();vroM*<)@hEiJ&wH*4B2H8A1W&=$G?4x2Z?rm-U8*X2CFmy$hcv^ zRxq=(<6IsET!up|UELV39TDz@c?TZfW5@ZWC85qv0_H4tYV&yZ>xBepI;mn5oxAbXk1KTdqdGDY_1Gw`>x|dLxY35xlgO#QG2)qdPwh(t zs%IJdr1wqv?Mi#i4c@03BC+fiteXmykEXf=IF|EhR+i_bVVT~-GNB{D^$5;YDe&E* z2BL-vbu){KR8m@P`m^pkIys>{=LnQJLmD^=5X?j11l-oI!d1@JU`1*^T(af5D511k zv$g*vv+vHexb0zmj4t;n3B>cCNa3#kG~^d4qwguzj-UEvF2 zO9Ov`R5gL(2h0MplilB8TVq9n$5}GV(49uKrNgVj(%bq&;+o?sbg=-yz0-5siX!S` z!H9pISB_396>!~EN??~aKyOY*hW$Vh4cD5hn=Fun0G~<3-B7&x$Fxk~;b8%JeMSc9 z;VM?DTh|>-rBq3cdQ5h{N3&|H(uQ44I(7y^d>#zS82B7F=&32+ zmr<%T!^g7FEiG7eMgiIE2i4q|)X)>V+pQd3v(|{_Wg}-};u4@#9EeSqG0Lbdj(myd z-Eb%kCF)qe#=dN%AVWUFmsq z+bQl${^L1%aO_J*k1DrSnC`ptVw8m>P?GPtE zAsG#t9=I_y{+Orz=jg#v#Japff--3}#JJD{$5X+@{{Gi`bHaLgIcL)?RrWA*Es*v+ zO$mLq!kAqtP$Qe{Lw!;o-l|?Cc|9QIBtvc1U4ggf`ofHivjo>!(~Xs8owzM|;Fah(zmtG3W?{6_`FNdt+L!-xdW)xiK|CUZiP-5*X8 zB8*h8v@_{K7qBh-eX_PUJ8h1HvSbp<+LKqdg?Z~D&bBh}8CpCEdvqY6h+WHaHX0hLWl&--%G(N0i z600`SjJt;${3g_+sWe4fD+6DcA;#H)iuTY2Gtb7AJW-owqB;Ks@zwqhs4tI*w~YSJ zQ5Z-;u`(I3z*&LQgkBOOkVwKuB+A~=kN$B|l^osGcGPPpWKjE&7x9H3X?R_tp2h36 z0CAUAdCTyg4=Y0L;;qJ-VB7iK$)qb9?3_dit6FGERCNR z_}AG#GP4ZvB9xM>^)KVCDIPe0Y76@sP!-Eca#W#AB%yPgU&d1Pmg`Q1G?fF=bNs!{ z!yrSR#$ajr@FkKpsrz)D1VR6HJgk$;==u7OAyN9S>Pk%tbQD2UItg7vm2hNeq;R4$ zsbc@EI_Cf*W`rlpzT-+H&k>rH<(%=F(8iUw=pzi|v%arvLgpZl$(7qy?-Kkq#H=&O zhCz$--#vqmzS==9#cS2t4jCE*8@rIqmW+c$!QV9emy?a^^=*W-J#*^3uZK zOC3JK+!%^F2SY6i+tyBc6M&h2#OetA^r)$HDKMLZ?x&TD1d}U_vr|EbFfc|1f-yA3 z1>Jr^Ub~Y+3(ZIWs?><@OU=M;_BJm?~)!^q|KSYo_6P4JV#o_!N)1q@>rM5j@jTQdjx0_OzhT-GrOp;l$_cT%SAG2)6YpU(TdE(HPXC|)R@Vy#b%B;)b z#Mgwol(6R{agzj|UM7d<_Vl!qh}D)&5SNi4?rx2OkM0B9Xq!tHEp1oNZK0h`ZtY?` zG6Jt-cMU2|Q57R$^1v#@|Bzst6q7@v%}bm1|I2`F_Obanxwy1}2csN}tkjaq#W!Cn zmHC~z*Nw#gz45^swxJ0VMRv25SS|> z15gyGG`NkGg=>wMtbw;uZq6}Yb?sGfd9|p{U@7CzXN}`Z;;dQrKRo}Zl0JUhbAE)sH47Y^nOAA)dp6va ziF&>(SFe%*um^7)1_G4d>CH`IZthZr&&^Fu;xPI?1IAa-%gmR5W#AGLegy|W%v?uY z;rMlS_BrqgjRHFY#@uL7*rREMO8QO}l{7UdsWQ)M|8R^qV(n(FN?scdN8TsUzu)yz z{asLiCJ8gw0qHKAm-qONuo&jOFs7g82+?tzppIgHzbod1H|w9qY0MQ|Q0P*p(u@o| zDl+0{ST@BXxccKnLCG8?c=EQFoy>BgTKT(=uQfN-(M;_>{>>&^1=?RLd~3lFS|^}w z9YT^_}eY*j#=e7w5FsLu1h=`5NL4=42S=8ER zxDHTief=7kM4RfTNHw>;jlD`?t<1=HPU=Nbk3i6x8{7s~o$n}b6SR5gbWtdCqO-xs z&cK6@gm9ZWP{Q8N^k!92jomZTP;cd-(0Ska#AVg4Q+~wXb=%hnOvG4~`ky^O zb)fE%0BA?K4q&_p2N8XZ4;wX34W5?w7Kvf;?JX8}m59%R`yakn^E!#X2&1H&#>b>N zkldf~z(+`yX|}n&;(y!t!q7t3LdZjCRi(OQN02!C>#W|1x>o0{{Td3|$iA*>5^PUG zsap?>n;5GW-Y7fG_&0m&YwI^(xJY!5X>D8e)e#x()`V3i&8#WnG84r?u(>YItms!u zo^QJ*U^2m!FN|gJpe&H>)Yv2p@I50NgJH)0f3N@h&Wt%22?jly2CPtO4h>#=&ti~@ zHeZr$GE9aTv%x5yn3Ob=q-z9|ir}(u2}DDEQvvWX`lU#+{z3A`k2%JhF`kasNWXoX zT}%Jj947+4t7SKhIX*W>#{dTtAxueGreFV@vPL4)`9U^fE3!0=4C|He+3B?L*X*w> z#r(x%HE8Z=xGszlB|U$b=B?wT616%VZ)QtrN3q^yjQkyz+b(eRT1I6q=L2mj2U^eH zkt>!#@sub60vSi|pJTs3N$E{K;6+0nz8vLwzZt{bxj;5WsHF~L8^L<*uA$) zjvNO}J(elquWlaHRP)uy1{|R+Z!uuwln1v<+|NeWWgyQhjG5};c%D(qHM{rgd)pOh zBf;g_r!m8i7N?zVPBUd?qt067-|DWTC*y|)sPC_VFClu~Hp67tOXm!83@{#6$Osd? zZIhD>FwSgK=C7rtH4WbdBm>`GUYz&of| za{BXgYZ~KxrgdPD8>JhyF3tQ_HytS-J!~USNQ=Z!qG?Xt{nct z*;&R8X=!QV%lk7f5ZsC;ckI57JKlos*XK(xWG>}=GcI94Yf=R%6^dSR%Y)tA5QPyv z#=umzkkTbHWj3lUF-{eVi`v&ZK4Cgp9kxr)q8NFs>y~Z(qqg4gk`FwkluFasAD)VU zZqh*a(D;YIpZ^rx@)ka-!C<3Y^T;#-XTbb;cv#rbB*MKo829$hYY7Jf=l0=Y2Z$y? z%6~~tP7ak9q1zfvH2!C83$)|B4vY7Jr?sy8MM_=`&I(z z%PFB>gc_#AypigPuS$DCfYfpLmoV8A5JwazwYBu}xXLk(-;y3Zs(EeV`VyrriJnX)b+swG&zj^zQlYk1#kM4bgGT)3WMFCU z({%ZVqf>pKT&zP_ZZt0+kjy9Fp4nHB!cS03i>#6p6fNyOV3nWu3-2S8#NMMsJu$-4 zeQ>j*L;6ouj2C8gxqRe?u_>|=En5=MC`2lDI)%d|@B@l4EA_JL&&Edr4 zq@?q0p;v+8@D;?QH2c#5bs_9UdeRd)y=-%pL@_@-hTE4UN$ClPJF&5A+%jFLv)Xgj z)fe|$)r8}(gmc_UZ2oZJ&jd|YXQ!WdY96f9k2L1r3H<3~6E@v0w^6$EbI~^QQS^q5 zsqUU65E;;6W9I`JA!tG&E?Q}`bV()T|Bsp=ArnDxUzYj ze-2!hkYM6Lzmbq(d~xy5gu|mdFck$=vYo0D-nYDHvfKy#_;T{n#t}>;jZ|r_D`_-DnZ?70jP8T%rukqW zpTPPUR_`0~fA3(k?LYfXf@8#QL)jKfLJYTDmU=DgGBjioOL-QNhK#rv#+~6twv_x^ zGTP5+;#VtVDn`KdxaUDz=Jq0mx-wNDyJNI{RyS+UT1x*K7e7iHEHVv$Ppm?50&W>T*fANzau(zCg|3u;;f#nuA@z5_2 z8JB{=3P@!}&@92m!D$Ae48jNkg%>#gt;@k_F8ZS{HJpIv_6LxARXME^0tN_l0>w~; zauEd*3ayB<{JECF`b5qAo<=SjfbInIoZ=|tOtaa!Or^(^n0ggmkGSC$B>!y9H7h8> z+l2GH<+E!bA!trteP6~%wu_shBoXy}L~FXIR>k(IM<4X+G;-2SO)vPNm9$r!eHO}yZ zIK$=5(SW$`dIZi^C{z=__8W_VN`t-;*1gl;Z}Q9eYQ%JI z%}xwc-_9v}6H2W5ifesF6|`80RuVk2xs?vpx&eWK3nMpYa?fkren%k=BRCyl6B5d* zs$KyA)P)fMuBbP+X6x|~TEl&2=Z!IfZ*RE#YinQlAJnr~<>G=PB=Flx%gjtFdcS!* zvk=9~l-mcJjoWPe{QDJ4mDX4e&oCo`i7>|RUwmu}7{M~hTdve-eE3gsju8Q9ZJK#J0+>}6N9(663x}D3BA=!L0s;&{Ziw`5VaX@~?%MwP zC?4ptg5gZqw+CfV`Rr(?KVW!zGUWz^R}enI=##z?N9Fl#`3?ZPnpTF4znSBJu3Irt zrN-eZ``;71Pa|qG6P?%{{st;s?620YC!(b}uv*6yB-^IlVP^U|eG?T-L|*SN-ilrs|}=Tp4(+h%27o>A=;=L>x}WB+I6e ziFLN~&!t(817bRmyRAXyYQ%(zsKmkeQU!c0aIuAED<&e|PLvP)JMEbUK%Br=IV!CpZ^DYira4}_h zfa&KxBQYb`B$0;EZ5v9|DEi#LS`pH#e1Kcjk(3?94rmzp1Xgx%WRB>t?p^~dArl!P z%ktZfcm?@rI_ZgyhcUEaY7c$JeNAlem%#2ueFx{P!uDNN;(^J(y3W*12Uvlfg0pxH zY4e%5!I`ImpW~^dRR=B)ow-`rE=6*0s;6W4u2A3$}+W7LBmGD+{pyO0)#aL z*dw5QMglw2Me{TG{}68ve5n{Hd@6oSu-M)Q(10iInBOHlgqPyN$PXAgu#h87eMq;5~Wydp&%UHS=orEybs?FX0gwT+_fp1oZ^%V(HMvJHfVfihPQV~8JK zxb4v%FHTTo0IWI!ch*}qolkF^*{Mvs9ER%`iK?W z+I;qBFE%ZW5X@A_Wg$lSnuh=;=!l{VhkZJbUebZbA^h^>7MNU<&;DXFMasGEkt+z< z%E~C=YXzq5XVMbhH#%oZqs1`-&X4jgY6x8{Mz=uYMPVDA+GOATBF)+2D|pnoPXdUC zgoPs%glV#X$^^gzHgS~W(EMlo-%(yP)og=h(+sS}#0dv?t>S#AV`$ZYT`p8EG zBWM0bmN=ye(zMF{`oz!NqkVp9I-G?5p;#e55@ogp_T~YO4PEq|FT^kMxAtSKT zY}_v4y+Ss!PV4_tn&zVu+$bhe!z^>}-gQ)O`z5oM(;G8a1833x397{hSB>~x@!j`v z_$-Y|!`Qd?7Ve+@b`*(MzW2+S{08Cbfmy}S*O?J4?=kPl5k(LrdLc?K9ZnBbegz>r z**|u*&0*oliu#{}LxzEMmg!CQqPCpO2j88x(AZZLD5+MPTJDm2#pxDQh((c*D)o2L zqfF8$87{rLH`>S7WeB1?<~*7vHEYuT6){TjWI=yHuVC+w&WW+v>V&<} zkwu0mBg~|dAh+WQNiiyt1h*PWqy5(#&8A1O20pubwaOKy9HhCqo>Nri&j}pbt|irp zqwA^--}uGE6cpQ)@ZD_z?KbTLDM{_?C?D3I;A%O}<3-Mb!@DUj7B_v|47t@uGqeZI z$%3}1E>R}rQ?p?n*Zk%$tJuwqB?7E3Qccw-hK75(yrT8ibBo+MPcqYYw=>V8B~YPh z>;q!-_ZJp;BO`o1yb$udDywrX`}M;7LGba~+>1`OPkGXr0VU_ANg}D}!TAFgb{#^k z`#x?1-^wdHT>t44{uSdu`h>%s^{fFgIY^@+tBWs}lF#tMqwy z;T3=_AVS5guFhcrD0u>+Ccv|6>YLh}}Orbtvv zQ_B2iX!C*~r|)a?f+aVb5FdYY8KGUq`xlgv%Oq0zTF6kMCPTKwk20M1%%Bp4!In@% z6BfWrbsK*X4j!QSKnA#CsP=U&1~&>272K+D`g5JvO#;*R4@Q9r`Y(}%^QO1O0ws2N z&ykC~k6fe*o1&r$n6+VjyR=(7N%b;sdwPZ`DhYe%=it1KwxAIaPHugKAMTmsG5z0$ zWV9TW27k$CFY$gnmqUA=-NDD4h8?^4ao)85iN%ONvD7~|?%TCBtHH%ScP^@>{dU&1 z#rvfZH3^#0oU*-pUCst0lS_;Nd;1TQ2O)QkQ2c>r3-=0Ds6N*d`dcSwx#)`0ynJEDG#OTmXX5O|{iFpUMrW*ku^+mK@UJ_;$?O_XBzZT_2;I z2N{1a8VPjEIzE4xuorN$%b2|))%gWsG|Lz8cEA|I$$ob`eX;2Lo@w@0kgO~({TVL2 ze5Rj6fj=7J%>AUg?B}g6d;dM6=MTT8b6QRN!TKIrDdsC?InAt+{t%M@KHCnXfZrSQ z4wlGs-A{)J&X`zJ#dlZY;y&^q^lEb|=|F6|7}Dt=~ke&qzZV8p8NfCy+~h7zI-`1mu;$)%v99XkBofXmi6Zt zSq=#aF##@CaKBv*;T6@#iE6mTw+{&m@3M_lOANH)8a0z0Hz(HS;NX7Y=R+v*J}f>9-WO8N|FFkNgzXM9orimHU0 zKzPa4fL==7yL_j{qD-osLzni*Fp1(nvuFk9&&{4Ejo!g+&@7;-&4>A27al?k14K%!bVP8G%>GB%X*QEiNq&-o7{HqS_W}2#g zDHr&cBtEcw)-1qW#*KeI8xfXNZ%9T~^SEsR{HFMeU9rTl5D=d0#+fVWhmz7n-!T6D z=N4Q1WNdJGE=uj>*ihMr%k`Q~dve?>t8xcYQ6tUO3FsEheR^3gNXA^dxHAsVL@f6S zs?=pe6C{3@5uU^(D*$s%yGeV1p9kisPyMFYOfJ_D=EydQp^Qw;kwJCXFSG@p#kG^m z(GCTl4f&sQwq0dy>g+8jsZo&6yqVBhyxI2hmskRNsM2XUH#xPD@nfEdt@Wt*q1q%T z=bQZ9Wy1=MiwEq?=d9Atu33dWzX~&UzCM~f=mf!AhLIM<-T`bY#7$gm)=LfYUQ3{A z!;=}J@%preBYuoV#}pM2(Df?Fhb2QucX@&(;pX<~1lD&iPMmf!5i1W$2R{Dqba9>@ z&G$Q-52v1%96iU6U+;R%UeVzS3L$cs$OKjTL0tbwvj}w!fDfSU8m+y^PSkG!PU5-~ zj+8uI*S{KZlXTbqRdIb3<-^EZ>>wg5&l1NGe|)NN*;_m%O@dSdxY4~2aHHDVQ~+8y*y6c)QxXj9 zFS#YLb2G#Iv8+e+2g*4V1s;(@zeaNwkH)%O;68tnuq&H zp{FhS-0rI#j%d1JGK;UK6h{xX7Xt_sgk;9ck$%J%-9*@3N!4q{0&{E;+A^L;3=-b7 z4Gj(D;=cjLvaq&>19)zbkb=3ZV)8KmNm0#9ReTz?zYlRh6q;}Uhbn0B{PAPnXQx|9b!!_{;BU9`XPw`Gbe37`xG{k4~FCfggE zwlN$)aPPhJ!(DV<51OhIqZx3BV1g80q5cNGMkAW-`2xpjs3Zj2wz@fLc;rvMN zKfsNockgJtBm!<-2d563PATc@i*vmVlg+=sA7hIQ*AVU6$oF!zKE9Z31wE|DQSC&M zq30`uecO!>g_&@OkFw(_Y}-7W(%GyPacP}G``x1OZ1mGPtW~R$utgrX#ti6RT>>I6 z;tQ^@n~Tbni}vFSf-=<-!d`^0--^r&iusFRnMb@wo-~QyWVEy>!8)J4mjpNkL<24S z;*b+6TnO9~fqW+kI~b?-d@wsZlu=81tipon3jiRU{rzbd0fMUQKGpspw5a zzecv{Sh9RqNEM40o6P)^%SWWunw$%r`2=_eg4uzbyzgdmNe}3FhXTSAI zyv>Vm_LneSdf`jKFvlyf85TPz4Cq_k+ZmK&81>9c;0B{Ju%-ZKH}HK6n1551cdS?h93m)H7ufu-w-Od*KQZ9i#RI^Ayz_brErywWT*-hV`snZNV&9eWpu!QQCNRh z%krj{U>D=RJ4CZyvE&6=Qb7e@<4QJ^aI^Tc$Gin%Np2kMc61uLgREC(?*%i*K;BfR@Js`4-u~gJexoloQp5dY32;-HOU#V_}Cw)`OSveVo zuJL{Gb!U&zppAv@CDC}}Cm&NeYp%NC(S*9q-L!y3-0CrJruX54O!P?u!+1YBqUENk zOoWqmiEis&T!PwLq)9|%1YhZH+ErkZTc-Bmpa6X< zl|C@vaCJyMzP+7IzvPN3jnEn=Gn?m%sTQa1heDmcgFXM5zl||el$fTE2vI(OgqhlG z^keuQI_ncl{-98Ku}E<(BC444@pzQ7J+#16Wz4l7gHZ8On$n(dgN;fUY=J8fS6edp>|I1Qd%A zv<*?}cpXcNi@YWs_^Dsx6BGSGb$&xv@T7$@fA|iLWoVLW=|8==@DhP1l`(?}P(%7_AB$DwH8u&=JTCNc%_CiXk|`2Ox}} zFk+MYKw|sE;}1XXDo?<#q3Z=NX@O)V*Bj*Sculxm{^Xv#qSFmNiVeb<_D%em;TO_g zHruXAJd?uKA0xP9NDXHa%7xFBMXTj$Hf|?P+`;9};U<_h2eM1~lixBwN8xgb%zBeG z@=au;=_6B8XptElYI{FNa<2jp_k;fZwB+PGzC}Km>4E;$^In1hyc`IDK88tpyPd*- z((93w4m)h0!xGOaRz%&_rtSExuJx?;UW#6yh%x`(yU%=P|C6wfb&Wf1qOTqOcfg;F z@X9Tzx2!|aCU9|Vg(LX75mmC3bFR!m<;?HvJT2=|SWT(>u&ofM1P-TiOM2(3TMiRhH26p{anYXv37xlPpO7UP@ z@$Bxe#*}oJ5bLY4hfhxCS5W3IT+ts>zlntlCN@a>mfbTEjc#paYviMx@Fb0>iWKR5 z3@5Ls^@FKD0B;zsuK)B28<^ZEsOdmC3E9BtQ|^}CBIWu+`}+K}+-=vLSWdR-%%9Dk zt8BIL>Mkc66b#-hbse88v1d7M>d=Gi?Ee04$42vW;$4@=Z`q;km}o7*!Y!z2{l4}s zmKl~z^Vd=h|D#kGudT3QG)`ZQjDhtE>1iVinXNRoiV+zZoAw2Z!uaP)aq?w{cr|Xp zD?{z`m6pT!^(i8UstY%>5>*$k>COlvJY< zd$jvSggH8N%WtneVcP*fjE(T?kh&p-f^#u$tk&8pV@ErN?@4P#wdzboO+RR8b{d~; z4oX5lt>+hQ;O#Ne53n=)k}-IrlbnKL38d^YuoZd}!eOf4e%3bA`>8BhX&~p57UJI-Zgh)%W03x(w~6r4KVQGjJM|ZZ?>vMMVal^N zcSk0L+Fr2TD1V2U9xMMf7Jx1~d6$XqAvzi8wlLnfaT)4jz*TUUHt>rve^Z);c|Bh< z^Oh$D<2WCgsd80bSaq(;DANsOd#nF%ZVcP zlhf#VHRr#`lPLK%F0*{D^D7p)B89a2Lx;yw&K?3Mz**6-4*u0Eb8Km~_l&;o?+0RQ zqM7FG(@P>pZuVc=M2#A-_sa@*blq^T6rZ#xWF_QSZsHx$26X*ZGioXFUPdrB-!zI) z&!A}l0-Fv9=Gg(%p9xsa5pM|-dH7(uG#0KnHkz`>N?2alpZ0K_Q(3OkNQOtEmippGXFUI}ntF`J zxfz1%!#%G}SxTEDnvO`82eO+_9>Le+F~WhO0(!Ri-(wSm1PAm(f>BnfG`z4nG13dS zJKb)-Fr7zEZ+V})XnFBd!0{OVYNi87eDHlwG}k)!g#SZkJQgjNjQbZmjsQ33%h6Bw zf>pX?9%#KZy8b#muKe)8Wh2^>ZZ;sdsf?)x`77VTD1Hm33V^bPLjn&{iicfTP(p%+ z^g(2d`IWeD8X7%~+Ud1n9>IjgS~Zw0iOGj?y8jf_adIPDN)>EG-UQq=S7TDMkfVQd z!%Jyv(|>`dTGCM6sYEGI)%UKOo5|`XU5r4liwe1vV%?PG*BwFwzTwyL#X%J zjvTU(G@c&<-0Qm!@G+Ty{20NC|^OCvAOJa@&rvvCW~Z=ln6xE{4tJx?PJ$3Gq3{cw#epXYPS zOpB<_X^rSnlPGLPb>+*mu$h)U)L{95NCQMX4@(<#xx#_^x(J16NKnB7HBbb6e0p~6 z&QfU@6r6X{KPc6{2_}j5C*i4P z%19LY{P19W*ZsBM&F$5CiQ>&Mau@`WFU`CJ>d3Zldsgq~xCFpCB*kjrRvjFJj$!2O z0GQhZn99gt1Vj~6f&$Ghe?S?f60?d1--UPN7Wf-&l*2dV7#Z7-Q~v~G-walQzFt$0gs9gWVZz9V)=t?%z<9d)N1PWS-( z3uSNK?_6=@gMI)~a-W!}5y&LoBr4118f$1y>#t8R$A#o{?;(qNDZXG+r7$GV`&Pa>4EVvf`+K zHbz(D&ygD_a)ed&bTJjJfMj03_8H5am5Jl6p~|Y)PTHp_uBqGJ^Ge^}4$R?#AX?>? zC#0zD0i(z7_2^v2exk*UMh_ODPrEsu(el~^GC$HovD0uS9nu@*YUOXB${cyyMU4su zd&es@Sx6)J+Op|ec*eb@s_S%3-p8=EEg!1wl&*5zT9<^l;dQNeUW0T>{sO z)WaUi#T6f&VRX8T>_RJpH#=G==u)+>9rD|J9rm2(Y-0w0(6ae^1+Rh9`|6a8VMzb0 zrlngi*{$Gxb4k~u$N2f7BaRk8O+i%0_;>Kw1^`{-=d_%>;>XT@xt&*yQhyFNYx0vC z52-oDQ?b%AO^|8+Yy6|emJV%=ZPl(GwEe-U3Zy_8cT{pd@={%W{nHB5vXK-KPsG|f z+Et^?3o+6M;l*3sIw?KE>E-?7rGjRcdV}7*eNoV_2%p^_RhV*thhF7*z&`up_uYb* zu+|`~S2%qlhSsrF{(xIlHxe_Ui%k0JoB;5nW8U7UhsDQUH~~EMBd~zq$I{1fKf5wI z&ObApmBoMQFzuBOJR4;#?%_!u-o-p?53R6`+sSSsOQd7^+Ww$@?{H;_BIzij3MOeN z^8cExLIe-w0RJ8+F8#?kG=I)qKpqlu)FAbVG56aaxk<`>jKBM|vg{BkD*fG&DJ{~^era<~N;;R_;1y+fk@i85UaW?x!k)&mpGT9Y@j_nQ}^MSDm zS{^sYj#($7m=v{~y<>6PO+NTI>wYP1Ob6p>ukM^@|Bm758vfq5V!u=Kn=RtGz-2G) z#=ccnn25aco}gNmc4A^<(cIi-oIC~i`I}b8o};laJq&zsjqQBRJl^Z*u2!IHwz=du zu@<*Bdc&()WEDCAAM|3uPXRD)7@6eOUueqmJvSxY5Ucp|k!+S~fO=EUh1TMOqxPNK zvmqT4M?@BzP6AG?pZip{%dPZQ_mF4M0M7siw7VeH9)OgB)Kg$~hc`7fo#^_-Tn1;% zwL{`Ca-N_??=UzVXR>gT_XY2~`YU~aBOl&M**a7|uFO1GD5I7-_Q=eg^|PRqm(BV? zO~V@}vN?U7$X~l)tE08&{XA+PVJAw0PH!3r?7R$v`XE*$aRXkzA&f?4HhOb)BvSyo z2Z+2H$#`)QIr=Z9sr*#M1_c0*3e!f7H3G;ee+s1OR+|jBER<7EWYhFY+paA?47>Mt z`Q~JE@I4gl%vu&K#FT;vv*-QGDe(Ajb_X-=gujeG@t;yPIxo=YJ^f<)mJcCndieE&~(j$|!tzZT50@))cLu zAGu?(;#(Lr`n{^$voksfOz33$HZXY5P^SEOIte~GJ6mZ8{{`;?jc5I)m(L?aN_!E|G{2jp0aOARV96rjkow9sm}v&K4qXVgvyWUU1-?Kj{N74NCzIx1udGJKH!T`@VV zna}d1yX3Ub?wHGnl~n1APEEo9t^oSnSH&oTJ>RQv0~BiY7%|{l$3}t#AV+D``d$?6 z9Y3%tn!ub35fdKuqS`dz@&ygQ|5ymvJWWOn+mXTb zw6C4^FE{z+%EvbwqDLt-nM>qrz16^nECbpZ`UqoFDD1Mb_EOP5Cse3&Un`Kn!0FdbCUo- z($lqWkIhlcq_~!`Cj$39f8dAxfFj6`hcF}*6_Z}=GqqjqP$P31%E(@RvoLpgc|$2ldC3K`%3=}|u~?IX_LS7byh1Yi8}GF@NR+ubRuey_B>F-mf!Uv&mlXGA z(uG&%V@J*vb>z66u+dhV0QiZIRntF%`u z6Nm67V6%>#9sbROJqD`0{pq1CsKE^XV|l$5g(Q!GPq^4=^-<&|h;xwqASe-_fqod` zkQOte#ibyZ5N1rX0eK|R;D5U}ll=y!lhnh8-oKLUs+{vpNVMLhz-+_}hxkT|-#`pt z$ud*8-kSTO`n#(bRiY}cbH#$akGSnGzVu*<$y#lzP4kEaiN7Q?XeN|iJ z-xw|v$-?k|6qUyl!8Ttv;UFTVcdB}q7KWeB`e{RzJ`1B5{o~BP9mCJ~-}YUa6-3U3 zpbjjCG*JX92E=J$`*|NvBTp+U_A1?8>M%$+5{C3pKm>mJ@*Xm-kkA^4gTn^N9)wvD zLuohLQnR12D_xk>y8;_Jisgq6baaM%7iyG5G_rOn^5NIwI7nWcGgYKkMgP-hJr*O> zUt9Kbn7O-PlrJ$%3Z=fWg7elgd>M6o52SW~vxOhWhq6MD?X4apsxHy&L31j)C#WJ_uKfEuU zsC#B#5$O&me@rDF8tKk*Jab?o5Ph7@SgV!sB{H`YyU4|%^;02zv7o@O*4T?*^mt;_ zXudtPucD^YE4fVYvDE%H2W>PW_Ro_3@12xtla0Q<^b4eQu(`<9{1WAZ_`ksr=C97) z4nV69^yx^3ECS!~Jg@?@SfzL(BW8CgKeEG7cy&TGz_)ng*ErFeaEj*6cgPrLh0XWe zqmRr#blDa5IjJiJt{OwV2p`YUUu%SMVzB&F@x7qpP55Y@#=)f`m#2er zk%6}3@%UJ#QcgAf^W9U73b;Z0W@Whc zm2Jq!zF>{TUAdDZN+yr{&&J=|UBUYOdkvZ%+%UiJT*XYi_n?Uy%$Dpp(Sz9E7l$^f zrw}a((D!NLL?#}TsU%uhBy9Sk+7Jr_As8HuLaIm+;}SV*)_AZJ`2;frTLYpKFYb)t7)zTiHuBO`~VOpdPJJM zbZ>r}oScNu%{lz+(klffUYuUM9BjDsKhg-skmE;I#X6Y}B*Aim86TLh5UhwanRy{? z3Za=Gp{nj;X|u5;L;MJ~oSCcOLD9{-FElmU&pHT@)dMf-)$ymWYL(3PZvi6;)#_0a zJUK>Rb4j0(!F64SPPaS76Xr23OF)*AeTR)Ub_~=hW9~`XWZNgi6z((n? zwi*J3u)Vx-gN#5tibY5ox{tKl(!@d`lG+%yWr*lb6Lx9v$FW>OY!5yNf>7CSPy7@z z7<)6a)wk<-hxg)Gdi!$$atQv3$YHhwa=$xqleLr822-xyp|V};cFo;obN6v-oPFEj^}xn~%2O_+qU_AkM#6*PlqXv{k2NzPxPWr0 z_Jy&sj{s(5{2(ss3hovAqV2-w&AGK({(i_?;8K87aaq|d2x>+{LF6e>x^f7#o7J`@ z_g|mApp<#f0r>NK+N<++8vwLM?#!x4A1wr^{P!5$z4%#Jl2pm8GW^f}z9i++!GG|J zX*1PJ91i-pU$g~s!|qtRM)0LP>}efa>JomRQdFt;SV9!}#vjoW#0}<&00Ch%B_APg z$PF)AyV$%{I$Cr`22?dv5sf04`1!B2$dyw<5;SBL5<*h!Aoq<*wyPAIUCewG;y7{_eUczGY@*9)qqc_x+~UV(#aZ!=o67(ECbh|-<6iQ%bA>P_jbY(z%nZ1Mz(i> z@B8QM53i%cb11`QyjJMWfG@ow^8F6}yQZpyaZMhtd-CyzxFwjx|1_YDHBIAaU)@FZ0j0 z1_vsU0ICr%-)HG(t@3=Z_>10Is5dFjO|!^SOYvVrCkHC;VHIM=_*J2qIV)EfKzi}U=vXz!9@2|X4frz?E(L1zB5j1#v(GuwW z9XV^Fa{BI$fmfg{X0#FdY}(_~ivrB({B8@u!eCYax(d28lz#i-aE*&zj=qhh{95*8 z#Se6+eaE#(@V_oR37_|EUGV9DS$DfV-VPVYwFhgr;X57r31YAE7IqGm8Y2t^&6jwZ zd3pvubJYTz5(em!_wK<{ulso|0r$-1LBb$==Dnl+8zyK((*C-9Ir&h2kEGc@$xgT~ zoR+SmniNEm=uL;zJNO0+#4-TE9j7oF4eXgub@n7@eZD~A zjcNOuX|ccz+|Tl;mC1?b#o@<>VvB`l7QD5V}9upBPNOw zL{!bc*w~yLN2dNA=^$$h%x{y(?yIcjM7Q`op~n4r;bRH0YAOgOe~Gy;ywX<+zMnHN z(J^|WBAfrHk62JymgBnGqU@GS+ef;NuKlZQaU1=zmrwY1{P%rf z@%PXKl_K(&{!6(fa`X-27pwKYe-z?;!+E(;BfsMpJ(JFs8M(>E&M8C$-~^_{Yucvv zBGc+gnTthngyvEB7K`|%0qsLkzv-}PtEtI%!i*#3JW?}K3syhI7{{TCC6$In3i(?Q za+XAwEp$8(2*6gTUNBJ$$MA28NzX=z`~Nc5$hHHRop&-sSO_` z;?&1AE0VqsUroJRK(l=CRxQmxb4`x;VxCtu?Dvy@;1OxucS+VKDQrJa4fSKefXTqP z#KcOBykSiRy>A%2Lc(p@mU0j zvFC!6R4BB=@$VsM|2xDUl`|0NED$@raS0_V23)|vLjxOE?i8>B z7@_L-@lmR0ItKAS_-eC)h0WGhni8QbzMHAufstRV2m)Wf#rQc~N9Vb$uZiP**MR}6 z=c|jtm5`&(~7b! zk_DKRURH&=CL}}wI5ns|QBTp)(%L_LEb^T-^*`k&&!=W)IVZG_-+!^18;0sa)??BY z4(_q~;{)xlziF|7!y-pZoAFof8YBJSNLSldRs$>KHRN5VnPyzEL|LDv}l zZmq_^PM45)Y?fr{g?n> zTGb78Ha3uqz${lVIsO;A8wA6CKKu?o9V7u3$ex4W^<8u|HOaxxeXDN*B5YDulm8FE z+o2cv)uq!v&Ch?+BeK&wS6Y6PqVf|snvV9YgJxq_ebsZCpaHzS(RJz`^Q7=gWK4g1 z%)KWO8(V1R`IDvzCl`lXV%*(U7Z}Ipqwf?#ZK--qn31K09;5FQs>*pS>JCW6US#k4=IVoe~(-1 z^ZXE7O<7IxaHs$AZ7&7{%T&Lm!r)YF0Y4hc!D zic2-B4Zx2`A`!US+Cs0Qp{OG-L-Mm$v7uy~X{F7CUve@vlmMk!XU4}VKwJd>-S}l% zkQ>QAdei~k*@H1tGqcMA0$--K`cqrl`iUOZx-v^JVkc+N_&Z*|efwwm8b=Z){%R_b zRb1(Y%l9|0!+X0Xsx;Ft9tEUkT%f(edrQ_x@e|iD`EHMG4cmv0E%8 zn|G)&=&=5Iq$(5x*D+$iLHz-QH;BJ~cW;jmfOO#GloJhsd^RlA+%1Ywi1|c<43E2- zT0Hy3_VC#`IQSqL1Ms|t0LlYO%HwE#jDSz|dTgJY5`%e+e?Mpy&^d4`X^x16+=}8A z0UeD|4W@?9fFD9@wXImo6ZIfB?*J zJ2oF8PGl{;y}gNBw(*64igvLlaWQP+g-tR;&xGmSd$XCMQMYa3OVIcT_SUA4oZJa> zS*1xh{aXI`2uuC8FpQ>{l=l%jE)V1WV2Kh+#+%<_o?$k!wHjXcCWi6k;5>l}2&uUp zDLcO!A?4*EjQ7z|asNlGf)Ag+E-%Xv7RGe4L7OVJZ^WX2e9yxso|1>eS@X< z1awvsRu>HQ(FuRtU~W{nm=q(R?WN=EW}zNT8{95ASi!^ra;Y2TWybp>%w(f3$Kuy1 z-bI@&<@r(-*l;ZiLD6I{=%s*w4%rimrB%h?n51_;J+GY}{wR-s%G|=Ny^|AkYUuSrl(QG# zK(i41-6|Sa;IVC658_zdzv|z0-4XMqza9P!Hyq!$pI4Q_XQ(fz%S*q!1JT0>JN~^8 z`J!+cvg37o^23z62+#7rIP@p%1$-u1JjR!+DN_a&3RITvtB4?{JiLp$Io(dI3#*m8r%0vJC$%! zV#xbF!t}C=vaXk&lkUvjCbu%gGSbUbXI&YPfwN(Zk{ZFlW@1F$3c#gCJA3ogPmB&EP_2OGj~_adX)dg_s6Cb0!&4Oc+Z();TsKKWc3XQ?Ge@wnPD zC+21R35tBrt7vj$j+=%D^9B!JCto>x?S>ud5i0yNW$@Wk&Si3Jx5#^Cs}}eU)ZNX? z@V4&~V-OE9Ik}9U3e3FaCe@q|E$?D0Dh$rd*f|u)<4;jpGq7&$(2eR!*LP>@!HXKJ z!D!0g$dCOj66WuLBdqUU*VVktABykWCy89Ma-wolSFhbiMfhpwU=x&-NJ_=4xrv7# zT$uxqt52`1Y0y|nvF+s(oThn2wCgkaP(UYF(CSRbSxPjiPDgL%*SgwslDE?&WMSEpS{!RS-bj$=P+^_&K_FgER4U z!RrsljW&JRqAl)w$hMA#xeXvMh!2L~%t*69piuo)pXDM!v1_H&om?89iX0_d2lnBM zv%laKLf!Mu#tp3wh1cz)NS2s99o?ej`>$CwvLUR2R_PJk*F)r0_m1QXem{CD?wYlN zhI;nniP1(m5&tl|Eq!hsIidGcqVa{`GBKM+eX=SOk?ntxAD;UyD!+03^#b z#YU<9{E?T%{(U0HZ(d1SWVdGr&_NH@HJXt#jrtwq541b$ zb+Uz`m2d-y;?wPZOD*d^Zrb5!EVp7%NgGTO+JC<}s0$az><<^`V)TT=s`x;Qup(zU zqb#q`;qrsKHl%-kj(@}!ys>IuA;MtpG*!VvqXrxXP7sTz;2}@ekDFX$euG8(yOV0* zr02}r+^k)Nq)D^p4nC|Kx9@zS5bRXLP~IrY&z7x3&a z`5K;FpI)^G-ZHriZ+R`Yz!WDu5sS(Zn&cW>pSVB)t5HF=0xnzExpPtgi_QMNt@9X$ z$_PJ9QX<;*I{xR4t0u#-oGBU!7^rJQI!WJ`TY3(el{QNm1qLOymdsS;`I-h9n7Gri zRf3v^JMgMk?zkVWepJzZVp*J$5K2aViTlR~CwK<@xG<1YvodN3r_}bgZ5;`5zvVFr zas|p1aVAab1?0NWUsG)jN55TsyF@mIpR$>o3EP>_FETf>&z0w?-PuNAf|kqK-Dhu7 ztkoOdXGp;B1|=4_)gFW+AIZ%tO!u!6IVk(XCJ*r~mz9xLRM37_wEf6l9n~xMrDVzd z_PWxpq1C%f0#o5JPs?ojbnTwnVRA?lFJ8fwI7N$jVA}hJM9Q#bEEw(2dpFgQ9IZPd zgy);*?yLUDGhK0Qq)-(7@UU`oDOv)dO!xHmB4MNe01$lJn3aVI5>zZ%9 zZ{^2m%9}GL%5d4YWav5QT>m{R!*t^8@H{=4=NkO^V$SP;|=kYnj|<)6zmfXY9F z!0DGfiEh<}YC>6>*2U-QA{FPcAsorWyd~Yik#2iJbaXv*B#T%4h)vmoLC(C zuESrx?yk4>^ccw&0DsG3$ya&|6mkhj)-b|7SxtLUsPY%s+DPWJu;Vf|#HyiCfS-=s z?OJh!X1%k;R4D3$te*cZ4UvlX;voXrtSApEL!6}BDzfM}Clg2Ggp5b!8@;txk+I0- zl8ef!s33=AM)$veR?97+>kq_rfWi(vHG^CtY$75#8yimV;{`0?J9mtL2k(A3Va^nH ze&F5>*9SEF%fN?4vVFO^3H9~$>1J8isX$yBqZ8xDk{Go(k`OmA-!FslPPnzllpI_2 zGSm0#n3COwFuBNDav-0g`MN4vC$Q!}Xy&J@v%3r>C|rl0Qf6fjltb<3o6r!RA#`+P z&CG73dF?(J867nOa6ZZhAo@1ni_u^!rktyew4kGU{k7@of>FR5s5Fzf z=;^Ve)}X!njGqcL!_Gr^xVZRHbI6bn4GryE(uB~!&i;NmTU&^~q>=C_Qf3>?_hlyn^ zGf2Y~c{iSj-pcq>e&?18`KOzEzR@enJ-GD#oef*G{gUtq_CIoy`9L~1lBW%48N`#~ zL*ph4!UcqLQEv+18YIfm;uf`hwvZW_ICz(I_4E!dGoX}JRD1z}umnaT!SCcq#`oK| zGy1_>_ns6PNG=?-^gWmTn5#CvP?_JzB#69>Xr@N?M$?tN6y>MucrJlF#wP?{%XaDq zrzUFrpZ>FDSY1;EI0UC&4e1xNUMV0$NJ&d0nkH~mS(&#dLudd5Fp^MEV4;#EUWtpJ z{A59TP>=5(kV3g57_rX)xp`!)8j>#}7$oRtXJ-)rJut)xfr$;O5myCK4M8J* z>hOG8i)2{s>;HOwF%8g(nsnqDiU0GVVgzgK#-Y1#+f||<&*s6L)k}rQNZ}e?LI3ZL zD!g}DS>;}Q#6X}qC2qgsV}5VAta=Uh?FtOXPzpNxr`-IKGl~HQpBs#JWpw&$oLw1rBY@|l(5d* z_giZnYwxw!AA2ABJ^H8D`%L$9-`90s*L_{*2@cOtq`N+#R@Vb6-M;e~6ON&5{rei6 zMQJZLZ*NOIIUvxf!NP6be7Jx`i<^gipW4<|!M^a~%BrWY5(xy+w$#7=``J^xpO6@f z^^%f`dzbL=)S(J|Y3o$I()*{T@4j%Gn3#rHN9l`U8IVb7Ve9j0oJ~vbplR<#`c`W^ zsix&H#dvn)a*7q_{+O{!Jq`Qkcf6lXb7vYe*B{UTDB<%8msu0co6ByJ&YAghquvXR z@b@`MTBUc(erh?LGQRHnzTlnV=cOrg&WlcFvaa57@Ioe^`s$&SF9qS=u~w~rN|nsD zy&-p-c#es~OK|e0@2#?5>_$u6ScT87JS)A)eyx|zo+}$(=J=-MG%X4?wl5CLKc+(z5R(Cyn~&Ewa96;nws+F4UJuV zaE=cnG>iiCb&s26R+a?Bx87LQ8{)@ST%|3ea3f{`1;pUi&nir|D4+ebj+hfO4=&R= z3#msNm+27zB@X}U!TBsqZJ&$E)o3o0HPmcnU1V7);$U|1QsDv*F=F`GZ73~EBSRB$ zBTl2(o5|Mn2x!lI~B|KqgQ~3G0*AcHLz$Vu0xXI~{SSz33&*(y7j#3Y#o%1eP zNYvf73d!9Wk&s(_rt|Mt=>+(Um-B1V8Z~5UswBh z7YuTnDaR7fp$a@Ld|%%(0+Xvq&eGuLD*{#oh{u0v&^58V z_bka;7AXgp6V{CylR3uB+B1L1VW>lPtjzC>S4~ROku6=Ax@(rR@H%<7-G3mips|R| z8p9ixopR@x7)sl&|7}}viaH-J4i{D3SY_y5_TiD+Wue8F%~i>;+I4KxHia8XGke#Usb38f4Jy5K(|0z;b@H)Xb+yGmL$D8#5*2*w zu}ikfoXADzIf31VCe~s0+_Or*HvO{kWGwUP@SV@4<#2Ae*p%z7ve#+v&F%3{bkqJk({h+mpJ!m1$E5sc$i(~8-`KsdSV<$O#^q8X1M3M2`(38-4p_d zcTuxn^GJeXd8;lUZKww4SPLL+p^ML-*$>q(-&plEeoGuoeJ3HwXCWtW6M zT!bz8@+yplL>ME=T$;WGmp*U-wieS=_NU)nJs`iLGKfvM;aUT2ll4Jg66;j{c&cXH z`lUSUq;0RJf!gYUMH|c~I-O*(0QtN`*u-{NJRWdJc)9(is?)s}!gOb;*B@y-oDCK- zGZ-rWkR|Lzo#u=y9`0(qjD~-%Tf`KYHrTsqaFbbld2*`gD%Q=RF*NstXO<4~%zOSe zeTXzmlZ@528}5lw@PAfeHh<&l=sCxiv)0TcXpfyVf*VG$Z8$%-yb^hl9_~K>en2!1 z=(it@D7zRaEfCpb&?pLYZD#ELBYv-c++Shc8@ObJzBssEjHoV=lWS)=b1j@-oGkg& zkq{iY0jWJ@k3CVXOh;D~6m*2K7|3rH^2y@}KYZhBpG!2xyuds1kNy9eH!+Cp7fozpUya{I-ovd2@f5EnVXq!XtQU`=6J;*XGrxjlH}h&ZSOlJclN~ zKdUo{x{ef`-l+cb<8tgt*tFa?A^PQ8w{B$&b@_x1|DR%jr-cnkU$kr%S#_S_6bK6* zdLu8+Dl)%$&751F&)Fv4=1c`*`DTK)m3Z7vC|xA7#uKx1-xHasK^X&wqWgf2ut5 z>&vXcUS*FRC;t3IQC`tYbLPfZQ<{?TtGQIDV-F*QkqQ!fnY@I30ejka5AbEI^gN-NX&IOJ`8ChC<^4rg^*Y@nK(n{PvxqrXLX zvG^E0?-24s?pu?~7`r5xNcPEBUrIeemD!f9aLY8r!X#29y)x}j)@~IS{F`s;ceeKuhe46C9kJRlvq%pf+2VmDEqF z&;Opl`^@|i0G0^gvd**@mM>Gbh0$J$GF)TwMb`Xljb|JvGNzicOl6;+*t%lHiZ6Hg zSFEV0O&@pJPca4tIF~P9jz75GEHBqUa@x?`yz{OKQ^o7oT)VX- zQMrGfU2)LJRugr?e9(VEZ<^~(-L#$l{%Td#)sxqd$ks+^BQFrGIE)lG0sWbojtK)p zdt6>m@^raB_)TVnw$k9gV_+yt5!P+bU*8=`?=LFgeTE(hK9Q?O+dIU>OBCm^r{FnE zS0Er59AmX82_5^K;4Y!4m{;rd<3t+UQ#XMRhI6;_Zjf=K=j_`7&OLB>?=&>zvpV}} zC6r%mr^kAcLXSDadsbhc`%Y8&2T4pnLPJlq+uo+^B3lGHQLB18?2}zR6L)lo@u*H0 zcjP&UA@DKhI+?#sD{JAU6c3yn3_fkLBS4rJi%dOnd3aAlYhs5nW`xARiEbzCF+qxt zHvaY2mg(ZJ^NR$&xV>VKq(CHn5eqM~$6Ah~O75(8l%&^5UC|rs=-QHbTTP?Z>MiF4YnX_k`~k}g}?cQqD9lXIuKg)wn_jlF+2?cp5(ijlfy^kXa1>wJdZ z)w>^((?>pcK;DR)=Sm}TLF5>TGyt-N!Pc!t4xW52g)?!G-|($j%EG(w8v>FRese+| zSse2D?@n~Z`wUBlvuB<{+srm{xS<~qn#$ofiwB1!7j8r8+5gAec&=K^Y+7&K)dn~H2<)zepnD$d4>r!uogMWlXKHLacZ?UDF;L6t=8timYL2^{#mfx- zK$NkE7}J08374=mX(5>aLcYXquC&Lwxx+s;95kr?Uk*ET+1Y%=U!Ea$`hOqZ3_gU9 zShzx1R*Bs!ob1)|x|hc|Pu29%1IF9QrKRh3e)-qiC}H^@-d(KQ2qx`n5QT$nQS2X; zfy7}g4x(O1R$N%vA~5lLjC2+LIXFAr7t`C<$3oH?U=u~-qHr@y(*~qBKvjv{!a1mO z5vfCLKqab?mK3xzySTcFU(q{gWYm;ebk?Q#GLdt@-Vg{e+@2obI7jjYqi1Qd?&b}r zoUAcOq;?zXS8!bC;A!sMx#N((Z{4!e2S_g{9+iD_w9oN@^QfSE3Hj?0Gc&D}gHIja ztHnguz0FnHxN$M*+=!1~iL1(i2HT=M(6V?I*&t|0tKhqogHl_-h6r+S`N9VS15PmC zM0v2awUsE8A;F-MYHrEN66==p`0+AS5m%!`GTVEG2n`Va6e70;R(l&eyD;>-rxq2_ zk0mB3xj#d5#v}iqCka;zISAu|qU?6V?%U=B(FJV`8vSI_p&380mp^iU zukJry%dhM;uwtZi$_m?U3|yI_;`gRcpr%(CWq^_fNiGldlb$?lv1%h7HEQ4A?n2}r z7&TQt(XPy8=@)nPss{=%deM$oi)VoTJh(tseaU7JB5*TYedp}>_A`fqG{!Q`s8_x!0@8RL%T7mYX)Sj&%kK!eT8jr1#o+J*Qc~A=R5PqQe`jLqKN1pOt!%LSeSq{#e ztCf#~evd~`Vn#+rPaUDFn1-b32Mnn1E9{hVz>$&KR98AkCl*nlo;f`uJW%Dseuur- zXIuil4NxHM02HBip@jD8)vMpHWzuLmW@b0_*JK)Bgak#1T}EI0wQJ0jkdP4Ff<4By zjZaW83S7Zog`(I@OiVy^B0!KD@{;oAreyjDO-@c8%xWR+ntSpeKCA$FOOsR(6vWSf zIDGr5&#SZJ`d#{+W1QXhjj1Ve?`rF*s?u7wVM8@?aj>MI{{eMJ({^vXzI&YR{Gb>5sdyUFoPyC~jo;fMH4o>E2C8=-(^jk5tD5>*`k9~a_pEasp!@Y! zEutz&;XE>@$I+!v^gSTWMH7yQOHSrNe?#I)@S36Yge}G}Fi;(cK`@$SU~!#EPsdWR z)XwD?TFBcS7!5M~+Hf@?AqpPY2Jdp6g;KiQNQ={GZfhegH*7IiqN0{KIXes1|JAzu@*ga*BCr3m5aTZJllb=SYfzx& z`|6*Br{29w3;3+0a%=NkC@<`h_IH|RT9S5{UM z)2n|=`5eEsKi>v}q~;E8YP57p1TwM@@*DDQ^*29)D+YAD2n`$3pwZZO8pRbl$SOlR zrS-%PHT&oXYjaAaD<=wU6}*RsyNi|JsRRxb`u`X@>f`6fLSe!g8X2XY+C72S{MJDp zspoga@4>ipN&~NMmH$#$Uf41u_aS(8^GexLMOX_wGdv4Y{D^ z&b@T<8mOI!$Ph1Xbp$MRG;!!6in;*)j7Xx#idHoPyfnxS zx__UWG)9V-*c%BsIl~O&O~YCD@9$064S^I~^bvUFm^6jJWlk;%59u@kgBS4Y&&r}T z-(R2q)Zf3r!ZSQ`4dXJ7mgTji`^giFWBi?g#s!<|@C(T81660$A2KuB1WBCQpt%Xr zQm?UF!xqC{!}SdftH5}39K04)u>LdNMI|K`2@(CC{Y8`X8QA>A=u;zR%@aL_<4yZy z7sHib`TOt8`crTU7lMPSE4OZK4*dCvzwv>!hMd=c@$e5&^7i7s;P-MJ=TWL3cK!Nw z(v}2$-j$dd5^8E)QUOEzxipIk!yPI20CZjKDefN6OR0cNU)D3RNtVgo{Ko~SJBcr2Nu3x`iwv$Hm6pej=Mx zm$>_Vt`a)me0+R3_U+pT>UkMbDw#Np9;%hdGOq*zsA_FJtoEbbR%PcWFy#vh_v0?2 zHYEESfg^kg4kE39DMpzpkDV>ggWywTWR8>ISH4DTWw!q}Nc>;1wOc2ULSw$WHR7nv zRwV`1Q`o)$6gZCs^|atMv5~#i5#C1qkN91e?}rH;*Lc8G_y2s$m_* zn-3ZE0vlpS;3RTihhTedLz)X)k71zTfzSxu!qnB(HR{`o6IWIJ{RcxCrNg5_`Q@KZ#;T;$aIAW`5>{6hz)@61sPi%WlRv#)|+3^>RN=I3U} zl5iCjWWJ16N==Bd%E>)46vpNu6%3ATsI%e_f zjI6A8pA9pOS1Y**p)-*&I2Z*jC88A$ec+~^y{+lzwGf1b z_WN>TOQ2;e>5pgJms zKLLo$PuFSOe4QK{8;m<#3o1`E*4Myaoo0T4S@i+X2jmVl*pz;RwnJ283uHeiD-*%H z*M@>RX}H32C2m7d=rDwe+=FHWu>j$cE`y7J2Q8Gl_4P07?;w5>=!<+0+}MkK!&>a6 zl2%_5Y6SfHUWxyD1-=Im9(yL}&cKFe9c%-f;rZPnXKRj`qZHr|63F@VMJstAD^l|F za{?hedgR%sOI4shG8k>w41_m201##Pu`5GQ`?NVLUhW=k?a(8+PVu~2kr+UNYOcVT zb|=Ngicyi6Y|ifh0a+MWPK>_ z2N1F`2kRLa@N0dU&-Nasucsnm)t#pl(0Vug11@5*ySuxgwe^DoeqT}|Y9LO7#sbKI znNhq5#^}TS4T;OC8boaO@)L=xptKPS$ITXY+};^d0}qxFFgiRe4Q`2)fComItP~-Y za(;(sfR)0u4CPe{+(1QwYsqOs{;9_H?ML0`XTE=33k|Y6@2(MpjN$;$<@gL_-m8HD z4Ao6@^t49R$9ZqqV7l1awJZR7)y5|)dVE=x|*FA>?!rDhC7@|o-!X@(KYb-4IQhWx;Zp~=LRw9>6h{! z-#mW~%(@#|184jIv>^iL{!krt^2ElG^*cS@H;!-;i_9?}+%v~ei#;|q6@kXM+*}3y zWcBV0>-@O}sshY>0_ojdN`S&h=?>4JXhjp1B0KbfK9z&!)Ce;#oXYSZ$nDzH2Ncm! zN<`>z<3|cS!~=hQ-4HS>Dd7}-Ev9F!gai#{BNZzRaV8y!<=3xYk73nRHZUg(eYg1cY3RnwS{Or`4!0nFbpH{i%UODjUh$ zH19=FNQfth@gZVP^fs_-aH7E2e|ECXHK*7hS$&IwLM@hkuA`Ti7gYKxfr6PReSLi? zS=rs_z)&=BZmo7W=H$egYu0^21Y$aX|7$TD6V6Nyn7}nTbiOk}ro4V+^z$!k->>Vt zke0x^LZ`fE){hpE-@kt!w6=}`e04QLx+#jjjF&eUL5Ilh%R*#yNVNl1fg2#*zJw)m zS2))>fV0ZVd725<*0wD>Fp~k(a8CEXOf!wE>g$*C%UEb))V!>Kuj&4Id3iUs+Hr!k zAf!G)$#$@nMiYrbMdTknOyUww>4~b|so*F*_4##U;X5WOZiB%yf=}KA%{@8bWq$Oi z&D`&wKA=kJWiTjol@RIX3}jcZ13*zgh0x%sSt45!3=|=;eS2XemxVO4SRs)7K4E89 z3CD=AGIp=myle|R;{F?3m`?RK)IvOt6G=X`sjgGVJJi94nw6F#Lk$*~DoiUz+WsFu zexSm?22w`7h+Ys}k>Aor-VY0GIYz-wY(dR6X>C1s;lkoMxKcroAE|7++&u)VL^@37 zAiGnIp;)tKjWX69WL_3Cp7sBnoqBKkdwLwn2x6%_hjaeI@kzb|8~uUgVqbkCK^Nga zeEarb=}*(_Bj*S>YG~k|>h=~zSx@ZEnk>okmg9VxNKr#T&)baV(d*4Cn{Yh$TK;t3B%))~B-~u*_oXQ`n zDl0Qy$(GlkZ@SoC_?ZjjL-k=9%E@c_cLZfa$8?n#dCog(_t5=&E9hii$on!})xW zS%+D|Jh1^$QS^CZiPYAsk>;Z7B$4+h{r2q}c@B8PJ}laiq0bJkD7!*xQ+LmvJ@!gr zkr_w*Sy3qXob2MKM9}_8g0A-II_&6cYoE}B{kHPyU4#ui zCR`s0^a@k!fR=%}H<6KFWEaka?=FR}eL<4z|7~{tzlIVEzy7~V)Bg`As-I`E3zQO? T825io;j>3aUpq(Z*!h10NA)>m literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_learning_curve_p300_external_thumb.png b/docs/_images/sphx_glr_plot_learning_curve_p300_external_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..87ad2b95840c4f1bbe63dc0acacf84d1c447569f GIT binary patch literal 28685 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 PQK+lvoXAkR==*;F4B literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_learning_curve_p300_thumb.png b/docs/_images/sphx_glr_plot_learning_curve_p300_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..f92e3c5cb2baa3737fa95de2a166ec14168d75cc GIT binary patch literal 22177 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 AwEzGB literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_mne_and_scikit_estimators_001.png b/docs/_images/sphx_glr_plot_mne_and_scikit_estimators_001.png new file mode 100644 index 0000000000000000000000000000000000000000..8f41c1c9926ec210f2a0a3279c1a76983230b8c3 GIT binary patch literal 32074 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_mne_and_scikit_estimators_002.png b/docs/_images/sphx_glr_plot_mne_and_scikit_estimators_002.png new file mode 100644 index 0000000000000000000000000000000000000000..cf942901e166bc634a1d6626fd93677f5e2737f1 GIT binary patch literal 20676 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_select_electrodes_resample_001.png b/docs/_images/sphx_glr_plot_select_electrodes_resample_001.png new file mode 100644 index 0000000000000000000000000000000000000000..5fcefe02d1b758c99a49b4e3ceb1361a3e40e6e7 GIT binary patch literal 31498 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⩔h&u9o z937_yjJW#^t~gxwH@d7>W*47Uq>^a=r_pTbr&9>ifa%(ie(P^14;Ww{++89CmD<%w5OOt%kd=|MKU!s6PW+ll~qJSzjki z*z>T;zv1p6gtstlkois1r}>t(WLnD8-^2KiWPXE1X_F2)VtX35B;-4o0oF85pYB`I z(sM=&6OhQ2{Kp@EV2&<3sTclCUxT4`p7XyKA<R!AU?lrTHBUD2m)B( z|N9RcrTa@L=(rMV@E?b{Cbx|TOM)6@i!LU>o(($mAu;J^RyblkplU6`J~H_kk`+)R zCxBLMKRYqI(x)O814_%}1I~l}GecMhmt(CnB``VT{m&YZWi1p05oqv2!^n*ae`+oG zhWx6^2KmxX9Vyt-poLrpcl;H;19DK1B0m*t5P9-`X;fEEYrSsF)5hLUZAbRYO31Dl zA-=i)M~S&%>_OA2jwmm^GtTQK#Nu!)g;rWbM1(Oi3gill#3tR2 zuam)22dO3uZ;Nbgb+)xVf9UYx8OFxO>ntX{sMksL`JVOD2uK-dG1rsR>}Z+v%L(oZJ~;iGXt_Po1&{ zWVSvEZ(BG#xnouzJiZ?B#l_j#)Z04)xa!;{7}*d&FzWWJuJrCtkHnx4(V)TbSx)?f zgoN9dY`m@=Z?2)nHT-=5+ysq}2eH34!#z4YBH~WMRXtgZ=And+6uq=VQdmw&~L7!9RHL;Od}p=&m8LmwfIdawDG6pY8#T z9<6L}FtA21`Bh1Y6LOKWtLy3=JFdI$+({!;;3vz(&j;1$MZT{_5l5B}n(J$M>NmZb zHObi^=xFQ0GWYq@CmN!ltf+X%+Fdw9s=5dZM~wt%CCh$}^ah zNi>bOURBJ|!rwoe+~?Rdx9>;@Rl)0};%|_}L%^*?aw^5OZoAaEj91$TWd)5j??||S7^X9r5PuGz!RcnyBZDm zNmEAz7hktcefzEP$Bz?fX=yuEFiu!ZOw8HYnV+1TZ0K^ZDkH3*_|csoXa|L|F)z)2zxj=ukaQ96##lO_nlD3ZKnK_T~PLW!%-(JL&I=Z^Pg5ZVu7waq( zUR<lHYAb0%wXMMnUjtbxDlRUWUhZS+@KB|) zsKLu|>1mT`hf0;gA}j7gs5^WmR9WuxVxWk~f0UVY)Ae*e1t(8-cMi53sI8Cg!_H(O zyD%_=Nwiw6*NCQ2+K}tqv0m+haR;02c1?{RTBwBZuhu4s&h9m)R|^*{N;JfotmUiq z6_-AnHC9zt`oJ=JFFyvXOWv%r&s^k}kBod$aQyha5><5co~2ns%Pzu;kBW^=0%O?S zXfj=A_-4^AcwnJOL*ei5@8Kz)Y=CB(<07(z6qsw6Du;GdBKgJr5 ze6&O)SIlQhGav-YOF!@Pe}C|J%ZD&a*bid*yhbSefC}k~x2YVj2FE{}dpX3vBL_

%q>ysH2|D`gT}Uj7QWfo$0XOM-cUfIANYy}i8$ z2L}bT1L})Lj{fP`uf2&{|9}8d&C(7CX##!d?jwo5;^o7xHEHHd9Ix2XVmQ2-zSd%& zAIfQOZp3U?3}?xq+KIagQFMsk73G@nsKpTHY*p3GV@uw8`17v3+Q2sg0-}Y%Ch(~k z7O@;eX|>vlJCcB9vlE2%kV&fyJ1?_3op#ZiSz5nVI4u(%#XbIVM(?u4}U| zLHW(@nt}Z3;paDDP`;ca7k_HBx4ON3lOmFZScIH_Jsb0r$wjz<5V>j+*10RKkfJ2w z;0wBYc^N!YxE>kJ7oa{lq#3PNSQ6UJv<408K5>hRiK&uNHNS@<&8Q9!32BM#NjLZ$ z#=I*ySP$!n0&um$Y}4x<*nI9vrxDDi99-vqRmG{)V*+kak|y|`udCb6iYAu@V#nQ` zj!`OAUtItZ5HxPQ+`!-QzJakZd)^bVGQbOXh(h@m3x)81fcEO|zqyhn7KT&P3I#n- z6u^pRUYkArY268EwZeP{OJNd8cf)CgQ))bVXq4!?3drklW0-|RSi_{>?~Lo*-8Yh` zy78tL;{)=f6$++#7Pf@vz2c%G9OqjvFJX2}IKsddudMu%9;SAb-6@lekVkP%?P3)E zyIX_qNgX$)w5QlxwLL8CXliPzI60u`86pa8Ied5XoTJXfc-d`wy2SpLTsGg3l}E67 za6(FuO%MeN_&{tI0AR%yLf{hO*gTMqQ9F%_bOe}3gH`>=&XIku)(YiGSOa>;If97E z>MgK@CI|dj#QKQFNq)`}^is@0xoe6I;qMwk;=lL{ DDha*< literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_select_electrodes_resample_thumb.png b/docs/_images/sphx_glr_plot_select_electrodes_resample_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..b31ef677174a02112bcbeb9546d6c08082c9daba GIT binary patch literal 8474 zcmd6N`8$gs^xv}X88(+C3sG46elb?Ub-t=Am z;#RfUR)n>ELHaFcd&k-TW`n!F$SVw<>o!$*t2#kpzA;rT5N-jUTC|!pWgIS!^?7ibv!dV8mNT7c=00gf$#5~ z+bEb-QQqF(4N+0;eI0mNA0MBm#l=i5EiLWc-8#2!9cO6nd-Uj$hDh?{=3+nXks~-Q zEpj(EH`0(@0@=>2R9J8CC6DDHRvR0eq82S2{#5yJY{|!6`aggEn1Ap)gT-R4<10ybWDuQ!-D{vj*iXjrxaRxdN$qyD*T!#pU~&|LSy;!Y;Xn!M2V6^oC6RS?b^VWN>gmD=3#mLj zJiTAPhQ;%$*iN^`k$(S1^L9wOKAaG<@t zy?&}C#&zw(c67X*x48fgSC?}|eEo<2noTo-)%=Zh@PeXOjG;NKm)bN@Z~h!$U>7yw z;B6^(MP5AspX(hRjWxUZ;OdtWn_DL{;JhfOAGO>xOqlvK89Q^n_fhP$tV$JSWwIH{ zp7eHY@huRyKi`3{+znpzFW)BPkHsj_Knmws|jQ|50=e}EgLFbr=@*2@O`crJ}5Hb z9&2gqUvu4xot0a|y+V2da`*)nO2}rluxs58)2$U=|{N z|L?D!v@>_nTH4ykMFg1hBBY6kL5ni!owr394`z3*1vrH`gKyD z9=~RhDH32Vd8f1m{iGJSpbm#ScN$KX)RI3rA8~)Idi{gS2v-mCbw$6;6IxnY(#}6r zae8_&@zWd-Tw;@lo<6$mjgOuWBao=15j16$y0%OmgZ zeRtVhFjn3AY9hg`(uAyiX^G(^5{bcW{0}h~)%WE(o0yQ4s7X#v4jsJV&p1}?sqNw- z-PvUHZ`nqUhnSTWPax1fd-hBKi`DWF-erdazO>>xZ=X?V9vK}mr~WtK!Ue{pM zU&S_8$I@pfQNmUN-Q5ZYxsGx?ng)c0abL6bp|-a5sXDiuGimpCMpI6jJ-u{-G?RSM zwjqQngzZaa(lVQ=jg24^uX0$Hn!oLrX9kLae-%Gxsl^mq)l3of_=3-iP@sy7*ecko zB9F~v-6w6kMRt}XsE0NLT}YP~6cwcr6BC1rVb4ff4Z|}$d-@b*^8CD}qoa7x&0_17 z-W&?#-RskB+AsQ%EHx{+5grrsj7A1qBQ5ihAy;Kj@M{l4)_qB7t|OHmi)@Z}@0R*) zIqvN25aRW{^~-uP4h{}ZNJxaW*lOzNQ0c~F=m79M7Qax*J~>icTue(x7yS4!rvy4? zp%RxQO3_=B%ugOLYJBNZ(38`*0c59(-v0>6&dy%&!Bcgh+nboxj{qppv5ROF4rrAO zHnp|UoVM=@IxiAhQ=?*QYs-Scbdd`>>Uny4?!ZMQW@N;YNG>RiCNQmQCKk$BkI=y@4XjFT_nKNf>y8kOrUa*vBJhNj1yx4v9$m6Qo78weC3Vg3g7@#DvZv6^khSu#}SzAEd~d{lAp z4{L8lrVb+k9G?I8+IYgmgmvw~?o#D^mj3}s-XwA~bW%;5<>&mcUj%ws9e(!J9;w?R zi}zRwiRI_B>o>P4|I~M8z8FwpLtf&Zl9J-!lSW~(4Wo|v@7^ESP{ zR({FCBE~pRw^UU)7Vu^mxpONk-cOyKr2&830EzTGgdOdmN~-VDhm#vVmTajHrdS66 zh>6!;38T`&dAB&oO-1qt)<4)Di{w6SPk?m-teeWDckk>jl^9>U7DdH?e)~~FOo{n^ zE<5q+WfK!(N=i5!DSmeH8I*M&uh_{CL2vi>NXwhtK7ZHSuJIWmn;Co8A5N9F^DxO( zYmp`*~-RkOKvL~GdQu1Q5jh5os7jaBaR zECU~oWnow&12bz`zvqW8I0$oXYY-Nmf6i8Cj%f+G)Bk)jCz6jGReOk2cVLtutxqhO zDyabN?8i4)*Ux7^jL*oxytb-A%gD$SWhZykZwR1}PcRml#{B&0=umO}wZ(fTw<=2y z;WCp^3c*~{7e<*{wzgOaG{am^cF)FBbp+#3LFe)tAKwg&f-U9hCGh1=CsItXp^3@; z4szzDwp4un%Q8^&q!Fg-dr~)QlzlY=%XiDczI7Lvl&n_gy}arIy%0= zcd#|Lv)Gt*8a{rbhu8<_#SXb)c8@(bAC8YFFPwcO5r5J42ui;l+`LH5l&{kgP6eDo;n z)hqF^$Vee!VVsAsn=Hh_O#^VAw7%ZJAXOX0Dx?c(X%r3DNFl=$rw=6Z>S`ei8(ZUs z03sTcXe+KWrktY!lnMAfeEXj^h|0i#2%t&K%#7o_8Nhns!UcUJBYWROtHfnW;In8o z|K9><&+_Hz#%aN6faW6rGE{dL@`~QOyV^u1JuoR87^-p?MN3)|($cv4TnX0=eh;5M zeVRQ%b%PermI3v$s3=@3M+2e-2?Kf$f#B+D<&SZq!}+bPy0z=A$J#qPo5l|hyqnwF zV&ZWg6rd0RvOvmMmzwtu4G};>ZmxXiRL*1qT?tVXPoY=NjHlA_THN0r*Tdt5BN&f~ zDAV`x1L%L#W>yR1fB2V`j*bq2UFsuTL0w(vk8sOU-oJm}#ofJ$G}&ZqY)l3+Pg&Bq zFjK|5@%#5<44jfU4UM1$MV!L%Ve-YHQlW$0!MY!$QqV@@W1sP|6(-nR3yZoywT+Dp zBw12vhSfSCO@yl8BLE~aewz-pJ5w<(-rk(NQ46WUH8ff?Cy-3^UbRd+F9InPIjhMO z3egeJ&122a&zA=1AT=@fmEXSDMIQCV5pB}>cL za0brkcr84_up>jj8gFiOq9rUVS(sHx$Wi5i!e26`JbGlk_$40!c4dzR0c9rQ1&}i% zK}Ii{TH}sQ&d!F%9aFH~Ax-8Au?}M(Q(JkC9V2FB9EsBnee*`zh)?($q+(f4vgk$Z zi4(Ntw|iOvJ)vG4P2jsu^>|r?H_YMc$SEkU@y&2xsx=@LK&|821VjgWdxJiGI!8%G zWdouKNRO2_>ZO&UM{qk{c4ltQc7JzE|H6e?!*Y|F&aN&T;Lf9S$L+h)$fTsC;Mzvw zwAX?;jvf_MRmGe-b?X1gm5f;3yoMa@NYZDOH34~fQx8n8*L*M4)aq(Hq;Ml%wqbDa zvGWDPmE4>hvbB$UlCAN)F;J0F@!G<%+EO+x&CS+BZ)_YK9kn13lT%Z@k=jhQDr_~6Q3#p?p+J88j#3sc}S)!Tb!&X;9BqDdWlgqi};$Z~RWBxRN|y1YI@|BH)Fkn@FRCA!)`+GD9XSf#b)I zw|8{`H3r`(nb)!O7!*HwveakYc5`Wv8G5HzkT71|ISkMIw^tDzIpd}TXR2z}@Xm+M z4DvZm+J-zUV8Z}FU^z=$eY(1)CeMBTbFN)tX#djI&PJz{>s%N2>+2QKFGASIL?Xv= zqSY4AOtvEZlGCs(+ySq3aALpmgI&3~t|y@{U!JHvJlG>`Z$m+~=e*Hq7qj{pziTwEt0Rkdw{6HWRYE6mI78N2LH%ikYukGUANO3o0L5plh!b$Pg4Fu9|*;;vcy ztQ({Y=0EN1a2=1Dcs{jgU>>`JzkeX6C2+JPfM(%t=*~W|3oU6^rV8ik>T2#ZixMNqsYqsiUC=;* zyNjYAzMwVD0lov6L7|d6!hp-=&YUU5VTKTvo^DI9YYd~4V9xat8K!H-%W6tKZn75C)3%h`PEu4u>Pe<2GNw$^@X%!Tw%M{6?MA zyO~Dyv39{LSFhSYy0mw6XpVn;aE%Y=rBUWDAj}I#*YWf`ljZkQ3?VGIqrMVz0sMQQ zpo8^k2KYuPFaq}aFCyx4A`L&pzU2LE-PaLiblG%PN}-C<0r8+(3p)3^yTTT18d{}nlY>YmF^5}4|XNb z@vI zK+pPec@K!2e+4iS23id?4?@L|J5Sbj^@TMvG+tf^*jsrIeoRYw&)Lomfus{g0(g`8 z&zaiLl|MiKBt*>Q`5RRNqPU08Lk=Sv;p~H50Re#^h`eit#zHYj9wc%4`uY%hXl!i6 z!DV?tC9a->(Aj^^h=Lmv6c>-4)ttd81}6?k-l(O`G>Tm8e__{^CIc}wR&9%P2SoruPA+Ez@Xxe?TitBNZ0eP=p(Jy@~(hdly1rWfC znhSWCfKV@~J5Yw*v#_&Mn3XY4p7Vb2orW!8_w)~c6UMO+4JX9 zS^ldwzASwgAX28VOXy#kL75-|va+TIWDw2^E{+Vv#D6wc$$joA^z^`wfa!gwT*+PC zKnOt)p_MbQay#y~_4Bwg8>Q!UXaYJd3g-fd2qwa7;#88`HMKQRww{PWQ zF-mOx&o6-HBw$z=nma(4AT|y3cIK5XIRHyD^_5Ypcm#leBtTaidvIXgTrxB=ni2Wn zy>>%bL}Y5cjUUNVVU05O_N}GCQV`~kQc}QoyQPF|cWTPEp=0FcjT?MF0{8BXK0Mt2 zhvD!Sw92TGQd6m`EaUh0wkc4*SI1&tQ(zCGf`E2R3&Z;yIMT}QEqW*~50z4YUkEHr z!N$f0X@R99It3#Z$YMWDz0@sGaKQjOpb&u0bE>Mi{eLevK$=fZVLv!)1BN2W0|bW! zUGUF$WF_1Y9~57?uFEl~q-cqx4x>Sqh_{ZA)p- zIr#g1-~(q)&)Aq1Je1Id1qUR*8ig$cP}e&fySrB+4h@OAd73~RmR45l9irLwot=hI zo=J+(fGZ`xe*OB}lJbqfKetk8SSuLNgisUllp)X+KLUPT@L2m{1){NKq2d~V<(YB;6@WDWYfFNYkg#Lb91Gw>rp_;?FI&Z>{ihq_f}QH!ont2 z-jC~Ex|E2-yjd|=G4agZZxf)~pjTJu3?+n3Q%<2iefk8hiZm$Ot}L~ht+#kAmZ%s! zRMiy8Z1ulROF44HfTF~^YobE%!K>(bj?gxO-->% zO5Atu+~HCWRE4)MgQ`{O2cHtOi!FrOXYR>u5VhE9F*G4lnkR1P?HzV;aq%~x3Si@e z`%#AGUQ_Kvp-PuY^11GGQDu78zI&6DSaY~wLY(|)RSHW=+Pa>c&M__Q%Qxht zq@)DS!Qqdt2EWaN2APtY+7_y!64c_qje^BF5)Az_cmf3Qy*MDpB$%;Dltu#g&VvPB zWGVzwI6H8+;Mw@&Oc()(CdzyK-EoEL(JCC6f^Q?&_Uw(ufySL8>I%m(t1&%0JE7kz z-y@G3rV1!4kLY#~2+K4KGYYa&-zFyqxYK?oNWA=y(fjWfBO_y)f-@gIJw0i)W-Zrw z{NugEB!a#wy4~4<(cZyB_hp4{T34#d!7lUJ9Tbo^_0hn|Gz3%FY094BfA{x6WrF~gNIdKV3)^$)TSI3jL-xZ1 zC2D3q2`DDwm~AkML?Q)UE@+0WqfjtY2rys+QcqmwBity_Gcsbz&C6qDV+;B3KOW0U z7cw=!O^wHrR@a^9r=~)nR)nxv@`roh$625{rO&Vur=ht97>tOHre7YZU_iNS%or?x zf6om4i^8ZR=&f`GXDCe;D3k>zeJ}EYqN0{CI`%j2^G1Nzu{>w!CnqNrT_#Xqc0KKL zc;h^N_KKOA9oPx_hK8XXcsAbebD+K=z|@8TNmRV8J2;910|N`-Spo~%l#c${dp~p< z%xEwapz&&Gn*Ke0z1|o)E`VZl2{a`8xz+i37~cGv@38~xG&k=pcL!Sk{P`oGNFovw zSvWX2>IVloZ{4~@OG}GF?d*&&O?tn@Izqi z>~60mfc4vU%jU;lp9l@J^(?SsfV= zou;N{?_!|uL-&+(TQzm9OG`_v7>tCtZF=(VdchU(oxMH7-OjV-V2IK9INcI%CmfT2G*HwPrd1Uv+G1|0iQYARMujTcC@p`oGu(WV2ZMgil zj$S$4hZ_k(dhrvVQcl7IC=8MWUI_Xbr&k`8nu^9Kd(gs5LK700p=UuT6U2F6pHriQ z9I_1opjzXAU|M)@Y!7-gO4Q$Z^+Rxt!zb|XlK=ZJ8fI_H zKRz5okpR@EKt;ezCnR~eb$k3_0`h3MoCeifU?O^ggC0&wZ)AULadGh_;2o$%q%{Z$ zAqOIz0uMh72$*-Rm={D@TwGjHUAFpP62%qqqwnsIi9dM&H**dmk3xYABjn~{fk3B$ zb!bNT?alSCWb*(Rdr%&iX8E5epuagaHt34 zhZzN}&BAz{I*bn`Z+?`JPm4pCSYH0!Rx?fhI3ReKu$l{ z``s`;&VRcns|BJ30sc3`$-00{wJhE_Y5Mpmg2zMZ)n?9l{rU)0dv4y?87P+ac73Pe zGAgSYFP*@^vmEqP;Fbi{*K72xJ7FaynQFXNLf{JM85nG&xu8$E<-D|D8Us=tKpmP@ z0^9|pX;XJMBMeQ6%{NlPNQ9vc#5VzPP6Px{Fx{*S_#+F$NnBgGn1OTdcx;~o4yL35 z4<1+?uFTDe6cqNPoI4Kw=+pj1_ykq{Ww9rs<`b>c?%v)sD1&=)3i9%egM;rYRKX;f zajU``&F`;uFoPPAl$3;|NKzVxCJ#&ou!C!BCstO#jxnU7CB87b;M0h2&STblwb1S) zx=8R~z)9NNYz`u$fGs{XErb!Kv4sT#)FRXzcr`~biY$1*9ugy2dDp3h1Uuw@{=b zRXS=E=}MJup-5LcY}otzt)0xwIq!V)&b%}8z1Q_!*ZCs>Ve{;#-1l1RSJv9U{-}AF z_tVXv^6>ERGJg20HV@B7>O4FjYX509e&X+C)Q2x}t_Ss9k2+bodRRDH@@QDNp0;;# zwYNF`mAj?0i;a_`l(?+8^zN@txw@Wqk(ZEg_?H)mJ2_iRypM}Bz(GDa{eyuE4-cOO z{kQ6_O0o?PkIOp7U%xwcHfF5Hr@!3XmpH-~_RF8w@BQW0FJBx~J@x(F?SD%7x$bAdgu0kM0Us$z zZ(+e}4B=0*+NWcNio9d<=aynz9u~#Trtzewcco=a`c8W95*0PFX`DaO<1<~4?`wblho*1-NUL8on+;%v)Nxw#i7Tn57Q21U&lRcmT%T^_I3%X9bK zop^Ygr{GYWcV=b(mxJ#f@ilfAx#YGP+DYem(s3LNOL%xrF*X{X{;t?{nCZVVYBt=N zZ+B-XNi(+id%H*}YfX9Ax7pth8JqTcPnPA`wTll7u-m?`jaKq@mv6L*yP zlo!nDxsGNO4yNZe)SO%OVbiSx0WEE9;suv*Uk2~q2~v#^H)+bZYv1D8f4x3)o#)bU zvP;X6!qbKADM9-{r^|8Y<3VY>o1qL2HZqqow znFDqUHvAFfS*B%8_fAy#Ot{3?=GioFp53(X)Q`%nj>f?UYXs_ajU2+} z#=ER>C+jcpDc=w*dK09OGn^DHvs^gcAEG5b>%F#eq?XpEs9i?B?vtRc(bn<4GSRr^ zfH|C$%QS7WE~g6L28GE|TH&1KAr%+S%Dgp}l-3kGc;2N^N%m0yU!!dK`@pLLD$4D~ zE*k9FEdPN?e~x!&fkW5n^1?np1@DO>>veMd*S5I7uo!Mm)*2Zd&7CY~4LbR=jLMf< zv#cKR%3>WWh6t>@J?#1Z@kW<+6AvLq9RAK{E;qj3D%v3&Pf;Q)EX;FpAYyvHg5#TF zI)8vqDfGylLjwsRnyR>^ndM6(WB01IdCojP%-uA!+lJNq&h3ma(dRfcETK+W= z70Uxyr-PwKHEmoQrW;jM#yj(C3(IFSXanJUJNF6glu#@P34c~s-xRJyiQn@{!hlt77o$rwi*yeR=urWT~$f-=4mh1$U^+_@H(e*?(tV~%h#_A5_O{QfwPsHj-oMGX`@uqj=&DNFeu}^; zw{PD*cI3#B%`*1-!+Fh`qCJT5iHp-ivLo|NY7$|{BWm%i?jcn-H@CpJw5%+NFxA8+ z+;lZ8BGGZ&)W9WU&w;Q+!9;$i(tEcYhGIR$g?5?X?E@QTIV=7gvy{@((i!9(S=)-a zPCGS*sy~O-r?q}X*=eWX?AEz{65Qn#qL0tP=v9zsYA zG(UFxins{2y|nxg)?4#ipI{aCS)2py;C*w*G&oMIOM_gXt$ll@$#9sSsm&>GWF}Rt zU~#M|Op%06cw`RCGIuXpmxrAHnm z=VEoB%g`=E2loJ##^%lm>pGSX~ZMaxxtsH_# zY}MyGUw>3fDeQ_w`F`BDr^t;{tUgZptv(Zvo-l0j7~i=L4ff^Iw*{&Gi?wEwxJfb2 zHM;_rw%{43WM(!9a2Bc#y%7-=r3fQyivZS@^Xd}6)zfR+Bb9x<9=)NY$m~ab^aJyf z+An_dC4GtI<0}EjX1=KLqm#FPj@tz`?7=@d=bJDG@@k|pU9R!f2Mon$n`I^6z?(m_~IsU18T9% zazNY;$qtQ;Nu=7MxN{wxJYKz4gEX14`Tp$#|a(wlmjuHA?R6k$UIvA2rmd%bfx zY?gJsbi4iALb?%1{Q^aCNdDFcZ5@8B@uMPP$}>|T2P0OC8T#J);eBpKT3RiI;IRr0 z+rT>3ZF47Ub~J(;50Jsz`k9$ja2}i!T^!M?=zOdD6e;$^$jHdl(rA|KNa6EC{FX1W zEqJT0=$85{HOD*7l#AP%&9FawS1q(>m3e;dY@5*#PW&m7VhBY$>zFf#tm>n}KIBu} z!(q=?gp^jaGdw*#WjasYc^qf`oG%mA)y*T`CGO)n4f3P=7Qd4*uRJFlkx`23gAzy+ z^3$Q<*>*FPYJb_=N((P9>gvU|r;5N26a`LioY$T4#=Sqa^Z98T4D3ZEr?^a2;t$IpY1^SB<$z%BmlUUlS!= z6CU}@NNbu!+(C;f=JLv@^QlzZfJjS~okG@zeS#fOW;odTDirZL@NgeGA4+KW9 zAYx}&2!zo&Pjna6`#q^ItE#8`5+pxz*LAX2DOTQ16;(|RmdDP;ck{RcGcDZ75dXCo z*6=yHDk3J6 z_TFa{dEyo4=*hJrm)e)jwsm-oX5_M$Mu*Gfh>p^<;n@pSDpoUZpKp@3J*JE}FoaYwEy)q`JMzx?g++jLN#PGu?3zn_ zhEc6T0<9a%-(95LMWt=-;|)d$N0T*Eva%W}njd@hOf;*MiTxyY;L>N+sO!Vef4C+I z5wZwH>J(*wS6iq`L{g4M9u`=9B*4Cg{VYqRuHV8Vfk6a{!;eaF_ZuV-Nvwtp^Q>zQ z&my5%QxGC_kd{?0zp^x|)>Yu(Lglnx#ga}4`wGimEwQO8s^V^DrZ{a*$rDem#`rA_ zZ<0Lu0|6H*P!Df)YpF7P-tvXvNMCzXx&M{X!qPr}9$gc_E9K7#S_xJsFhZDuqnRa+ zsOF|o?ZU&LA1|X$Zv6c4mgmp> z@G!*AjNzV8^rw3fsC&N@C`H3|?AfgYxwED39ow6JYnM-I=_v_kg4X(qo1Mp zuJXfrw&en9V8&FR+F$1S{5hc!5ksg%?WQ))9efkOClKd8-Z@aE!aj4yrT6qBUIbK| zInC_{%@!VRoFe!J{9-rNjl0G_v5uayaHGVh&X)@X92;KTJHbC544~xH?@_@ramQH# ztR~#P{q>qHr@y7ERb-9jYCPHK^l0hG7~%<4e0PjkZLO^X1jFz6U12lLmVLxgZwe2M z;c(1-Mbc+nC@t80afl$7#^A2=RPf1{!uz^EAHI`%_wLhQKHuSt^563HZ@==6H>z-aDE}sIj^F3ksG6vqdH?lg zp&*mI!!^h{J$K8B8r=a#8YhtmFByHXbFwdTnASNL?-mz({W>i@bf9(iIxEP^^Tmb)*NPdBiqA{iZqx}cVv7m=g2Ry}6jz&h4;djV8VpVtJ`p&qsUsG`r z#p@9M1p6RltNV-XgleTM9{$V)(kStx#sZI+n8e1qckbF~=5q!)``W4xS96PBQ&g$K zL&kaM$31`{wm3iCZi5g)(*|`GeeW}FXI5J>SsslLAWlg@Unx{jg|pa5=RM>S z&oZWzUKb@Tiic^EnwFM}tR&>=A0LwCJ8oC>_VyJ?$L{;wBjV_$Uc-sqK)*$=FN-?k zPRX>mAm#US*pnQ|v+rIKUt;m5_cm67LWGIC0XUstpJ6pK?tN<2(X)K_@&SI{>Pv%(q0%2RP!#M5;LZ>(CZNIXW?)QKP<^Xs7Z>M3in+5o-B|tFR$mDp#%P zpQ@E;ME%rr+UOPT&0fZvRsqhuKPLh?P9lD(CD|E=O{7W*m@>+9dT;=BHCsQ+`v|WZ ztM|iiuh<3}P4iSvO(my6Y!-ebl1_SnF?$|H6zC& z%M{QtEg43IO#s`*#X!fKXN#t4MAeWVcI7*C6|^L4#WxYoZbIGBe7BKa)_L|#V04BJ z7IC7$^2;@exWxMwaUf&D8-U-nQImo73wv^P)6q^)EvhT5c?pm*nJpFmoTiNx3y+%+ zT<`zZ9+Tj@{Jtu}v1lN?38_&p6&Th5|ETZX;8qj5EAdURO8LIiFDte2pwtlU#E{_~ z6XRFLta*Jm^yn_&Uq-LHuap8eCqCj+DLrOlVlvW{s5XpjB%!p}AEMzXx{Qh}d8Vk* zH?sw&pbdUVmGI{<_!L{`E1lXY$K*N7(`p~C{_LBuhzQx@)-j|MRuhoFZYszeUTn^p z3j)hGUEc)C%8X3^_N7*6`NCs~aN=CF5t36pCVLYb{pNB59m`6e(lGmk;f8gPhl)1hNw9#Ks`e7<#lE|fsI-r4-h2G7DX0+=k?lg= zk%bNwPKkxFy%k;#Ixcp1J6zm2-zzbpc!j;<_pXma0HqTJK{U!17N^rLD~uT`UewPN zUI8fCB^ow%>SLZXEU6qK6=)$DmHb(G`;$Qa2(XTlh273->y&1mwTZ9c3190C>Ni{8 zWvIcS$sP1ca%rg|?$lAyV;}K|UQz-fte;MRhM*Un7pNv-e-y^FzIU0ejOeM%#X9kr z>kyG_ey^aqRO8s*%^E@K_Hy5SH7O9Fy~6@AP1OZK>z< z=AhBhQ7Pn9M4BB~ezj@G=-fWu6{Z>~ZKu05KN&wY73_DuUPR!AdYqyh$Vi)(Hf&+g zPgYouL^g)(-Du)^gm&tBov+iUWZw2FTu3b$$ndb6uA5_T zdt>A!w95C0uHBHCcSUuTezjYtdD#qWS-D|c6Ji?4Dij?f1|fpnE;9`QqofOP661s1f=?oRv`w_$#@LH<3M^Je7SJ0 z*k38ScvzYd&F7=j(x5poot0d#dB7-Z&&vZEUW2{ILR)2*oC^JVua?fwy%{cK_h#sC z;z>*0ZkgCEJDV{WKibni`HilvfX8TH*o3&8Kx?+eBS|E}Lk`4zU*hF&Q(gaHJ#)6zWY;;Y>zm>R|N_D#wOcJt|7iKCY#{-k>@%<*D1 zB{gKGN@t&Po!7NWJ4S!D1$Cd-@how(N%=Fz{EaB&=+^K`aKQ%bp zmIDL3`1gIasekF1e(N!}k?2%SU!#)Gc=U&Nf2u~>0)nm2SjpXIUZ^dBqeBpZg&9k; zqwTLdp5IFqWGttiFDonuev>?GChT-Xml%i*jo$Sh_P zF6kr2%nxxcqR)sy{Ze!PcA`W{zKT=w9xUlwal}P3lOp;rl>@uqXE+R=H083a6 zF23u~kPo8A)I|xO?SP^h^AkO}h~}1{p9Ksbt&ylEeL)7?e1t}`D*ULlx6g0Y<(7qlgysQZ zT|hQ)wGtEpH=-SjcYV22vktn+{T693p{DenREZK&Ch2M0*_Y=x;5mGa=kOInTO>@< z=~ee7p;tV+RR~@pzHJT);N=eoh}{JutA0)ZRC36hgQDtjULz@l0Oyvp z&rf(FRUu7h?RL|Mb|^4-#4!Ol!g{ts!5}7ImHJy!7FOBmMD1Oi8?OFrxyAE!rh7zt zQoXE_S9x28#2qjy*~b(9kOCG8z(GhImLWsRHLG(Tmki>0gCs0JIHVs&i(2^=d+#v2 zoAYFnKd8^s$;)rPMnc=*NZ4$#L-*ydRq5sI#YTS_c{ZTsb&y>W*rxS!9QxOep#8U> zzYjNZj1*jq=Pbrw-7GDFfT-!_HtU??aj@=Q&Kbr!Y;=8aj(0)?Z0CynHT}##)&qC8 z_sr|xu5OW~FoJhTkoPe#7tYdhg*!JTJerx3ID3HTki5%tdObtn8<>RSW(5 zU;na05?Y*nZoNzjz$M-=Cd+R&?aH`6aKa$4T0My`ek)4@#DNoKC&&m`w{?m*pX7Ky zFJ&Ma>$Y?QQlUwm+hD|-^Yx&9M`+mCNEp%`QJm7!(rM#sczLq-tN1S6R*zRGVz91F z81!&9avaCkZ{Hwil zg_CoR#?Kg77rKrp-_Nf-zFsDQHMsctnp1y#$hM~n(@DurRp&d(``*nA@4uO^_Tf3* z9eY-t(|MX+XjYRJY!cGMDS6ztTqGrFx3rL++p2f8$K?l6y{c6EadG~W_%F|W6Hok~ zApX8QJmR!7u=IYZ&Im`)99Z+;>nK6!Nbtq?qU~R;m{WoC98W{ zi07Jmq?Ce0UCi}4ht8AD6J<^1f$=xem6z>SpVRrFWKK!ae|r!P zqZhQVgqfGJTjJ8=t3T;nfm=a$d(RR_Yqg`-51npr;{9x>ewgWm+4+y{*kB0>_*1pSD@yR|D%Ej7snvTAAyGd9p8m5zh0>P-gOZ zNyprX`?%!YVlVEW;mvr?1)p5W?8$NAoDb|w6%mG@6kJW@L;jqXgHWm8R$%=wzjrWTe&m^_?!r1=jy7|l*EOI&*1qu zTrhdl&82gLk#*m9ql0Tl9k1nHT3728e^a49bY%4C{M2tPO7ACI$`tn|E)7(4jKiNH z>H79rH#8bx3$-bTv?mE$yS1CR05V#4=Gk=MZK)_CwZW6UI7C!qB0LL`@Il;hS%FMN zOd%EGgCK|NDdm8>mQk3z`P~KD%6?{l4ja;wZ)ct-XNV0T6$^GCzq*LD zOoZPgRIpr^05S5wu-1pJ{^j{=w+KX3{D#3qjlvSZM?CP@5)wt5W zVgV@4G|06YfcC^GJAx9DC@49ws!YLvt?v3<{tGL@5@K&$IHg6HWFyKlpg#Nx=9baH?ea7{a5g zzqb7Vtx=ae*mjjtlAC{GSs3~zez%0Bu zf10%tejzQhSVUng`#?d5RdfszVF%K6&goYViANyUk8`z9L_g)~?Ezbuq?4fv@`niG z49T)TDcaFcTw07Y0AUBH?Pr+t5@iGoQ0x+@ho&|7aIJ(oD5ojhF_mgoni{>)7}Q~n z2CkZilJ6;0?;K;Z1J^4*I+b8=-j|SLBAJzaz}>*0rhV%R`Gc!?DphZ$mnu4_6n3#Z zstv9duqMNErUr6Zk3mm_5a&u>F*bNY*$`n3Qn4sy~5^MTkHGe-MM;%oz;416lRaA(*(NtNP zv1;@sx{^v`s><^my4;J(gZM;5eM7x@Gm>oW?3xqRB3fEn2zlq%p4Zjmw6*Lm<-}Ke zb0qfJbP2ETa=Lzbw#~NZA(qP~5GdYMVC7&(!9X=~BKFS2@W#FhqlPtlQLf`Lbj1j$ zPPbGIHVe#oijO+^imIOzu3^nwsMZrMwW9R1Ka_G&Y1Rxv2>Bj+GLI z#Ca^-8_k4u0BM%XNT675g#PC8?7KC-W78SmaIK8EF=6Vyv+S$>{csB^<=@K4IWcLU zy^=Cq){q?0RZ1=!fEFsflTK6x@s86@3PO@pL@`2AJuOxlhh9z**;VN59h@^!l@P-- zj7%h6Hq%6k*&>p7g_?laiNfkP3U@kVW;^gh|1hRRCSP7_fAk0A+s3N=^B|X`{vhfI~gF;2)qStRY=l` zS0-_11OIZmIv4V1|G77E`D93#(7|adt!jl3mEP5<0#-J9S4nWB$dn1XhD>0TyQEG& zy+%j* z;jNYr!Em{ev#ce4|K(4?u0d_Tmq+@aP7kR&J@*rM3|2n^TrkCCwXv={hl97cKKqWF znUJTfYQ+lc5+h8bP~Hsj`Xb+j1zusv7KQ*+PuCIc zQ>(W+F?Y|clO_KhXsxc3b(QBo%!T7p<`Xq$02VzBW4TB zx!dvG=QE~5%^>ZDN~IR7>*A%9#^qh_ml%Rnxf?kRyl^r4wnGMzffG)$AX_8bl548MP zS>@ETo0mGt3H;rK)dOqI7QUZ=@5hSO7^@(Q3P!6jPD#qCw=~$KeM*oU3xe-v9s|j# z5+1;jl5f=X-|d!Iyk2q=4C{49i0}Yp<$B_bxK2d!oV{Ddk7CKHfgSPm?vXoGX;Azj z^U*ZqU6*@9Ws8H+xwYaYyN{C7&y@5Gl7opGCR*~14hBAy^B-A$yWNDp77Cbc;L9f^dzzw>=b9A ztdv9YQ+bMz;8L?IxgU-=@{zQi>L#}=Laj|vTN~7^OP$2hQL!`Jo@GY9h%KP5h$7p( zM6Lm<$U$E@1H|+L4w+`=`)<*tUVuvN&8)T?#>+2k0v|F3Jy~ToMGN%6TJqJ&6y>8dnJL7$*03&~zbY2-s+)WDZ_He{V^wT5S z24%by4jj?a0-?`;f3v%ytpk^=B^cVagB|l-jy`iu17KIlPecS6o<2A^8<_8-kin%H zQ`ojisA??24o~_0(!>pp$gH{DwsxAxq|E@+$mX|hjpJrhl^^NYQ%o$|CWvf~5ct*` zwl{G*9xAoZvd4Eur|-5&4;`M=sGfFGDeAU;0e~w7d3t#|o>O=I@U}=mM|rYFJeq#2 zBS>lxs`M!^VtWCFG);O~77cg~{2%Y4P(96cb(SF38YK*Br?mX22ilux(IMnVyR&Tk zzZSqf28NIgky(i^9#LCG_(O$B4T{x=;g664(I_~X)$#&u5-#*$YR%ZrsDH~)%Ms?` zO;e}j10@+u>k}0Y3vv??0$ch(W)%VYOydu7Ze`$tYmFztoyAg>fznQs$%X0A4x+~l z$e6MB#FKt0xPT-ZJG9}Dpj7!RBh~uKoRRLpzyQ}Oi!zGbT5{No&E(LMNe#7W){W3aYn@5^7bj}h>o$M4W@{)tWr8d4W;+c~g{!H&*k5;J?+#d# zjuDSW-%}yXglpyXiAJ5HN1IRSs4_{9`*6)Vv_!yp5VBLN;ir$+P5~MYfVAY+FjvHj zzk!*o0V?Jcj=Py5q>E|GvRS3Z&!djM}d>ZVWETdt>_$ga5adaHG> zin3LRQ{wHhHvwM==l~u$Km258KbB*|SVu0gJcDE)CTkw~0bxZoMUv0rx}Z?X$iQ+N ztkjO8?FMw%oab-4T^b$EvXNCZEBsc7U?$TD)my+(&TusBWca*@0k^i;QC*eSjODN;5xzAlkr?pDH>P6v`e(W)uyjAv%smgM= z4oiJbk_As~V}Ng5?UGTS5bzn#yU#xxtuQJWE>w&2XH}O@_s+PcjYRT#+ZTPW7oNTR z33Uj)+>!cC+EZbrLfdgk{h%>!qW|A^5=}svs1(V_^t0IJIV!P9*1>*IJSHT+#QvJe z8b2AOu6YMY!}=EuaHL9+ajh>MYt8zWkJ=73*8Q}!==na@dg_WlXMgTsd!D;Zb`46u z43iJi_tBCy50kd@(};^>p9+~PT5E0H-EyzvOrVnCEfM`$#k~%y?5X&6Da(nN8OOfu zB^mdu3Pvo$HpJUgjLWWxdf(d;syYh|)nTH4y)kck)Dw;PD6{ezpQO6j5Wz@!4^6+7 zrnR2VOQE`%S8v}5k{3Z)3o?mZb-8%5LkO(3puXDg_ThP7BjdqvYnmQB3puD}1`$yk zC?;4&c>@5LjZLFux4oMIH*5#I*Q7c4k1gu1CIF#ppp?3lP?~(nwMo015V_isR5tRJ^l?$a~B z=O3rPFxW=+XmV?ky@}aRX&QmUxzi?Dx(n>Q{lyj?GqZR^QY93_ng<-xz7{24L}FM( zm~{XcP7>AlZJI+s(J|5r0#LcX{!1t4-5`zp2MbDflY5)+Mh= zkK`?OcN%Zfm4B0@WtRgwt)^RUldP}drMZz@V{X4wBvF3VHrc5(y7q_gQ%lF^ych4UCUM<<3g z8AsMWc$I3w7)50ibfzBJlPhvBfO;EuUyRckH_GeF5s{E+ME_wV`W-}Jh^ePOL?pez zH7W}azNjj|n{Ds@3!n)}$3UL4wyeA7tJm9M z${z*H4L6q`D0tgp_pweWAum#*bo5NZq}z?9RL}v$)k%rup%4NuWdE-_)JQcb*u4p=lDYnSjr`2ln8w1GfQd zP8?@Bq4}-@q=^fBfBs`~Mn|ccRII3LB%`1}22CdfhCx-4OoBotQD1&pwW6iVS3B+UXR0dS{rVgaPp~>h&L#X=h|YuC zjc1+@bu#Uj(DYlm^APDKsLr{PKbkqOp>);Fyd0bgS^yr=NO?C~`ZXFkH^d*Hrq{}y zs$|%LSIP)T;7zDIck5@vw(;tOEh+T|206b}k~XB3fa44- zU5M6+<_h~fpCW#pYkm6AGk2;XVdv4p(~k1XB zb(;h;-{@bl4Ix@*E#@uYi^+@E%SY3X9*!c5lYhs=Y$ekbg0la$+4b@1zA zK;-PrH>6y?-_VfeFjo|{ODpT8EspI=$L0+U6Y~q;@OiJ}IX8%_FqeLIYxHKGU0+$p zQ1NV+Gh{8E?2+7I(d?$w_$l|1ZT{kkyPT5KPq0Fr6!)*^=W`s-A=XYeJilQ7*I7z_ zz8f0+J&v4MN}rB&9l2*Zx?v4Z_NQOm;1Nw+DzvtGrNp<>&5gm-9v^E7^c9J$_-eh8 z%bxMXMyLry(Fe^XO-_@$Zaz3Cx^_^Q| zdFWJqo0h>vrA;^GAj~zl3hn3Nsjb^4T&bF}FL$xT_hj!+CmXy)3;u!<<;%n7AEbxY z6ua55f30z61f;Gvf(G{PSLmL)s_UaOBl2v#Iy5fUp26c;kFI8Vtxj@%uR@{^_+OK* zP`5PA$Loxej!*L%LR-fHE0eM+RntoK=0k&D+{&-T3R6DMt(yPG+oy3#KZQx|A$yx7 z04@oG5TEM-LzZr>P?w*5_Jh@AA|ox4r~#_>bbrjpDOHY;VTf3q>pKn)#<(<8gEF}e zz@bRE1^iOof3!m z9YO)nWzeqt6h!q4dk(cw6K@aJOoD_<3KG-MoX-53hIV=$o(WtBKky~ zPKhGEqR~Xkee8u*l|ACLCuBta5143pmWJI=i)!V^4FuR>l#}tIgY0ff%3r&16Mdt} zuugN0biFXr5tmgTwAd6;9*SQLQF|Bg<_2-&8{{q!@M1I^+-MRCN~iFk-5MN5S3tD& z(~#gd)Eawnqv;LmjzAaTU*YQrT1Mk$9d1L#i@ns$0|9mOHqr<`O~*Ro(eKDOCaUf= zHx`L43`Q{V2n*KTrb4Gat12Jh+xk}l0&!VB1ELHjh}(TYgblEux02tH;py3|em5sa z67XG&Lu}Z&)`zP34--ITQm-`#&gN&js4RfPPNM0kK8X5yLVhGCKAB3w&FQRFTWQrXCTUl*sOfF>lgg#EH3i2BW(;ZGN0aGM<=!*n>;isiztI|!>$ z1FZf%KpM)t4=CqV9=_M~u`s1A0xQ&ANpNX{k^Obh)3Wv-DZsFCNK}>Fm*f|sR&Vl4 zgNw0@_noW$c%$(%LkS=a9{tB*VaA2be>Fo8!8`6u7i*c9UNNheN*+=?0dAT5U*+}x zi*mp}{)}$@e>BgbQpE1Np5@)?X0YZVXV^A(Le;E1JUiE&QZzr?C3VZnr>0gU=ezm( z9F}3cR#ibPxs7zc|z`2 zjXwv%PC(HZ#=vN@-M}L3Nzw*L-(-jv8cU6kX{ou63c_Wy@z+x)F#Nd5Xul9GKZ_%o z=M#Mc8soP$4p395C-Hae2QQ)&nk}e}p9TQ*Byi|m$SO~5L!AWn#QK?5C>hZ>YyBD?v!1kqvj|lzo?od#n%Qk`3sjmBFvL z?TS52T?tx~Y}@Z|-JgX-)Q)P1D2#a3J+a z#xavflq7_0R2aM})j*xek6=RW)jz+U>t!tovu$pNf0Z=7qe<#EEy{45%%HEMWA7i$ zjYp3hdH$?`dV_I#2%5)OanE}T0Qy#XMRq|AmxJ)L9)<;urKDe_K}$6DaN`?67rcr}Ab5;EXfEl8Kx>X4n*SHudQ zV$uk|%uliCiLI&SL{F2O9(W2&O} JdCxJ;isy14xxd;DI)?0<4J#AgTf~z|H>(c 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_statistical_analysis_002.png b/docs/_images/sphx_glr_plot_statistical_analysis_002.png new file mode 100644 index 0000000000000000000000000000000000000000..e15fa3de5af30ccea74c677e6c5ce75f84f676e5 GIT binary patch literal 32200 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_statistical_analysis_003.png b/docs/_images/sphx_glr_plot_statistical_analysis_003.png new file mode 100644 index 0000000000000000000000000000000000000000..1262e0e1a3894d18df262d2f3c2b0062735b9db0 GIT binary patch literal 19563 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

N@ZYsAS?`Pa1BV@m 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_statistical_analysis_thumb.png b/docs/_images/sphx_glr_plot_statistical_analysis_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..f3bb2cced0a39e7e96b1f1d1817d6c957330f5ff GIT binary patch literal 14925 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 J%bvaZe*ixi5TF16 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_within_session_p300_001.png b/docs/_images/sphx_glr_plot_within_session_p300_001.png new file mode 100644 index 0000000000000000000000000000000000000000..ced14bb9f73779a93c791216dcf99817a9674ba5 GIT binary patch literal 12924 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 a(6;?F3kVqhf+;2h9+(@d3I*5iKKU;it(rLi literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_within_session_ssvep_001.png b/docs/_images/sphx_glr_plot_within_session_ssvep_001.png new file mode 100644 index 0000000000000000000000000000000000000000..4b9f5b3605465854a1aff5bf8ee3f6efdd61b6b3 GIT binary patch literal 11613 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 czTatd#k0Aj;?mrHx9Yqc6PCL zbPyLkEh;H|$ja5#$wgL7%>K^{L>-+i#pdyNL%0c}(?vrU1Yx<3{?Vl=rCKA1s2%2< zimqqubT96zuG_1c`3B^}@$C-R5+2=nXsven-f#KVGLN$x*t~SeGhxFk+4o-FEsz#YOV-iw#@1h^@ z8f$(Xl)QI??)>@lTRf%Uf=dz-62}i8e!t++a}K_z&~Empr5%UO@jrC)=ZLX|-yAdS z*4u>bl~qCPLMKmN(a+T5;Na*gahnvVA()jLt*>NpzoG&#$VPs$)yaUKBoX>eg@CIy(8czU;y9*CX80PRj7; zqY|l)9&J6Zs+w6*fwzUVpEh%G$$iQt$2Mk7F}1Qv`|#m|CN`J{N4!7G_beraPfu6Z zs{M^2{`TR+hjTjZ1ciib-Qsd`PIXSZ6K=z!h}>`-stzup3eD9*bw7e^OFkR0b9|CO)PEMcEaMm_>!!Ut)62@u%{`W$r>?Twe{E@62WBuhI9L{0 zQ&lzIqNQZ-#uf0fX~Hw$LXt3*zrw`=6si446G~<58pC%Ytt*4%Bjt}Gjt(%|H)TX6e`uHF6J~rBy}57=_Thr z^`gh25Vk%A)@mzO){pe=rmEXmqe`jAtiFy;*c*M@gw)m<`ty5gs;dPhBy=SuCCzGW zZEW`O@bpi}&d<+VN}7d=mXo!ss;ei0#44;7*9~(m(km+Z7P@jR8w|M_5#+AR;rNxc z!}Y6iMwhAXA3lDRv}!yQ5gCb%EH)8^S3z;{+%~sU;^O7i>e?907fg+MGy15+jrG}y zzH;x(S=DprJh@lDeT=6=l;3U-M8bI?^lsNij*mo{x5LcIwdOQ!h>$RTtw>&tXo)YA ze9y;QQZtK+t}?L+H>Sq>Wd!i}T^$)2DOv9GJ{DKBf9Wm*cjMYDkwBC z`sJF-JGo?ah4kMv#>%)zcrV!z)`J;JVNc< zN`{>W8{<6s(j9tB1Ox@u(AZa`&YdN=(I_=af(i$F@S|M(_8A+ z@4M_(QO#-@0wtmHn)mWd+o#8S7Z>6;Od!b6xl6iFb>w2Nk;AkU)5F8}L29u6@$F@_ zqHl?snwqApUr*5;$RBOpj>N3M!0o0kb&{MXZ#-CpUho7s;n-2x%vg`8DeZ(yhO!kclAk+2d_oi&YZujq>?kzQ_ z3E?4iyt~;}>fwmt#|L{$WtT4*HIQv(H9Y!#3%POBI~p%eyr1kW6%Y^zO%4(*xtN%kIMMvNR)A;vk1@5t0VSVLMiv$+uo_Jh9V|-J%K7c5BGrpLbg<|xD{Q4gj1nsiXrD_cUj{=$zs z9X-7WIE48Yb)0UK?RAr!r9XaH*!NeISFO$xH~fO)*Oq7dCn~awe{jki-1+d~!||WB zV#`=K;A)}SB@-EJ=0D~LaD%p<9v{(wK-|Eu=k3n99i*nNF6lgc(bQ+Ystf)(F)`6f z#Np0gxbW4X5Vo(c`F50P%0njhiORd1MGEHoyl1Ux)D^TsU@(vM31)B!HnVLVqV=|g zg`k|A@xo|>L4Sqs;&fp@)`5CaU0uh_41eLt{={0*(o1{!E;Y^%)#N+$$|_I>?uTmj z=#^Qw@WIxoz{$cpeR_Em3c-o1y1L;~_Fc*M?roBkkVx~G?K66N?e2vT?krfd@sBJ@ zt;v|MeQazgYcr)$O!$B~$8mI|i|O&o5caUOV5MMHH{l4`y!Npx|%MO8nuZL*wce0I5b5Z#WsAUKzk z<;#6K8XCb{ckJIaHa=kPv=?yNT+nOvD4P!t7^6?#ybz>Xb?B}1X84$TqxuPlNQK(Y z>CKjZ4_*Ed;LROW1}xZqwfH?@2sieMv85gxrx7DH{)InY_x$;XOEbNhlD6%~<>c1N zeq5JD1JU2TZrl}x3qkB+JIT7D`(x<Mzwic6=Byu6AXioS1cXmBqz4GoWp$sDPT zVzAPGAN(sv?It~u&zyhmyS8G@$A8*~;#Ax_Bh^3q@Ck|^{(Xc?xVIS+pxn%Qh*Yn6 z*CUU58>&l#Lh2~qThrWkF@o2+(w{C`&LbNla5|v#<$ZB~1WD*E84gt^f7+{+_UhFc zv`o!cA8@M`DI6o<)}aEkwf@?quB><(In_)_iAEX1&J>T5X=}5#a67tay*V`2l`o?x zVWKT_#8o!pL^E_tF0KrXWWM((7E>60&Xq?`HwNd$fv(}j!W@Jk~SFBSd!rIH{J}}vrDCsyc zA42{K*%&x8>dt`OYF}?Za5A15MZrwH&yQ*YHY_&1i^s&s_)y;RrURIx!(-MyxxgY8 zHFCLUc#V#B@vy#rTmL-gvvYmSb_Hx}z}^J~0OxS7G7AdyO-tSNtgNg69EqY2VKUa^ zP<*;9>*#!MeyVz2ebUChJBmVui2%$56%`d5TdWFEN_465vKYxFXn11vsK9U!0hwI> zFzX{Nurbz{xY?4Xc^{3-eRXxs{mXGAzBl@rA$<3hw`asCvx%9#`Sj_WVV3^wTeqwx z+p|&+60wUmi<2ZRsKsBtd@+LhkEx*zvJ;qrr^nH!ZU;h94Udb<0%-875Olz)9a~@SHwfWYp!x#d zMd;Wi=!%@apXqfYnMTWd1O-5rQPPFr=FKef3AFXK$tG2v zHc666(uWUc2zUB@7J^eW<1&<}-&uMDcOuA>UHj-dT3eH$)I+*&$a(f`7raJ9MC6xf z8XCSNd13$y|Kyx?E_Pj;E}TTsnm^rUO}UWj>I;y@Jowh(ThovWX=JWEVOwQK$5pfhr=(QddTD6XVR(M- z=i$M9ou92(%eJw#MZ+5krGT*TB>>LtuyTY?pFZgqa_run2;_^vjsT!!3`BOYu#gf| z?gM_AF#O?MjN+JY-@fUSzI^*e<`lyKZp6FSVUDs3=4p{;Eh4Trp)p~B=z2NcV&sxS?hrfg!!-Vl^XgA;$BI4u4FetPFu#mEa ziOuTUi<3sh&ac1L*5=<0dva8$e^sE zr`To0Njf|_I%9C~Mnf=nTU*=ql_)|1hpcOw{+p|bGA=)?fVcpB)4p=$`PQ8W_otnO zZLwk(b|~!T8pF_M{>jM{#|R8PMCU6|-16l9XO+v7vp&$rNZwc9{gAx8X0oM9(jR_3 z$Mqi_K^fNJzfEmn%s@=aJm2lvyZ3g!Q3R0iEaO7FGZm^x8^K%&QqD1ce%sy>H?vtK z>fFZ(5+VM`(WAdeu~dwPae>|Z=wX;Hy-6eeK!#rCt-|hzsHoJhU)5eGCm$CQQqRxN z&wAQl=9SB*8Ji}claiK^q1M^i381eXkhj9k)uri7ND;o&`I=Q=ajziF1s{~rc5`#H zce@HVwyz&_FYUdH|Mc?n=g*h1*plr`Ovf;yQRCPN{Y>w&|_IMNr{OnO-)U!E%CJE-A6CPx@-1_5C{YVUENk0Zo{>=xRF=N zT69((6+ZKezuq)UmF*o9h%NjDrM3r(`=bmyE$vyI#ey&sBjfWr3ms4gGAF|$BD{j5 zlHa^}6ZX{6#-_RXwK^*oR~E2v{Tc}=sf@(L_mf-TxZ2%2f-FyWrvk(V!ssOu5)>5n z@w*i&1>CtX1Ry=LK2EOICVwJ56%X9^@r|1|je9NrAz3X*3!=$t8zigL0}e$hDAGX{ z7Ms@N!8}T|WD;wAw50mt;v$}eSMcugEPyo|6+6D^gp`y%u#$}Q^m!vQ9i1c!g`!V- z91^0GG!IHk3H4{KBrFtKNnt@-n8eB&C!~%ZIRbchWD%sjZBig&eEFA^Y;>OS7S4>B-5%$wM1%r65*}DuHI{?=C3ZxK~;Ss!efmFojiu}3wVJzZ`Boe|U#~1K15iQ9eiIj}J3aa-q z{+r~*xH8IEmv}b7rYev%THNxfMFT!7IhmK0mDPHn@@{ByW8-Dt)$vp;pqzZienk*_ zjsx38b38z3CqD+LTa8aws51TxEZnWLxDD?tlVWWcSr3#FkWqjjh!zj;LBkj2iOnr7 zzQx`CMbGd@0a)CP^xS!XL1sTiOOdG_5>>(h=n2(Onv zfBtl(QtqHPLM!TMJZ`487n1Y94hs3`01CZgr0iwKRntHzY;VBPT+m94-m1@c*%XS% zit~1e0%_*>tpk~a3hafUBS(&qgUqQPqDn!#uH>-Et*Hc+Fby;cAm>(@rm*1&tbRr+AHfc;Lj#v zlw8B@{mr}-V!qOvB7#g#PAW943yF%h6W6e0a{Kme zXW2MGxa9NmqsK5HAjARWA)?Z=f6H9=>AO(0&MK{SHnbMIST4@=8pA$Exeg|M2VDy{ z%?3}H`n?b-17IBvS!-g#24(Mff^{jmS-lvAqlf&dtEQFrw=y?F%`J-z<`A!rFNKN@ z6NDY$$9tYpeR@zP=^Z4oCS%9)kw4a00#RBS-n%%_roP3szZp6AM-W9WI*IoV4KZ&e96zxC%*0BwnU-dc^ z5tpxH<0tH3a%q$xO+x1lvvE6)Q z)nK}xXpZVNe_qJ}Y68QABW^7wyL3jj*SS^%!U`2v0o1y7-i}(aErbPPFBZ~LI4sAMb(Zh_SK#4pK35gPa7|l%^#9>w1jmilq%Ao z0%$0Z$8po3!y~B!g|f=gymF?m>+~+Oz{CeY^XJ77BVfsS=DE;A>@nFXe1B}-KnOyhcZ~cna==nDMY5WopRD?`A1?N zkT?9rhg*;*PoFNC^s{quP1kC`tSVJ~IQ`L_#qBk`dws%y*sLyAKK#d5e#`?PzPOGx z9yWJGPrBmZ0^(ZQThYf0|M2-N=0Ud*s{}V*sugRXo9Zr{wLaa>6ge(xfo(_*@327Wm|eF0d*I>tHH~J5ukLq$mc9w z-}rj|E`C$vjL*v87xkTw)l2FF99*C%W=&GiOi#i|9#z2$nGeUDdt(n)2ft%)_IjLb9@5 z3u+fHN(UrC2HN%}VVg1z^*E|Sc*KCaL#dca90aVob`Qz~0u7CvT z&HK5zvsLbIP0!0~&HXmw46nL?k+QPGUcMX$e*_p(Sv8Ia7muSAgMgzXz{gju1a2Ro z3HmAyWelW>uXS~LMn=)-dV^32V!Z}l-Y^u6lEtY`ot2f9&}1+)Y&+gwN7YNv>XIUa z3^K~fOw^-9BV3Qr97?C9AOdVaK(=vkSTf=9Y&y>_ATKX}f&s9=faTw_x_<_Y94l5X zz+VclfTU!btvP!BC4DG!QZkU-{0rD58tCjoM3YCi%^y@wIELT6Ee`;X*bbFDs6K=E z1Rzj!|Kk$>w^`%h&a(dtf>9i44b9LOo*qmGi^x!z4OJXMav?6Qlz_GT8wM}OkgKd4 zC`98Rz1SObK@L?ey>_RxcSc!j(Dl@*Q{i}gHk3R}XzhshnKSoLLFlEpWx@XVu&|?m z`9aIZMly4pItQ@FDCgE=QU_|z`L2?$fMWrur@_XInVC88=~I1Q-||`Q`Y)kW_l4vY|txJ+Wb#tCfRX{cw0wD8mJY&D>c^3bVY#w zB~PCQ09$YCWnvP0aHneKr1Zh3xtzF^p9>4X^`^bRlaD1WL4}9y-eag07xQ#^e zHuGMZVkC#d=k-Qc6ZoBE!7JO&%&Z4WJn3h2G$-gSg(aFkK2*bCB^_`o02oOV?BQ~H zBbe#OQUx;9)gvZ)R}831PBo9cur}j z1j}zwg~k~#Vxmu6zsD;eCZ+{ums9sasJF@peU%H+oyjyVb4H$Fm(}A@WRuAJ!AhpH zr9>3CBNgWnAPWC!FZpllsZn9|2SY~x#*J4%!QiCkfitM{)EpcwP~!Okd;;eJU8sK2 z7s@Dj;2A&|COY0F0e4m0pt|6=VY`$oxBNS5bFa7sn1DukR?j1a4PS{E7l0G44Y)uS zOSUrR0`R9ClUvm5;E}+8hws0hLx7fpt&|8(zd3QWjlhdS4S?k>KSydMuYY*ZQlI|2 zLX`1K6bcV{DskdZ_c%(df*ZAwHNnN%r0{UT{qXv_q5-t-RKB#bvC#&D3!ucv{|;-y zdL5RHA|oPRzj}29(+mc{u#@zy+)nvfRaI4?qessItjpSZ?dHuS&I1P<?6!y6ilU z_FG%&Z-!a}-~}uF8nb@O{OMVqnq9o3mDD50H#q@OgSxH{nTYfgv~EJA!K zT7g}sbF)1}n#s0%ga7ZzPc0M#8;fr*5<$7Rgu!4YT2e#&7GnC-p!W*o$(^m&VJM1e z7k@_8o4_K@IxQ;@{_~@7zh5i%da)?Hm zgHMsV?T8QB`|&%_+t_vBKqkm(ZLO`IB82qxD?UCx{uW!13RPrNrP71H+<3%tD^kJA zHpYl3d*1*V8T{J3JPBrQ`Kw#DYynCSwv%&0>Q+P%dJij!pTB&$0v7y_`Zytw09#vi zVOa}{PSPXyI2uq#^TZC)f2oEH2=nssWh5jVYHUIL7e3ripc@cwZEF*NWCR}9cCs!q z5Q{o}$fNH^uOTXvf7M`vX+~9_Oxy-7$0!R`%JIHSh7DMdkkPiIwsLO|kke5m3&r!i zkV(;|q;l+{HXIc+OIf$1c(t!X2M*{>XhRYzd_gruWjIvFE!zNXNeK8EajkbY{Kbnj z5Hrwj2RNeS1xE%%QxxP^VE6C9NY#jyzJdxU&{B~B&|sq1qd%g1x}AqM$50n1X8>kZ z$?8NV(8<@OGbQSv2m=9Wdv!jD3?l0Ujy8&G1xpJ&FjW9E&w0yftCLues8N-cdH)IJ zodIWg{3zEmU7U(d@Dy+8M?m$;^-&xx6;v^_*{q=m+S))kzX(lxZJ;8hg0wjKm>=Ib z6r$9}MifM>?jrQN!qEk1S0gz_pCpuBbf&w|F^U(;*uI%>B}9#fUwVZK+y34JB8uT>1LtOHt0hH4$JI6OLNF(E8(aX}V6t?!0_ra5!$T(Yl$rW2wryu*YyuC9m4}A_ zHP{9=8?B!gE<6GuGr50*wv56TlH0xh+)g_+P0jWOza??jef!2J^Ft+|6G#AF1_gY} zK;b6D655=1g#+QpgZ3i0CJi7%x%YDWy)8@<08%j8AOn(z!?Y&ArM`UYRx(I=lF-11 z(T)-|l>mv&m$ovB5&$r-&;}x~x}hZMY01w&0KEs&Xaw|#DbeObpb}f3WB`$IW4(W) z4Fnprxk!kY_Z(^hz_zzU61OALw({FRf2=%Vg0}7af9blWDkVSp)WvYAmKD+)f;q2w KF8j>2d;bGBgyFXU literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_plot_within_session_ssvep_thumb.png b/docs/_images/sphx_glr_plot_within_session_ssvep_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..03c87c9ffd30a8f2dae1a7a87d0b96db5fa2d93a GIT binary patch literal 7749 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 Mv!9B7y!hLH0m!ke(EtDd literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_tutorial_1_simple_example_motor_imagery_thumb.png b/docs/_images/sphx_glr_tutorial_1_simple_example_motor_imagery_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..713e50b540102dadf52f0c24845da89caf6c8a7e GIT binary patch literal 5876 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 L3^YqM>>vLZDV>=c literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_tutorial_2_using_mulitple_datasets_001.png b/docs/_images/sphx_glr_tutorial_2_using_mulitple_datasets_001.png new file mode 100644 index 0000000000000000000000000000000000000000..33e4223ff97b43d20613b0832320b34c7ee3a14c GIT binary patch literal 13843 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_tutorial_2_using_mulitple_datasets_thumb.png b/docs/_images/sphx_glr_tutorial_2_using_mulitple_datasets_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..8092aa0ecb645ffbf276eb83c8e5038117e0978a GIT binary patch literal 7751 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_tutorial_3_benchmarking_multiple_pipelines_001.png b/docs/_images/sphx_glr_tutorial_3_benchmarking_multiple_pipelines_001.png new file mode 100644 index 0000000000000000000000000000000000000000..e7a7785b1aed18efa4af24b825281eaef5c8a6e7 GIT binary patch literal 25204 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 literal 0 HcmV?d00001 diff --git a/docs/_images/sphx_glr_tutorial_3_benchmarking_multiple_pipelines_thumb.png b/docs/_images/sphx_glr_tutorial_3_benchmarking_multiple_pipelines_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..e1af0c9d65af9bb03707067a1c21a9dccb4b09e5 GIT binary patch literal 8993 zcma)i2T)Vn)_)(ArPVj z@W%or2Upy%***{m&(am4xt` z`ODQVJh}07rpz zk9&QYi;9twOa+nHbAR;cXl{;26#Fi?xL8y~R5Z7&j7}T#`l-gwtnU19K9T3eeMGfR`@_olhOUGMRO-ZWt6o`oqLlKUXJ#su8Q?5fx~(f%*x1_h;^iN&2kzE;A8mFes_?n|{%Ob< zbNiJx0!)WP!GHbwWj;~uXzKhLS?@ASOv@$zq^U{%V}E~pwWGMCBnnD|SX_=gEYQg} zPZN0bb1dX+rjq6p8Om^CPQRbmz$gt{A1)1ea-@oyw0+9BSyov|+J1FlYKnHEI#Er) zb@_9_$gcbgHJ%KO`Hk6j7IyZI;kycrtkNF(-ZZ#T%;h@jKrgVX%21IpDaKg#|tV zLBYX^i5NVdA3PFB3$?pEZ%QdC+>5+8`x7Iy!o!f^(v}aS~RU<4vx8?p4zBmoL%6$!#D# z!Q*~d6oa%}r3U*9b^z=Hm{nK!g1Cf4kzKpEx|)VYZb1P>ghjSd5f5vu<->=RFVx7Z zjA-!M6d;efzi-<*IG{yS6(!Se^U)h}e0cui#Vz4v6o{b+Q+rz*vADXTy?r5bdPH%V zBb$znPGJDw3pGnSJBpT!-9+sI-2T1~hz^(<(%YJ(CZHvpoNdR7!PASqpcd&xiL>4= z&?Sa|XEI3fY%gV*EUS|xp|~IX{51sx#IE>);!cTn0XJ)`uL(JsjtRL6cVsDufqrCQ zRPbU&L!NRx_=lDWxI+b@)n#K^sUgz4RY#gzN8b&B*Ik4!yD^4zU#Eug@VMcKP-t}A zRb*6DHyt^Yj_wBi7$h23OU+V*UkRDyh+?N$$bXYWsc^hVQR$@yM>2dlzC#p|Grz8I z0I{U8=<0*QU1o=*UsE|N4*N*y$!TfBGak=JE3bXe@L&_kCgRzgJUzaIV`FWF6gX=m zI`S;ozt-$zk}QM`w@dpTkl=hC8R?7kzOO!^W%u2aU!p#xxiBWjPcI3J#@;msI~ktx)IiVEMF%xvH5HGt|Gy+geosKoALew#?pt+xw6`K zn@`1X5D$~C>;1A}_r-pAhBtL}3-ItLdy}I))rbZ~P=nBuS$$Ka%*CBL?k_4Rr2SGv zrGxk*kC|}hlSIM=GTMIRn5ZlPZkrhlg6^0mty2Dm|xv^Nl<<+qNb)FpWR6a&tzK^yTGz|Lm?u4M zKHV&c)?!ves`xeI)-ferSU_&3t{U5mL$(|{>V#OPZU|8^Ticw?Z4-LRVA6*YRI^d4 zlg||mJfjs2re<$@{Hv^LgTO(|{ z+We^?uB?;KA%0FJx+1woMPlgX-~{@_9t08tA+B?@m|H*`VX2CIGLq;)ONf`H$SDDrYi3u??gvrOl&5wUC4 z>vg{+Y)vCE@w@s>Fy;MVD3OQtCEMz!|Mu6cK?XcJ#aAR_h`$Kl`k-ZnA1*yc9;0haO}{)f6cCM2yB zUf37RJQ)4|tJgo}+25)IU+FeDi4-Qt^A(2&u~$iP?~Y~JbL^nErN`Z`&v2@ED%%p{ zhi||1UkUI(Ty>t07R*Ej1vL{MBvO5g>ubYag*#oBv{Ypa@>*VZf$z+wtzW`(<60{E z@e1(jC!A|(!rp~WvrnC z(tW=BNNF}xc}H2eqo%X0FhHuwe>%0XI0BnAKCuVR(!Kf!WiN%t({@4LVQ+JdErK;o zw5vl+=6zKH^F%z`4LfN{%J@H~)!w==xVnLj|F1Ti_~!YJB!P$JNXp@Z$|9tKu=R&KZFYK#vld6jon{Z7(ein1A; zo;+_dY+|4K)#eTrM>K6oFE^<;Qaoq2cD3K4w}q)hHAfwV2si1g-xxcN_c5W=nuPw8 zfa$m)NR49JdC*>hrDtttH{yRcpMSS~|J14e`Y|yZ_pBzjetG`Hz)s5=Ejo^LOGg(G z&fE3LLb_(b6XAK=8j9yY9tS_=7e;d>3@3^DEpz^&{-OL~wCYsfwPf$faipwhzUB9Fg(rM_NRQy-HFM zcxG#Fzg;Q2MdwF>=}GsWR`RstR8(Xp;Gl=uH7wj7eyFhW$C@#z*~J_jCrhU%kWFvK z*LG(R&U-eTSyuGv5h|q%;zuX-GFm8n97`K?OmMf?Lz#2^Vj{sg-Ms_lrAVBruS@D7 zG;dxhwX)AABqyG?i!PEnZmM+f`1N4(d(g?@fOwE7UMF5UTg6KqQOu=;295bGudMet z_HV`iZ-?@4yPDXd!N>S;KW6RagF9m%ey#)))=`~~)qt<-}L7D2KxNIg`LbW=hFX@-&*R#PzmueAUN0T6wjg(5y zNRNEQSIgf%m{suKhsoEt*AVc3q+>7^fraRfcRiMY3)ez?ZbUMl5_<;4CFLLfO=`Jgj zZqVezq8lJ9EpFxjz_*F3gH8upg~iHf5x5Fqq=A6}5`f0GF6N_)fMt0tjp&=*F47Bo zUZ20gBB5{pYn^TeV|lb+x6F6D>fmBqSuJsSU;c4BP<6>K9{MJ7btFSjf-D z1DvO%mxqVTXSpDMU}A!5qT2QJcsH-Guy^ID>|%P%66myPuPuCiSwY`C=(2um8Z@X1 zmDd@knB3^wBzF`*A??0!1l$^iQTo*ABAuPDK#+u;mdJB6dDjy#_)w`SZxV=Rkse)4 zr)GifMvU1JanF5v@EFE5PPc=C6h17Lca4m4sbjG6?o4{85bE<@GdtQvdKQK$ga@SY zumRxTLvR_Rt(U>bSJs_)G5x6WYghr8{ zEZO(-Jd4XS5Sas9XRImUCMpMpgMlCcTJ}EWvT^o`%-a!Rfa^YgW=u;@&#_|#yv1Td zl9iQpV0zkY_gqC2MS`Xfj^rHe%vhOKp_d$>uC{3r0J|HAkgE@Cil(~${yE+<>Ev}6 z7wj~#x3O^UjokjLDOD{~i9iQ|J^RFoUw z#1JsZSd~4ql9CdLQkgwL^htdD8Cf(phxGOJ38nT9h|`3lhya@(d3XV2CI(@ULe_px zv2Ev+4J(-1J3E9|wRLnPEA`iNt1w=2n3!4`@^AgU4?EwFk;`T5;BfHEVdUn2SjAcz zM>I4!_(b90OGQmUtObj-#}W(>Av((Nfsv7LAW?viu5i`2Dh>{g6}>`&{{`;Y*x0?F zHVQGBnVco6@LZWkh0=$6+{R{R)5}@BiBO)z#p{f{w|gpGwg2)ft?dk0phZDWCQ%ESK)L zhMjXg+H?Im)yU@DxWmMg2nC5TKp;e-c|y){dbbps*_-SM1ManUufV7?x=?>qgyTvw zN|s$|^~+VK0^K%{oaN&p8d>r*!{R_(aoOK`@KV;t%@grVg)bDWjX_X@o00Mw7~#l4 z*^lXTd$+0X8zSvleGnd+MhgG~>#O`zu7og3paU3`G`X!Bwjn6o@ zt$3YGRg3dkaVFfko#*ZCvf^mQi!-QD>lrQLY7AWD@l{o&GBPq6&F@wZ1^wECqkvDu zXZt3tqA!$~SQ~Rj?~^fSwE@(j$;nBOZP-SEx!n!O*_ig&%ch;vFOO)&T_@E%@UYSL zz4qgvU=Kd9pv{bR|8p52n5?XAI(Oy5b@DZ4=Q?9-ot>4%Sv$A;71n2+%dUa`u1%?e z*gINTF&GNfm68`a2YH)9b|`RuaP!%s9Xa8E%#o6kGNm#*DO8uzqTOKEWHd>@y0=1# zRHY;8k2NlB43JikK(UaJxP_@bkn1h?_nTPjA`?U6AV$V-qpI)a@G+1Y$UAaoR>F6qmfF8S_l?1lL8B^6!R=y8p%YJm1Yc${33A6SAWCI`-_#(@0Xinn`u1ICl=_ScLbD>Yv7>hxHcGP{+e3vRs>X84$CCYi z_RxL)t?PdWI_e8aG?s`_#wV2FH$vjR3R0I@+x@zUPYSiRExfy**B41dZ;oOxXwXGH zcuQ@hJweRQKs*nT}i~7-0+#Fe85<7yIUmglxt4ZRxQsJJ7)tw2;HC)?JDQbiAP@ z@<;bNaHpByzMrE`2-c~t`^|5m=fkMHrjrutRti1bqF-~{cP-T-@3!u!Fa00+;~x$E zpXG%!0s+`il0Z_!;oiyc>L#*8pfBCZ0&I&I3*O z!|%GZzSgG#X}RjAsk0aHjA?9XgI~W;n~=KIjNuqjzEF$HKRw|dRH%YFb+4}QEQKIW z3*ILut$|W2IWhwHj*_5bdv+O*?iFpJ=WBsQsp{ON1f)Zz??Bh*%~r-lL2y3MXpcV+ z@IOEC-_X@x>dwDk9#O8HXRWVT5ifj9FltT7JnN;7P>Pn2sE-MG5eXTRfjHXxS1~Hb zNTN*BfY`kwNRMgxZbvS_-JDYOq6tKnhLTPDHdpfCgQ0%jq8A*shf-{vFmuf(--F@| z+B4+(G=|05<=rSxSDoW|87UW>W}P4ID+K-SV=i^fZeMxm&kL|~j)BsMXb91qLiJ?} zmID(7?zct~*Rrm_*=c_|%^EKo1shcVs$(>x_?ek&N1XQh?3b7u_3!yR+_DVTm=^>u z5w#88@p8TUzx0NG0Xe&~aKSUH?ZnmqhdWyH7H9L$rvyowcr}Eo|jb z>|;jC%l!NpSaWCV4{9+=7LV%D9SJMC7kzFChwD}n1#KRlk{0zO5f=9_+$5weTRy9k z9NF59?^1VDj@zy4k2RaA*89V>7B+X*(@ z?(XhDRR&H$g0|)T`=r1r@Lq4+-Ltr5|MF%4D-dA^#Ld>}L-KGD8$V^AoR8cH3fv$8 zW`nQE(~>=3XFCT6QV1VC1ps-#gy@)eWta7ah1#( zYbDv6S2))3c=YJ6yP=mr;or_Wl?`5eK&^)g;D}U+Vkb?UR9w`K|rPs)^BPPr-Us&Ofp(y(B4W}_kEphe#d@iT^sRPB&PmA z26`sN+#h1%QLkFOOS46ThZF=)W^i~NR}8*EyT6NwYNfE*!63N*h`g3C)g-g4iU>E5 z4lOPA!)Bb4N+KUQn4sTw1(#ps4&+Hj^RRa{AAMZ^y3=1R{$ecsGS92<(HyZa(CYF* zI_IwD(~k<|E!TT?&g8$8cwN1wZiSS{9LPj#`GubhJI;&8HLqwCseX1%MEtiB;B4&B z!c7#^Rwh0+6lKe$&ccX6+7j2jH~h{PLWDZu2{tN-D2PUM)X(`RmGvWxTR#%?PMt2D znNMY3$ClA3JR?9B|XcGr?weT^=uiP*1i5N z1*0l7;^U9&d!vQZq3?dH_m-DhbZ7S?cghqB?bj9V%8YV2-}_J1i1fFlsquK}D>8nc`ur>vehbx!&3>aHql{Ly zoi05|hsB@A`Sr}*K$BU*c;q5RsQH0V^p!6e9X2>)OK&Lr5+%)Hcs=aJa*VEIT3(+l zbc{PUP7r%T^yp}R8+by1Xn9s}zO~ZEG@Kl)NdMZKKU#uc`TU@U3g|MNIRkyA`mo8` z7V;>!Kw?ES8tMY_bg=QCiY7=J@yn&nGLytvM#>&u#5b%yR6DZYd_)c0nw6~?_^`N^ z5aYnmP`T52$u!`9sjBwY`7cqxuim^F12C_P^iSVI2(ZbZz>?C)m-1(mkd(AspK6q9 zIQfu#$$PbmFp6h_lUiF_10+FMwTu4CasjMirCdE(`^;qlw#tel372D@u5h@fP^IW9 zbIffaJYbnlV@ij=R~2P49vx5bR3J6@*f}`DwJCwmSSr%nmuAjF4xBRJZ9Qr9+Xci} z-^*Hk7|3^JR$Zk*r-8O<;pee=(!Jz?{Wpa0DxRz2-S_AeEdia zm~CBM9iZBpB1|T7JR+&Rz-k4C9~!US`s484F%YMxEZ>zt{sQ4N)8VWz)1j?fbSSMoZ#^gZBkRO$7vBpN+Cu{V9YAzXtn?g^5EbAYd68~d67G$4(77<^~OtSS7Mv~%+8)?f@h2h z+u%J|_1nhA#`V{dR>RJyF$`ty;6UAcyy|RXZ-$BHRgRlkt(jJ;#lG(k{C)jsS-;t> zC;%e;=qJlmz^=)H+l`~WE`|4?(P$NpVC_!W*jx%mD zHpT)HQg1rm_!{7MP5S~<1zLZq|F?i8k#vuICttfZf3~%lrNkQc_ml98$ev;oNnBM(qP`%^nfvJq)#7_ zD;&+92kz~H(P6dYe4o@bDWqZlTe>v34?G9fUf~V#1@24A_d&mVqgSYjsr9`UfG+|v z3sy8TCkL({KNYg5pI+VwQxlk9W;y+^p4$KY8b}89VeBgN zrHMSCM*wLFXivad^(Z<{4zj{e-$9sgeY;LgLPbRdat>f(L}$7H7WM`%g5U>E2sqX` zD>C1{e;=HjTz#m;z`ziN<|$-mudk~Ed2C{@kkt>A0v^tI-b591V3(E|e60FiI3oNy zKOYnf{VOt$JUrfwHfd8@Sy=(avvB>EvT|f0bBeN(5;qf6lsME3iZ$sR8Cp zLqk*8Ucchgdu^Y@PZ{zD*4)wFUeU%z@K0a2so1pfF*x-8KUB@O>eRjMCn~c5@$Cya@c%&Ndy6_Vu=WGkc=rZu0cUV zPEG>jFTIKtz#;YZnYZ?jmUps1UkwQ%0xv>y=xr(JcooGqw2m6oFUiskq5vTI>w~Z4GoW$~^S{0aS7)x&QzG literal 0 HcmV?d00001 diff --git a/docs/_sphinx_design_static/design-style.4045f2051d55cab465a707391d5b2007.min.css b/docs/_sphinx_design_static/design-style.4045f2051d55cab465a707391d5b2007.min.css new file mode 100644 index 00000000..3225661c --- /dev/null +++ b/docs/_sphinx_design_static/design-style.4045f2051d55cab465a707391d5b2007.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative}details.sd-dropdown .sd-summary-title{font-weight:700;padding-right:3em !important;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary{list-style:none;padding:1em}details.sd-dropdown summary .sd-octicon.no-title{vertical-align:middle}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown summary::-webkit-details-marker{display:none}details.sd-dropdown summary:focus{outline:none}details.sd-dropdown .sd-summary-icon{margin-right:.5em}details.sd-dropdown .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary:hover .sd-summary-up svg,details.sd-dropdown summary:hover .sd-summary-down svg{opacity:1;transform:scale(1.1)}details.sd-dropdown .sd-summary-up svg,details.sd-dropdown .sd-summary-down svg{display:block;opacity:.6}details.sd-dropdown .sd-summary-up,details.sd-dropdown .sd-summary-down{pointer-events:none;position:absolute;right:1em;top:1em}details.sd-dropdown[open]>.sd-summary-title .sd-summary-down{visibility:hidden}details.sd-dropdown:not([open])>.sd-summary-title .sd-summary-up{visibility:hidden}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #007bff;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0069d9;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem} diff --git a/docs/_sphinx_design_static/design-tabs.js b/docs/_sphinx_design_static/design-tabs.js new file mode 100644 index 00000000..36b38cf0 --- /dev/null +++ b/docs/_sphinx_design_static/design-tabs.js @@ -0,0 +1,27 @@ +var sd_labels_by_text = {}; + +function ready() { + const li = document.getElementsByClassName("sd-tab-label"); + for (const label of li) { + syncId = label.getAttribute("data-sync-id"); + if (syncId) { + label.onclick = onLabelClick; + if (!sd_labels_by_text[syncId]) { + sd_labels_by_text[syncId] = []; + } + sd_labels_by_text[syncId].push(label); + } + } +} + +function onLabelClick() { + // Activate other inputs with the same sync id. + syncId = this.getAttribute("data-sync-id"); + for (label of sd_labels_by_text[syncId]) { + if (label === this) continue; + label.previousElementSibling.checked = true; + } + window.localStorage.setItem("sphinx-design-last-tab", syncId); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/docs/_static/M.png b/docs/_static/M.png new file mode 100644 index 0000000000000000000000000000000000000000..91e2939c7f5fdc167544dc579584f79b175038a7 GIT binary patch literal 13411 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 literal 0 HcmV?d00001 diff --git a/docs/_static/_sphinx_javascript_frameworks_compat.js b/docs/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..8549469d --- /dev/null +++ b/docs/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,134 @@ +/* + * _sphinx_javascript_frameworks_compat.js + * ~~~~~~~~~~ + * + * Compatability shim for jQuery and underscores.js. + * + * WILL BE REMOVED IN Sphinx 6.0 + * xref RemovedInSphinx60Warning + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/docs/_static/basic.css b/docs/_static/basic.css new file mode 100644 index 00000000..18495ea0 --- /dev/null +++ b/docs/_static/basic.css @@ -0,0 +1,900 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 270px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/_static/binder_badge_logo.svg b/docs/_static/binder_badge_logo.svg new file mode 100644 index 00000000..327f6b63 --- /dev/null +++ b/docs/_static/binder_badge_logo.svg @@ -0,0 +1 @@ + launchlaunchbinderbinder \ No newline at end of file diff --git a/docs/_static/broken_example.png b/docs/_static/broken_example.png new file mode 100644 index 0000000000000000000000000000000000000000..4fea24e7df4781c2c32c8d7995511ac89e953145 GIT binary patch literal 21404 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 + + + diff --git a/docs/_static/clipboard.min.js b/docs/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/docs/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/docs/_static/copybutton.css b/docs/_static/copybutton.css new file mode 100644 index 00000000..5d291490 --- /dev/null +++ b/docs/_static/copybutton.css @@ -0,0 +1,81 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .5em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + border: #e1e1e1 1px solid; + background-color: rgb(245, 245, 245); +} + +button.copybtn.success { + border-color: #22863a; +} + +button.copybtn img { + width: 100%; + padding: .2em; +} + +div.highlight { + position: relative; +} + +.highlight:hover button.copybtn { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} diff --git a/docs/_static/copybutton.js b/docs/_static/copybutton.js new file mode 100644 index 00000000..482bda03 --- /dev/null +++ b/docs/_static/copybutton.js @@ -0,0 +1,197 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copié dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +const path_static = `${doc_url_root}_static/`; + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for two seconds, then changes it back +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + setTimeout(() => el.setAttribute('data-tooltip', oldText), 2000) + setTimeout(() => el.classList.remove('success'), 2000) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + img = el.querySelector("img"); + img.setAttribute('src', `${path_static}check-solid.svg`) + setTimeout(() => img.setAttribute('src', `${path_static}copy-button.svg`), 2000) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const codeCells = document.querySelectorAll('div.highlight pre') + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + return formatCopyText(target.innerText, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/docs/_static/copybutton_funcs.js b/docs/_static/copybutton_funcs.js new file mode 100644 index 00000000..b9168c55 --- /dev/null +++ b/docs/_static/copybutton_funcs.js @@ -0,0 +1,58 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css new file mode 100644 index 00000000..dc9503b5 --- /dev/null +++ b/docs/_static/css/custom.css @@ -0,0 +1,10 @@ +.large-text { + font-size: 30px; +} + +.bd-main .bd-content .bd-article-container { + max-width: 75em; /* default is 60em */ +} +.bd-page-width { + max-width: 88em; /* default is 88rem */ +} diff --git a/docs/_static/design-style.4045f2051d55cab465a707391d5b2007.min.css b/docs/_static/design-style.4045f2051d55cab465a707391d5b2007.min.css new file mode 100644 index 00000000..3225661c --- /dev/null +++ b/docs/_static/design-style.4045f2051d55cab465a707391d5b2007.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative}details.sd-dropdown .sd-summary-title{font-weight:700;padding-right:3em !important;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary{list-style:none;padding:1em}details.sd-dropdown summary .sd-octicon.no-title{vertical-align:middle}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown summary::-webkit-details-marker{display:none}details.sd-dropdown summary:focus{outline:none}details.sd-dropdown .sd-summary-icon{margin-right:.5em}details.sd-dropdown .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary:hover .sd-summary-up svg,details.sd-dropdown summary:hover .sd-summary-down svg{opacity:1;transform:scale(1.1)}details.sd-dropdown .sd-summary-up svg,details.sd-dropdown .sd-summary-down svg{display:block;opacity:.6}details.sd-dropdown .sd-summary-up,details.sd-dropdown .sd-summary-down{pointer-events:none;position:absolute;right:1em;top:1em}details.sd-dropdown[open]>.sd-summary-title .sd-summary-down{visibility:hidden}details.sd-dropdown:not([open])>.sd-summary-title .sd-summary-up{visibility:hidden}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #007bff;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0069d9;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem} diff --git a/docs/_static/design-tabs.js b/docs/_static/design-tabs.js new file mode 100644 index 00000000..36b38cf0 --- /dev/null +++ b/docs/_static/design-tabs.js @@ -0,0 +1,27 @@ +var sd_labels_by_text = {}; + +function ready() { + const li = document.getElementsByClassName("sd-tab-label"); + for (const label of li) { + syncId = label.getAttribute("data-sync-id"); + if (syncId) { + label.onclick = onLabelClick; + if (!sd_labels_by_text[syncId]) { + sd_labels_by_text[syncId] = []; + } + sd_labels_by_text[syncId].push(label); + } + } +} + +function onLabelClick() { + // Activate other inputs with the same sync id. + syncId = this.getAttribute("data-sync-id"); + for (label of sd_labels_by_text[syncId]) { + if (label === this) continue; + label.previousElementSibling.checked = true; + } + window.localStorage.setItem("sphinx-design-last-tab", syncId); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/docs/_static/doctools.js b/docs/_static/doctools.js new file mode 100644 index 00000000..527b876c --- /dev/null +++ b/docs/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/docs/_static/documentation_options.js b/docs/_static/documentation_options.js new file mode 100644 index 00000000..fece0822 --- /dev/null +++ b/docs/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '1.0.0-dev', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: false, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/docs/_static/file.png b/docs/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/docs/_static/jquery-3.6.0.js b/docs/_static/jquery-3.6.0.js new file mode 100644 index 00000000..fc6c299b --- /dev/null +++ b/docs/_static/jquery-3.6.0.js @@ -0,0 +1,10881 @@ +/*! + * jQuery JavaScript Library v3.6.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2021-03-02T17:08Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.6 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2021-02-16 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ).filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ).map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + +originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + +{% endmacro %} \ No newline at end of file diff --git a/docs/analysis.html b/docs/analysis.html new file mode 100644 index 00000000..45b02e82 --- /dev/null +++ b/docs/analysis.html @@ -0,0 +1,581 @@ + + + + + + + + + + + + Analysis — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Analysis#

+
+

Plotting#

+ + + + + + + + + + + + + + + +

plotting.score_plot(data[, pipelines, ...])

Plot scores for all pipelines and all datasets

plotting.paired_plot(data, alg1, alg2)

Generate a figure with a paired plot.

plotting.summary_plot(sig_df, effect_df[, ...])

Significance matrix to compare pipelines.

plotting.meta_analysis_plot(stats_df, alg1, alg2)

Meta-analysis to compare two algorithms across several datasets.

+
+
+

Statistics#

+ + + + + + + + + + + + + + + + + + +

meta_analysis.find_significant_differences(df)

Compute differences between pipelines across datasets.

meta_analysis.compute_dataset_statistics(df)

Compute meta-analysis statistics from results dataframe.

meta_analysis.combine_effects(effects, nsubs)

Combine effects for meta-analysis statistics.

meta_analysis.combine_pvalues(p, nsubs)

Combine p-values for meta-analysis statistics.

meta_analysis.collapse_session_scores(df)

Prepare results dataframe for computing statistics.

+
+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/api.html b/docs/api.html new file mode 100644 index 00000000..eb0fd367 --- /dev/null +++ b/docs/api.html @@ -0,0 +1,1343 @@ + + + + + + + + + + + + API Reference — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

API Reference#

+
+

Datasets#

+

A dataset handle and abstract low level access to the data. the dataset will +takes data stored locally, in the format in which they have been downloaded, +and will convert them into a MNE raw object. There are options to pool all the +different recording sessions per subject or to evaluate them separately.

+

See NeuroTechX/moabb for detail +on datasets (electrodes, number of trials, sessions, etc.)

+
+

Motor Imagery Datasets#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

AlexMI()

Alex Motor Imagery dataset.

BNCI2014_001()

BNCI 2014-001 Motor Imagery dataset.

BNCI2014_002()

BNCI 2014-002 Motor Imagery dataset.

BNCI2014_004()

BNCI 2014-004 Motor Imagery dataset.

BNCI2015_001()

BNCI 2015-001 Motor Imagery dataset.

BNCI2015_004()

BNCI 2015-004 Motor Imagery dataset.

Cho2017()

Motor Imagery dataset from Cho et al 2017.

Lee2019_MI([train_run, test_run, ...])

BMI/OpenBMI dataset for MI.

GrosseWentrup2009()

Munich Motor Imagery dataset.

Ofner2017([imagined, executed])

Motor Imagery ataset from Ofner et al 2017.

PhysionetMI([imagined, executed])

Physionet Motor Imagery dataset.

Schirrmeister2017()

High-gamma dataset described in Schirrmeister et al. 2017.

Shin2017A([accept])

Motor Imagey Dataset from Shin et al 2017.

Shin2017B([accept])

Mental Arithmetic Dataset from Shin et al 2017.

Weibo2014()

Motor Imagery dataset from Weibo et al 2014.

Zhou2016()

Motor Imagery dataset from Zhou et al 2016.

+
+
+

ERP Datasets#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

BI2012([Training, Online])

P300 dataset BI2012 from a "Brain Invaders" experiment.

BI2013a([NonAdaptive, Adaptive, Training, ...])

P300 dataset BI2013a from a "Brain Invaders" experiment.

BI2014a()

P300 dataset BI2014a from a "Brain Invaders" experiment.

BI2014b()

P300 dataset BI2014b from a "Brain Invaders" experiment.

BI2015a()

P300 dataset BI2015a from a "Brain Invaders" experiment.

BI2015b()

P300 dataset BI2015b from a "Brain Invaders" experiment.

Cattan2019_VR([virtual_reality, screen_display])

Dataset of an EEG-based BCI experiment in Virtual Reality using P300.

BNCI2014_008()

BNCI 2014-008 P300 dataset.

BNCI2014_009()

BNCI 2014-009 P300 dataset.

BNCI2015_003()

BNCI 2015-003 P300 dataset.

DemonsP300()

Visual P300 dataset recorded in Virtual Reality (VR) game Raccoons versus Demons.

EPFLP300()

P300 dataset from Hoffmann et al 2008.

Huebner2017([interval, raw_slice_offset, ...])

Learning from label proportions for a visual matrix speller (ERP) dataset from Hübner et al 2017 [R0a211c89d39d-1].

Huebner2018([interval, raw_slice_offset, ...])

Mixture of LLP and EM for a visual matrix speller (ERP) dataset from Hübner et al 2018 [R8f30fc0d0ace-1].

Lee2019_ERP([train_run, test_run, ...])

BMI/OpenBMI dataset for P300.

Sosulski2019([use_soas_as_sessions, ...])

P300 dataset from initial spot study.

+
+
+

SSVEP Datasets#

+ + + + + + + + + + + + + + + + + + + + + + + + +

Kalunga2016()

SSVEP Exo dataset.

Nakanishi2015()

SSVEP Nakanishi 2015 dataset.

Wang2016()

SSVEP Wang 2016 dataset.

MAMEM1()

SSVEP MAMEM 1 dataset.

MAMEM2()

SSVEP MAMEM 2 dataset.

MAMEM3()

SSVEP MAMEM 3 dataset.

Lee2019_SSVEP([train_run, test_run, ...])

BMI/OpenBMI dataset for SSVEP.

+
+
+

c-VEP Datasets#

+ + + + + + + + + + + + + + + + + + + + + +

Thielen2015()

c-VEP dataset from Thielen et al. (2015).

Thielen2021()

c-VEP dataset from Thielen et al. (2021).

CastillosBurstVEP40()

c-VEP and Burst-VEP dataset from Castillos et al. (2023).

CastillosBurstVEP100()

c-VEP and Burst-VEP dataset from Castillos et al. (2023).

CastillosCVEP40()

c-VEP and Burst-VEP dataset from Castillos et al. (2023).

CastillosCVEP100()

c-VEP and Burst-VEP dataset from Castillos et al. (2023).

+
+
+

Resting State Datasets#

+ + + + + + +

Cattan2019_PHMD()

Passive Head Mounted Display with Music Listening dataset.

+
+
+

Base & Utils#

+ + + + + + + + + + + + + + + +

base.BaseDataset(subjects, ...[, doi, ...])

Abstract Moabb BaseDataset.

base.CacheConfig([save_raw, save_epochs, ...])

Configuration for caching of datasets.

fake.FakeDataset([event_list, n_sessions, ...])

Fake Dataset for test purpose.

fake.FakeVirtualRealityDataset([seed])

Fake Cattan2019_VR dataset for test purpose.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

download.data_path(url, sign[, path, ...])

Get path to local copy of given dataset URL.

download.data_dl(url, sign[, path, ...])

Download file from url to specified path.

download.fs_issue_request(method, url, headers)

Wrapper for HTTP request.

download.fs_get_file_list(article_id[, version])

List all the files associated with a given article.

download.fs_get_file_hash(filelist)

Returns a dict associating figshare file id to MD5 hash.

download.fs_get_file_id(filelist)

Returns a dict associating filename to figshare file id.

download.fs_get_file_name(filelist)

Returns a dict associating figshare file id to filename.

utils.dataset_search([paradigm, ...])

Returns a list of datasets that match a given criteria.

utils.find_intersecting_channels(datasets[, ...])

Given a list of dataset instances return a list of channels shared by all datasets.

+
+
+
+

Compound Datasets#

+
+

ERP Datasets#

+ + + + + + + + + + + + + + + + + + + + + +

BI2014a_Il()

A selection of subject from BI2014a with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

BI2014b_Il()

A selection of subject from BI2014b with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

BI2015a_Il()

A selection of subject from BI2015a with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

BI2015b_Il()

A selection of subject from BI2015b with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

Cattan2019_VR_Il()

A selection of subject from Cattan2019_VR with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

BI_Il()

Subjects from braininvaders datasets with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

+
+
+
+

Evaluations#

+

An evaluation defines how we go from trials per subject and session to a +generalization statistic (AUC score, f-score, accuracy, etc) – it can be +either within-recording-session accuracy, across-session within-subject +accuracy, across-subject accuracy, or other transfer learning settings.

+
+

Evaluations#

+ + + + + + + + + + + + +

WithinSessionEvaluation([n_perms, data_size])

Performance evaluation within session (k-fold cross-validation)

CrossSessionEvaluation(paradigm[, datasets, ...])

Cross-session performance evaluation.

CrossSubjectEvaluation(paradigm[, datasets, ...])

Cross-subject evaluation performance.

+
+
+

Base & Utils#

+ + + + + + +

base.BaseEvaluation(paradigm[, datasets, ...])

Base class that defines necessary operations for an evaluation.

+
+
+
+

Paradigms#

+

A paradigm defines how the raw data will be converted to trials ready to be +processed by a decoding algorithm.

+

This is a function of the paradigm used, i.e. in motor imagery one can +have two-class, multi-class, or continuous paradigms; similarly, +different preprocessing is necessary for ERP vs ERD paradigms.

+
+

Motor Imagery Paradigms#

+ + + + + + + + + + + + + + + +

MotorImagery([n_classes])

N-class motor imagery.

LeftRightImagery(**kwargs)

Motor Imagery for left hand/right hand classification.

FilterBankLeftRightImagery(**kwargs)

Filter Bank Motor Imagery for left hand/right hand classification.

FilterBankMotorImagery([n_classes])

Filter bank n-class motor imagery.

+
+
+

P300 Paradigms#

+ + + + + + + + + +

SinglePass([fmin, fmax])

Single Bandpass filter P300.

P300(**kwargs)

P300 for Target/NonTarget classification.

+
+
+

SSVEP Paradigms#

+ + + + + + + + + +

SSVEP([fmin, fmax])

Single bandpass filter SSVEP.

FilterBankSSVEP([filters])

Filtered bank n-class SSVEP paradigm.

+
+
+

c-VEP Paradigms#

+ + + + + + + + + +

CVEP([fmin, fmax])

Single bandpass c-VEP paradigm for epoch-level decoding.

FilterBankCVEP([filters])

Filterbank c-VEP paradigm for epoch-level decoding.

+
+
+

Fixed Interval Windows Processings#

+ + + + + + + + + +

FixedIntervalWindowsProcessing([fmin, fmax, ...])

Fixed interval windows processing.

FilterBankFixedIntervalWindowsProcessing([...])

Filter bank fixed interval windows processing.

+
+
+

Base & Utils#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

motor_imagery.BaseMotorImagery([filters, ...])

Base Motor imagery paradigm.

motor_imagery.SinglePass([fmin, fmax])

Single Bandpass filter motor Imagery.

motor_imagery.FilterBank([filters])

Filter Bank MI.

p300.BaseP300([filters, events, tmin, tmax, ...])

Base P300 paradigm.

ssvep.BaseSSVEP([filters, events, ...])

Base SSVEP Paradigm.

BaseFixedIntervalWindowsProcessing([...])

Base class for fixed interval windows processing.

base.BaseParadigm(filters[, events, tmin, ...])

Base class for paradigms.

base.BaseProcessing(filters[, tmin, tmax, ...])

Base Processing.

+
+
+
+

Pipelines#

+

Pipeline defines all steps required by an algorithm to obtain predictions.

+

Pipelines are typically a chain of sklearn compatible transformers and +end with a sklearn compatible estimator.

+
+

Pipelines#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

features.LogVariance()

LogVariance transformer.

features.FM([freq])

Transformer to scale sampling frequency.

features.ExtendedSSVEPSignal()

Prepare FilterBank SSVEP EEG signal for estimating extended covariances.

features.AugmentedDataset([order, lag])

Dataset augmentation methods in a higher dimensional space.

features.StandardScaler_Epoch()

Function to standardize the X raw data for the DeepLearning Method.

csp.TRCSP([nfilter, metric, log, alpha])

Weighted Tikhonov-regularized CSP as described in Lotte and Guan 2011.

classification.SSVEP_CCA(interval, freqs[, ...])

Classifier based on Canonical Correlation Analysis for SSVEP.

classification.SSVEP_TRCA(interval, freqs[, ...])

Classifier based on the Task-Related Component Analysis method [1]_ for SSVEP.

classification.SSVEP_MsetCCA(freqs[, ...])

Classifier based on MsetCCA for SSVEP.

deep_learning.KerasDeepConvNet(loss[, ...])

Keras implementation of the Deep Convolutional Network as described in [R679315cfbef6-1].

deep_learning.KerasEEGITNet(loss[, ...])

Keras implementation of the EEGITNet as described in [Rf5b2ee1af1ae-1].

deep_learning.KerasEEGNet_8_2(loss[, ...])

Keras implementation of the EEGNet as described in [Rd83becb56589-1].

deep_learning.KerasEEGNeX(loss[, optimizer, ...])

Keras implementation of the EEGNex as described in [R643fa75c3283-1].

deep_learning.KerasEEGTCNet(loss[, ...])

Keras implementation of the EEGTCNet as described in [R89b58824c471-1].

deep_learning.KerasShallowConvNet(loss[, ...])

Keras implementation of the Shallow Convolutional Network as described in [R2ccacb732305-1].

+
+
+

Base & Utils#

+ + + + + + + + + + + + + + + + + + + + + + + + +

utils.create_pipeline_from_config(config)

Create a pipeline from a config file.

utils.FilterBank(estimator[, flatten])

Apply a given identical pipeline over a bank of filter.

utils_deep_model.EEGNet(data, input_layer[, ...])

EEGNet block implementation as described in [R820c2366bc63-1].

utils_deep_model.EEGNet_TC(self, input_layer)

utils_deep_model.TCN_block(input_layer, ...)

Temporal Convolutional Network (TCN), TCN_block from [R2eea69aed7b6-1].

utils_pytorch.BraindecodeDatasetLoader([...])

Class to Load the data from MOABB in a format compatible with braindecode.

utils_pytorch.InputShapeSetterEEG([...])

Sets the input dimension of the PyTorch module to the input dimension of the training data.

+
+
+
+

Analysis#

+
+

Plotting#

+ + + + + + + + + + + + + + + +

plotting.score_plot(data[, pipelines, ...])

Plot scores for all pipelines and all datasets

plotting.paired_plot(data, alg1, alg2)

Generate a figure with a paired plot.

plotting.summary_plot(sig_df, effect_df[, ...])

Significance matrix to compare pipelines.

plotting.meta_analysis_plot(stats_df, alg1, alg2)

Meta-analysis to compare two algorithms across several datasets.

+
+
+

Statistics#

+ + + + + + + + + + + + + + + + + + +

meta_analysis.find_significant_differences(df)

Compute differences between pipelines across datasets.

meta_analysis.compute_dataset_statistics(df)

Compute meta-analysis statistics from results dataframe.

meta_analysis.combine_effects(effects, nsubs)

Combine effects for meta-analysis statistics.

meta_analysis.combine_pvalues(p, nsubs)

Combine p-values for meta-analysis statistics.

meta_analysis.collapse_session_scores(df)

Prepare results dataframe for computing statistics.

+
+
+
+

Utils#

+
+

Benchmark#

+ + + + + + +

benchmark([pipelines, evaluations, ...])

Run benchmarks for selected pipelines and datasets.

+
+
+

Utils#

+ + + + + + + + + + + + + + + +

set_log_level([level])

Set log level.

setup_seed(seed)

Set the seed for random, numpy, TensorFlow and PyTorch.

set_download_dir(path)

Set the download directory if required to change from default mne path.

make_process_pipelines(processing, dataset)

Shortcut for the method moabb.paradigms.base.BaseProcessing.make_process_pipelines()

+
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/advanced_examples/index.html b/docs/auto_examples/advanced_examples/index.html new file mode 100644 index 00000000..81f96f64 --- /dev/null +++ b/docs/auto_examples/advanced_examples/index.html @@ -0,0 +1,745 @@ + + + + + + + + + + + + Advanced examples — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Advanced examples#

+

These examples show various advanced topics:

+
    +
  • using scikit-learn pipeline with MNE inputs

  • +
  • selecting electrodes or resampling signal

  • +
  • using filterbank approach in motor imagery

  • +
  • apply statistics for meta-analysis

  • +
  • using a gridsearch in within-subject decoding

  • +
+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
GridSearch within a session +

GridSearch within a session

+
GridSearch within a session
+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
+
+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/advanced_examples/plot_filterbank_csp_vs_csp.html b/docs/auto_examples/advanced_examples/plot_filterbank_csp_vs_csp.html new file mode 100644 index 00000000..331ab00b --- /dev/null +++ b/docs/auto_examples/advanced_examples/plot_filterbank_csp_vs_csp.html @@ -0,0 +1,886 @@ + + + + + + + + + + + + FilterBank CSP versus CSP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

FilterBank CSP versus CSP#

+

This example show a comparison of CSP versus FilterBank CSP on the +very popular dataset 2a from the BCI competition IV.

+
# Authors: Alexandre Barachant <alexandre.barachant@gmail.com>
+#
+# License: BSD (3-clause)
+
+import matplotlib.pyplot as plt
+import pandas as pd
+import seaborn as sns
+from mne.decoding import CSP
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.pipeline import make_pipeline
+
+import moabb
+from moabb.datasets import BNCI2014_001
+from moabb.evaluations import CrossSessionEvaluation
+from moabb.paradigms import FilterBankLeftRightImagery, LeftRightImagery
+from moabb.pipelines.utils import FilterBank
+
+
+moabb.set_log_level("info")
+
+
+
+

Create Pipelines#

+

The CSP implementation from MNE is used. We selected 8 CSP components, as +usually done in the literature.

+

The second pipeline is the filter bank CSP. We use the FilterBank object +with a CSP estimator. We set up the CSP to 4 components, to compensate for +the higher dimensionality.

+

The two pipelines will be applied on two different paradigm, so they have +their own dict.

+
pipelines = {}
+pipelines["CSP+LDA"] = make_pipeline(CSP(n_components=8), LDA())
+
+pipelines_fb = {}
+pipelines_fb["FBCSP+LDA"] = make_pipeline(FilterBank(CSP(n_components=4)), LDA())
+
+
+
+
+

Evaluation#

+

Since two different preprocessing will be applied, we have two different +paradigm objects. We have to make sure their filter matches so the comparison +will be fair.

+

The first one is a standard LeftRightImagery with a 8 to 35 Hz broadband +filter.

+

The second is a FilterBankLeftRightImagery with a bank of 2 filters, ranging +from 8 to 35 Hz.

+
# Because this is being auto-generated we only use 2 subjects
+dataset = BNCI2014_001()
+dataset.subject_list = dataset.subject_list[:2]
+datasets = [dataset]
+overwrite = False  # set to True if we want to overwrite cached results
+
+# broadband filters
+fmin = 8
+fmax = 35
+paradigm = LeftRightImagery(fmin=fmin, fmax=fmax)
+evaluation = CrossSessionEvaluation(
+    paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite
+)
+results = evaluation.process(pipelines)
+
+# Bank of 2 filters
+filters = [[8, 24], [16, 32]]
+paradigm = FilterBankLeftRightImagery(filters=filters)
+evaluation = CrossSessionEvaluation(
+    paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite
+)
+results_fb = evaluation.process(pipelines_fb)
+
+
+
BNCI2014-001-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]Subject 1 already processed
+
+BNCI2014-001-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]
+
+BNCI2014-001-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]Subject 1 already processed
+
+BNCI2014-001-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]
+
+
+

After processing the two, we simply concatenate the results.

+
results = pd.concat([results, results_fb])
+
+
+
+
+

Plot Results#

+

Here we plot the results via seaborn. We first display a pointplot +with the average performance of each pipeline across session and subjects. +The second plot is a paired scatter plot. Each point representing the score +of a single session. An algorithm will outperform another is most of the +points are in its quadrant.

+
fig, axes = plt.subplots(1, 2, figsize=[8, 4], sharey=True)
+
+sns.stripplot(
+    data=results,
+    y="score",
+    x="pipeline",
+    ax=axes[0],
+    jitter=True,
+    alpha=0.5,
+    zorder=1,
+    palette="Set1",
+)
+sns.pointplot(data=results, y="score", x="pipeline", ax=axes[0], palette="Set1")
+
+axes[0].set_ylabel("ROC AUC")
+axes[0].set_ylim(0.5, 1)
+
+# paired plot
+paired = results.pivot_table(
+    values="score", columns="pipeline", index=["subject", "session"]
+)
+paired = paired.reset_index()
+
+sns.regplot(data=paired, y="FBCSP+LDA", x="CSP+LDA", ax=axes[1], fit_reg=False)
+axes[1].plot([0, 1], [0, 1], ls="--", c="k")
+axes[1].set_xlim(0.5, 1)
+
+plt.show()
+
+
+plot filterbank csp vs csp

Total running time of the script: ( 0 minutes 2.261 seconds)

+

Estimated memory usage: 9 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/advanced_examples/plot_grid_search_withinsession.html b/docs/auto_examples/advanced_examples/plot_grid_search_withinsession.html new file mode 100644 index 00000000..a05015d4 --- /dev/null +++ b/docs/auto_examples/advanced_examples/plot_grid_search_withinsession.html @@ -0,0 +1,993 @@ + + + + + + + + + + + + GridSearch within a session — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

GridSearch within a session#

+

This example demonstrates how to make a model selection in pipelines +for finding the best model parameter, using grid search. Two models +are compared, one “vanilla” model with model tuned via grid search.

+
import os
+from pickle import load
+
+import matplotlib.pyplot as plt
+import seaborn as sns
+from pyriemann.estimation import Covariances
+from pyriemann.tangentspace import TangentSpace
+from sklearn.linear_model import LogisticRegression
+from sklearn.pipeline import Pipeline
+
+from moabb.datasets import BNCI2014_001
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import MotorImagery
+
+
+# Initialize parameter for the Band Pass filter
+fmin = 8
+fmax = 35
+tmax = None
+
+# Select the Subject
+subjects = [1]
+# Load the dataset
+dataset = BNCI2014_001()
+
+events = ["right_hand", "left_hand"]
+
+paradigm = MotorImagery(
+    events=events, n_classes=len(events), fmin=fmin, fmax=fmax, tmax=tmax
+)
+
+# Create a path and folder for every subject
+path = os.path.join(str("Results"))
+os.makedirs(path, exist_ok=True)
+
+
+
+

Create the Pipelines#

+

Two pipelines implementing elastic net classifiers, one using a fixed +l1_ratio (“VanillaEN”) and the other using a range of values to select +l1_ratio (“GridSearchEN”)

+
pipelines = {}
+pipelines["VanillaEN"] = Pipeline(
+    steps=[
+        ("Covariances", Covariances("cov")),
+        ("Tangent_Space", TangentSpace(metric="riemann")),
+        (
+            "LogistReg",
+            LogisticRegression(
+                penalty="elasticnet",
+                l1_ratio=0.75,
+                intercept_scaling=1000.0,
+                solver="saga",
+                max_iter=1000,
+            ),
+        ),
+    ]
+)
+
+pipelines["GridSearchEN"] = Pipeline(
+    steps=[
+        ("Covariances", Covariances("cov")),
+        ("Tangent_Space", TangentSpace(metric="riemann")),
+        (
+            "LogistReg",
+            LogisticRegression(
+                penalty="elasticnet",
+                l1_ratio=0.70,
+                intercept_scaling=1000.0,
+                solver="saga",
+                max_iter=1000,
+            ),
+        ),
+    ]
+)
+
+
+

The search space for parameters is defined as a dictionary, specifying the +name of the estimator and the parameter name as a key.

+
param_grid = {}
+param_grid["GridSearchEN"] = {
+    "LogistReg__l1_ratio": [0.15, 0.30, 0.45, 0.60, 0.75],
+}
+
+
+
+
+

Running the Evaluation#

+

If a param_grid is specified during process, the specified pipelines will +automatically be run with a grid search.

+
dataset.subject_list = dataset.subject_list[:1]
+evaluation = WithinSessionEvaluation(
+    paradigm=paradigm,
+    datasets=dataset,
+    overwrite=True,
+    random_state=42,
+    hdf5_path=path,
+    n_jobs=-1,
+    save_model=True,
+)
+result = evaluation.process(pipelines, param_grid)
+
+
+
BNCI2014-001-WithinSession:   0%|          | 0/1 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-001-WithinSession: 100%|##########| 1/1 [00:10<00:00, 10.98s/it]
+BNCI2014-001-WithinSession: 100%|##########| 1/1 [00:10<00:00, 10.98s/it]
+
+
+
+
+

Plot Results#

+

The grid search allows to find better parameter during the +evaluation, leading to better accuracy results.

+
fig, axes = plt.subplots(1, 1, figsize=[8, 5], sharey=True)
+
+sns.stripplot(
+    data=result,
+    y="score",
+    x="pipeline",
+    ax=axes,
+    jitter=True,
+    alpha=0.5,
+    zorder=1,
+    palette="Set1",
+)
+sns.pointplot(data=result, y="score", x="pipeline", ax=axes, palette="Set1")
+axes.set_ylabel("ROC AUC")
+
+
+plot grid search withinsession
Text(44.972222222222214, 0.5, 'ROC AUC')
+
+
+
+
+

Load Best Model Parameter#

+

The best model are automatically saved in a pickle file, in the +results directory. It is possible to load those model for each +dataset, subject and session. Here, we could see that the grid +search found a l1_ratio that is different from the baseline +value.

+
with open(
+    "./Results/Models_WithinSession/BNCI2014-001/1/1test/GridSearchEN/fitted_model_best.pkl",
+    "rb",
+) as pickle_file:
+    GridSearchEN_Session_E = load(pickle_file)
+
+print(
+    "Best Parameter l1_ratio Session_E GridSearchEN ",
+    GridSearchEN_Session_E.best_params_["LogistReg__l1_ratio"],
+)
+
+print(
+    "Best Parameter l1_ratio Session_E VanillaEN: ",
+    pipelines["VanillaEN"].steps[2][1].l1_ratio,
+)
+
+with open(
+    "./Results/Models_WithinSession/BNCI2014-001/1/0train/GridSearchEN/fitted_model_best.pkl",
+    "rb",
+) as pickle_file:
+    GridSearchEN_Session_T = load(pickle_file)
+
+print(
+    "Best Parameter l1_ratio Session_T GridSearchEN ",
+    GridSearchEN_Session_T.best_params_["LogistReg__l1_ratio"],
+)
+
+print(
+    "Best Parameter l1_ratio Session_T VanillaEN: ",
+    pipelines["VanillaEN"].steps[2][1].l1_ratio,
+)
+
+
+
Best Parameter l1_ratio Session_E GridSearchEN  0.15
+Best Parameter l1_ratio Session_E VanillaEN:  0.75
+Best Parameter l1_ratio Session_T GridSearchEN  0.15
+Best Parameter l1_ratio Session_T VanillaEN:  0.75
+
+
+

Total running time of the script: ( 0 minutes 13.381 seconds)

+

Estimated memory usage: 257 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/advanced_examples/plot_mne_and_scikit_estimators.html b/docs/auto_examples/advanced_examples/plot_mne_and_scikit_estimators.html new file mode 100644 index 00000000..1ce56469 --- /dev/null +++ b/docs/auto_examples/advanced_examples/plot_mne_and_scikit_estimators.html @@ -0,0 +1,1102 @@ + + + + + + + + + + + + MNE Epochs-based pipelines — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

MNE Epochs-based pipelines#

+

This example shows how to use machine learning pipeline based on MNE Epochs +instead of Numpy arrays. This is useful to make the most of the MNE code base +and to embed EEG specific code inside sklearn pipelines.

+

We will compare different pipelines for P300: +- Logistic regression, based on MNE Epochs +- XDAWN and Logistic Regression (LR), based on MNE Epochs +- XDAWN extended covariance and LR on tangent space, based on Numpy

+
# Authors: Sylvain Chevallier
+#
+# License: BSD (3-clause)
+# sphinx_gallery_thumbnail_number = 2
+
+import warnings
+
+import matplotlib.pyplot as plt
+import pandas as pd
+from mne.decoding import Vectorizer
+from mne.preprocessing import Xdawn
+from pyriemann.estimation import XdawnCovariances
+from pyriemann.tangentspace import TangentSpace
+from sklearn.base import BaseEstimator, TransformerMixin
+from sklearn.linear_model import LogisticRegression
+from sklearn.pipeline import make_pipeline
+from sklearn.preprocessing import StandardScaler
+
+import moabb
+from moabb.analysis.meta_analysis import (  # noqa: E501
+    compute_dataset_statistics,
+    find_significant_differences,
+)
+from moabb.analysis.plotting import paired_plot, summary_plot
+from moabb.datasets import BNCI2014_009
+from moabb.evaluations import CrossSessionEvaluation
+from moabb.paradigms import P300
+
+
+warnings.simplefilter(action="ignore", category=FutureWarning)
+warnings.simplefilter(action="ignore", category=RuntimeWarning)
+moabb.set_log_level("info")
+
+
+
+

Loading Dataset#

+

Load 2 subjects of BNCI 2014-009 dataset, with 3 session each

+ +
+
+

Get Data (optional)#

+

To get access to the EEG signals downloaded from the dataset, you could +use dataset.get_data([subject_id) to obtain the EEG as MNE Epochs, stored +in a dictionary of sessions and runs. +The paradigm.get_data(dataset=dataset, subjects=[subject_id]) allows to +obtain the preprocessed EEG data, the labels and the meta information. By +default, the EEG is return as a Numpy array. With return_epochs=True, MNE +Epochs are returned.

+ +
/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+
+
+
+
+

A Simple MNE Pipeline#

+

Using return_epochs=True in the evaluation, it is possible to design a +pipeline based on MNE Epochs input. Let’s create a simple one, that +reshape the input data from epochs, rescale the data and uses a logistic +regression to classify the data. We will need to write a basic Transformer +estimator, that complies with +sklearn convention. +This transformer will extract the data from an input Epoch, and reshapes into +2D array.

+
class MyVectorizer(BaseEstimator, TransformerMixin):
+    def __init__(self):
+        pass
+
+    def fit(self, X, y=None):
+        arr = X.get_data()
+        self.features_shape_ = arr.shape[1:]
+        return self
+
+    def transform(self, X, y=None):
+        arr = X.get_data()
+        return arr.reshape(len(arr), -1)
+
+
+

We will define a pipeline that is based on this new class, using a scaler +and a logistic regression. This pipeline is evaluated across session using +ROC-AUC metric.

+
mne_ppl = {}
+mne_ppl["MNE LR"] = make_pipeline(
+    MyVectorizer(), StandardScaler(), LogisticRegression(penalty="l1", solver="liblinear")
+)
+
+mne_eval = CrossSessionEvaluation(
+    paradigm=paradigm,
+    datasets=datasets,
+    suffix="examples",
+    overwrite=True,
+    return_epochs=True,
+)
+mne_res = mne_eval.process(mne_ppl)
+
+
+
BNCI2014-009-CrossSession:   0%|          | 0/3 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-009-CrossSession:  33%|###3      | 1/3 [00:03<00:06,  3.19s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-009-CrossSession:  67%|######6   | 2/3 [00:06<00:03,  3.09s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-009-CrossSession: 100%|##########| 3/3 [00:10<00:00,  3.56s/it]
+BNCI2014-009-CrossSession: 100%|##########| 3/3 [00:10<00:00,  3.44s/it]
+
+
+
+
+

Advanced MNE Pipeline#

+

In some case, the MNE pipeline should have access to the original labels from +the dataset. This is the case for the XDAWN code of MNE. One could pass +mne_labels to evaluation in order to keep this label. +As an example, we will define a pipeline that computes an XDAWN filter, rescale, +then apply a logistic regression.

+
mne_adv = {}
+mne_adv["XDAWN LR"] = make_pipeline(
+    Xdawn(n_components=5, reg="ledoit_wolf", correct_overlap=False),
+    Vectorizer(),
+    StandardScaler(),
+    LogisticRegression(penalty="l1", solver="liblinear"),
+)
+adv_eval = CrossSessionEvaluation(
+    paradigm=paradigm,
+    datasets=datasets,
+    suffix="examples",
+    overwrite=True,
+    return_epochs=True,
+    mne_labels=True,
+)
+adv_res = mne_eval.process(mne_adv)
+
+
+
BNCI2014-009-CrossSession:   0%|          | 0/3 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-009-CrossSession:  33%|###3      | 1/3 [00:03<00:07,  3.53s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-009-CrossSession:  67%|######6   | 2/3 [00:06<00:03,  3.05s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-009-CrossSession: 100%|##########| 3/3 [00:10<00:00,  3.57s/it]
+BNCI2014-009-CrossSession: 100%|##########| 3/3 [00:10<00:00,  3.48s/it]
+
+
+
+
+

Numpy-based Pipeline#

+

For the comparison, we will define a Numpy-based pipeline that relies on +pyriemann to estimate XDAWN-extended covariance matrices that are projected +on the tangent space and classified with a logistic regression.

+
sk_ppl = {}
+sk_ppl["RG LR"] = make_pipeline(
+    XdawnCovariances(nfilter=5, estimator="lwf", xdawn_estimator="scm"),
+    TangentSpace(),
+    LogisticRegression(penalty="l1", solver="liblinear"),
+)
+sk_eval = CrossSessionEvaluation(
+    paradigm=paradigm,
+    datasets=datasets,
+    suffix="examples",
+    overwrite=True,
+)
+sk_res = sk_eval.process(sk_ppl)
+
+
+
BNCI2014-009-CrossSession:   0%|          | 0/3 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-009-CrossSession:  33%|###3      | 1/3 [00:07<00:14,  7.15s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-009-CrossSession:  67%|######6   | 2/3 [00:14<00:06,  6.99s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-009-CrossSession: 100%|##########| 3/3 [00:20<00:00,  6.93s/it]
+BNCI2014-009-CrossSession: 100%|##########| 3/3 [00:20<00:00,  6.97s/it]
+
+
+
+
+

Combining Results#

+

Even if the results have been obtained by different evaluation processes, it +is possible to combine the resulting DataFrames to analyze and plot the +results.

+
all_res = pd.concat([mne_res, adv_res, sk_res])
+
+
+

We could compare the Euclidean and Riemannian performance using a paired_plot

+
paired_plot(all_res, "XDAWN LR", "RG LR")
+
+
+plot mne and scikit estimators
<Figure size 1100x850 with 1 Axes>
+
+
+

All the results could be compared and statistical analysis could highlight the +differences between pipelines.

+ +Algorithm comparison

Total running time of the script: ( 0 minutes 45.979 seconds)

+

Estimated memory usage: 339 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/advanced_examples/plot_select_electrodes_resample.html b/docs/auto_examples/advanced_examples/plot_select_electrodes_resample.html new file mode 100644 index 00000000..58f04c5b --- /dev/null +++ b/docs/auto_examples/advanced_examples/plot_select_electrodes_resample.html @@ -0,0 +1,1211 @@ + + + + + + + + + + + + Select Electrodes and Resampling — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Select Electrodes and Resampling#

+

Within paradigm, it is possible to restrict analysis only to a subset of +electrodes and to resample to a specific sampling rate. There is also a +utility function to select common electrodes shared between datasets. +This tutorial demonstrates how to use this functionality.

+
# Authors: Sylvain Chevallier <sylvain.chevallier@uvsq.fr>
+#
+# License: BSD (3-clause)
+import matplotlib.pyplot as plt
+from mne.decoding import CSP
+from pyriemann.estimation import Covariances
+from pyriemann.tangentspace import TangentSpace
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.linear_model import LogisticRegression as LR
+from sklearn.pipeline import make_pipeline
+
+import moabb.analysis.plotting as moabb_plt
+from moabb.datasets import BNCI2014_001, Zhou2016
+from moabb.datasets.utils import find_intersecting_channels
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import LeftRightImagery
+
+
+
+

Datasets#

+

Load 2 subjects of BNCI 2014-004 and Zhou2016 datasets, with 2 sessions each

+
subj = [1, 2]
+datasets = [Zhou2016(), BNCI2014_001()]
+for d in datasets:
+    d.subject_list = subj
+
+
+
+
+

Paradigm#

+

Restrict further analysis to specified channels, here C3, C4, and Cz. +Also, use a specific resampling. In this example, all datasets are +set to 200 Hz.

+
paradigm = LeftRightImagery(channels=["C3", "C4", "Cz"], resample=200.0)
+
+
+
+
+

Evaluation#

+

The evaluation is conducted on with CSP+LDA, only on the 3 electrodes, with +a sampling rate of 200 Hz.

+
evaluation = WithinSessionEvaluation(paradigm=paradigm, datasets=datasets)
+csp_lda = make_pipeline(CSP(n_components=2), LDA())
+ts_lr = make_pipeline(
+    Covariances(estimator="oas"), TangentSpace(metric="riemann"), LR(C=1.0)
+)
+results = evaluation.process({"csp+lda": csp_lda, "ts+lr": ts_lr})
+print(results.head())
+
+
+
Zhou2016-WithinSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  60 events (all good), 0 – 5 s, baseline off, ~1.7 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 30>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  59 events (all good), 0 – 5 s, baseline off, ~1.7 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 29>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+Zhou2016-WithinSession:  50%|#####     | 1/2 [00:04<00:04,  4.97s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  40 events (all good), 0 – 5 s, baseline off, ~1.2 MB, data loaded,
+ 'left_hand': 20
+ 'right_hand': 20>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+Zhou2016-WithinSession: 100%|##########| 2/2 [00:09<00:00,  4.67s/it]
+Zhou2016-WithinSession: 100%|##########| 2/2 [00:09<00:00,  4.71s/it]
+
+BNCI2014-001-WithinSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-001-WithinSession:  50%|#####     | 1/2 [00:04<00:04,  4.25s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-001-WithinSession: 100%|##########| 2/2 [00:08<00:00,  4.08s/it]
+BNCI2014-001-WithinSession: 100%|##########| 2/2 [00:08<00:00,  4.10s/it]
+      score      time  samples subject  ... channels  n_sessions   dataset pipeline
+0  0.844823  0.058944    119.0       1  ...        3           3  Zhou2016    ts+lr
+1  0.900000  0.049391    100.0       1  ...        3           3  Zhou2016    ts+lr
+2  0.950000  0.049339    100.0       1  ...        3           3  Zhou2016    ts+lr
+3  0.918000  0.049579    100.0       2  ...        3           3  Zhou2016    ts+lr
+4  0.817284  0.045368     90.0       2  ...        3           3  Zhou2016    ts+lr
+
+[5 rows x 9 columns]
+
+
+
+
+

Electrode Selection#

+

It is possible to select the electrodes that are shared by all datasets +using the find_intersecting_channels function. Datasets that have 0 +overlap with others are discarded. It returns the set of common channels, +as well as the list of datasets with valid channels.

+
electrodes, datasets = find_intersecting_channels(datasets)
+evaluation = WithinSessionEvaluation(
+    paradigm=paradigm, datasets=datasets, overwrite=True, suffix="resample"
+)
+results = evaluation.process({"csp+lda": csp_lda, "ts+lr": ts_lr})
+print(results.head())
+
+
+
Searching dataset: Zhou2016
+Searching dataset: BNCI2014_001
+
+Zhou2016-WithinSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  60 events (all good), 0 – 5 s, baseline off, ~1.7 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 30>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  59 events (all good), 0 – 5 s, baseline off, ~1.7 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 29>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+Zhou2016-WithinSession:  50%|#####     | 1/2 [00:04<00:04,  4.88s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  40 events (all good), 0 – 5 s, baseline off, ~1.2 MB, data loaded,
+ 'left_hand': 20
+ 'right_hand': 20>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~1.4 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+Zhou2016-WithinSession: 100%|##########| 2/2 [00:09<00:00,  4.49s/it]
+Zhou2016-WithinSession: 100%|##########| 2/2 [00:09<00:00,  4.55s/it]
+
+BNCI2014-001-WithinSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-001-WithinSession:  50%|#####     | 1/2 [00:04<00:04,  4.13s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~582 kB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-001-WithinSession: 100%|##########| 2/2 [00:08<00:00,  4.14s/it]
+BNCI2014-001-WithinSession: 100%|##########| 2/2 [00:08<00:00,  4.14s/it]
+      score      time  samples subject  ... channels  n_sessions   dataset pipeline
+0  0.865657  0.058112    119.0       1  ...        3           3  Zhou2016    ts+lr
+1  0.916000  0.049458    100.0       1  ...        3           3  Zhou2016    ts+lr
+2  0.932000  0.050020    100.0       1  ...        3           3  Zhou2016    ts+lr
+3  0.924000  0.050490    100.0       2  ...        3           3  Zhou2016    ts+lr
+4  0.829630  0.045536     90.0       2  ...        3           3  Zhou2016    ts+lr
+
+[5 rows x 9 columns]
+
+
+
+
+

Plot Results#

+

Compare the obtained results with the two pipelines, CSP+LDA and logistic +regression computed in the tangent space of the covariance matrices.

+
fig = moabb_plt.paired_plot(results, "csp+lda", "ts+lr")
+plt.show()
+
+
+plot select electrodes resample

Total running time of the script: ( 0 minutes 41.373 seconds)

+

Estimated memory usage: 429 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/advanced_examples/plot_statistical_analysis.html b/docs/auto_examples/advanced_examples/plot_statistical_analysis.html new file mode 100644 index 00000000..f45835d0 --- /dev/null +++ b/docs/auto_examples/advanced_examples/plot_statistical_analysis.html @@ -0,0 +1,1090 @@ + + + + + + + + + + + + Statistical Analysis — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Statistical Analysis#

+

The MOABB codebase comes with convenience plotting utilities and some +statistical testing. This tutorial focuses on what those exactly are and how +they can be used.

+
# Authors: Vinay Jayaram <vinayjayaram13@gmail.com>
+#
+# License: BSD (3-clause)
+# sphinx_gallery_thumbnail_number = -2
+
+import matplotlib.pyplot as plt
+from mne.decoding import CSP
+from pyriemann.estimation import Covariances
+from pyriemann.tangentspace import TangentSpace
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.linear_model import LogisticRegression
+from sklearn.pipeline import make_pipeline
+
+import moabb
+import moabb.analysis.plotting as moabb_plt
+from moabb.analysis.meta_analysis import (  # noqa: E501
+    compute_dataset_statistics,
+    find_significant_differences,
+)
+from moabb.datasets import BNCI2014_001
+from moabb.evaluations import CrossSessionEvaluation
+from moabb.paradigms import LeftRightImagery
+
+
+moabb.set_log_level("info")
+
+print(__doc__)
+
+
+
+

Results Generation#

+

First we need to set up a paradigm, dataset list, and some pipelines to +test. This is explored more in the examples – we choose left vs right +imagery paradigm with a single bandpass. There is only one dataset here but +any number can be added without changing this workflow.

+
+
+

Create Pipelines#

+

Pipelines must be a dict of sklearn pipeline transformer.

+

The CSP implementation from MNE is used. We selected 8 CSP components, as +usually done in the literature.

+

The Riemannian geometry pipeline consists in covariance estimation, tangent +space mapping and finally a logistic regression for the classification.

+
pipelines = {}
+
+pipelines["CSP+LDA"] = make_pipeline(CSP(n_components=8), LDA())
+
+pipelines["RG+LR"] = make_pipeline(Covariances(), TangentSpace(), LogisticRegression())
+
+pipelines["CSP+LR"] = make_pipeline(CSP(n_components=8), LogisticRegression())
+
+pipelines["RG+LDA"] = make_pipeline(Covariances(), TangentSpace(), LDA())
+
+
+
+
+

Evaluation#

+

We define the paradigm (LeftRightImagery) and the dataset (BNCI2014_001). +The evaluation will return a DataFrame containing a single AUC score for +each subject / session of the dataset, and for each pipeline.

+

Results are saved into the database, so that if you add a new pipeline, it +will not run again the evaluation unless a parameter has changed. Results can +be overwritten if necessary.

+ +
BNCI2014-001-CrossSession:   0%|          | 0/4 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-001-CrossSession:  25%|##5       | 1/4 [00:06<00:18,  6.16s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-001-CrossSession:  50%|#####     | 2/4 [00:12<00:12,  6.13s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-001-CrossSession:  75%|#######5  | 3/4 [00:18<00:06,  6.06s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-001-CrossSession: 100%|##########| 4/4 [00:24<00:00,  6.06s/it]
+BNCI2014-001-CrossSession: 100%|##########| 4/4 [00:24<00:00,  6.08s/it]
+
+
+
+
+

MOABB Plotting#

+

Here we plot the results using some of the convenience methods within the +toolkit. The score_plot visualizes all the data with one score per subject +for every dataset and pipeline.

+ +Scores per dataset and algorithm
/home/runner/work/moabb/moabb/moabb/analysis/plotting.py:70: UserWarning: The palette list has more values (6) than needed (4), which may not be intended.
+  sea.stripplot(
+
+
+

For a comparison of two algorithms, there is the paired_plot, which plots +performance in one versus the performance in the other over all chosen +datasets. Note that there is only one score per subject, regardless of the +number of sessions.

+
fig = moabb_plt.paired_plot(results, "CSP+LDA", "RG+LDA")
+plt.show()
+
+
+plot statistical analysis
+
+

Statistical Testing and Further Plots#

+

If the statistical significance of results is of interest, the method +compute_dataset_statistics allows one to show a meta-analysis style plot as +well. For an overview of how all algorithms perform in comparison with each +other, the method find_significant_differences and the summary_plot are +possible.

+
+
+

The meta-analysis style plot shows the standardized mean difference within +each tested dataset for the two algorithms in question, in addition to a +meta-effect and significance both per-dataset and overall.

+
fig = moabb_plt.meta_analysis_plot(stats, "CSP+LDA", "RG+LDA")
+plt.show()
+
+
+< RG+LDA better                                                                              CSP+LDA better >, p-value

The summary plot shows the effect and significance related to the hypothesis +that the algorithm on the y-axis significantly outperformed the algorithm on +the x-axis over all datasets

+ +Algorithm comparison

Total running time of the script: ( 0 minutes 28.585 seconds)

+

Estimated memory usage: 308 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/advanced_examples/sg_execution_times.html b/docs/auto_examples/advanced_examples/sg_execution_times.html new file mode 100644 index 00000000..dff76b53 --- /dev/null +++ b/docs/auto_examples/advanced_examples/sg_execution_times.html @@ -0,0 +1,546 @@ + + + + + + + + + + + + Computation times — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Computation times#

+

02:11.578 total execution time for auto_examples_advanced_examples files:

+ + + + + + + + + + + + + + + + + + + + + + + +

MNE Epochs-based pipelines (plot_mne_and_scikit_estimators.py)

00:45.979

339.3 MB

Select Electrodes and Resampling (plot_select_electrodes_resample.py)

00:41.373

429.1 MB

Statistical Analysis (plot_statistical_analysis.py)

00:28.585

307.7 MB

GridSearch within a session (plot_grid_search_withinsession.py)

00:13.381

257.3 MB

FilterBank CSP versus CSP (plot_filterbank_csp_vs_csp.py)

00:02.261

8.8 MB

+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/changing_download_directory.html b/docs/auto_examples/changing_download_directory.html new file mode 100644 index 00000000..1fb794a9 --- /dev/null +++ b/docs/auto_examples/changing_download_directory.html @@ -0,0 +1,766 @@ + + + + + + + + + + + + Change Download Directory — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Change Download Directory#

+

This is a minimal example to demonstrate how to change the default data +download directory to a custom path/location.

+
# Authors: Divyesh Narayanan <divyesh.narayanan@gmail.com>
+#
+# License: BSD (3-clause)
+
+import os.path as osp
+
+from mne import get_config
+
+from moabb.utils import set_download_dir
+
+
+

You can choose to change the download directory to any path of your choice. +If the path/folder doesn’t exist, it will be created for you.

+
original_path = get_config("MNE_DATA")
+print(f"The download directory is currently {original_path}")
+new_path = osp.join(osp.expanduser("~"), "mne_data_test")
+set_download_dir(new_path)
+
+
+

You could verify that the MNE config has been changed correctly

+
check_path = get_config("MNE_DATA")
+print(f"Now the download directory has been changed to {check_path}")
+
+
+

Set the directory back to default location

+
set_download_dir(original_path)
+
+
+

Total running time of the script: ( 0 minutes 0.000 seconds)

+

Estimated memory usage: 0 MB

+ +

Gallery generated by Sphinx-Gallery

+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/example_codecarbon.html b/docs/auto_examples/example_codecarbon.html new file mode 100644 index 00000000..8132e206 --- /dev/null +++ b/docs/auto_examples/example_codecarbon.html @@ -0,0 +1,863 @@ + + + + + + + + + + + + Benchmarking with MOABB showing the CO2 footprint — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Benchmarking with MOABB showing the CO2 footprint#

+

This example shows how to use MOABB to track the CO2 footprint +using CodeCarbon library. +For this example, we will use only one +dataset to keep the computation time low, but this benchmark is designed +to easily scale to many datasets. Due to limitation of online documentation +generation, the results is computed on a local cluster but could be easily +replicated on your infrastructure.

+
# Authors: Igor Carrara <igor.carrara@inria.fr>
+#          Bruno Aristimunha <b.aristimunha@gmail.com>
+#
+# License: BSD (3-clause)
+
+
+
from moabb import benchmark, set_log_level
+from moabb.analysis.plotting import codecarbon_plot
+from moabb.datasets import BNCI2014_001, Zhou2016
+from moabb.paradigms import LeftRightImagery
+
+
+set_log_level("info")
+
+
+
+

Loading the pipelines#

+

To run this example we use several pipelines, ML and DL (Keras) and also +pipelines that need an optimization of the hyperparameter. +All this different pipelines are stored in pipelines_codecarbon

+
+
+

Selecting the datasets (optional)#

+

If you want to limit your benchmark on a subset of datasets, you can use the +include_datasets and exclude_datasets arguments. You will need either +to provide the dataset’s object, or a dataset’s code. To get the list of +available dataset’s code for a given paradigm, you can use the following +command:

+
paradigm = LeftRightImagery()
+for d in paradigm.datasets:
+    print(d.code)
+
+
+

In this example, we will use only the last dataset, ‘Zhou 2016’, considering +only the first subject.

+
+
+

Running the benchmark#

+

The benchmark is run using the benchmark function. You need to specify the +folder containing the pipelines to use, the kind of evaluation and the paradigm +to use. By default, the benchmark will use all available datasets for all +paradigms listed in the pipelines. You could restrict to specific evaluation +and paradigm using the evaluations and paradigms arguments.

+

To save computation time, the results are cached. If you want to re-run the +benchmark, you can set the overwrite argument to True.

+

It is possible to indicate the folder to cache the results and the one to +save the analysis & figures. By default, the results are saved in the +results folder, and the analysis & figures are saved in the benchmark +folder.

+
dataset = Zhou2016()
+dataset2 = BNCI2014_001()
+dataset.subject_list = dataset.subject_list[:1]
+dataset2.subject_list = dataset2.subject_list[:1]
+datasets = [dataset, dataset2]
+
+results = benchmark(
+    pipelines="./pipelines_codecarbon/",
+    evaluations=["WithinSession"],
+    paradigms=["LeftRightImagery"],
+    include_datasets=datasets,
+    results="./results/",
+    overwrite=False,
+    plot=False,
+    output="./benchmark/",
+)
+
+
+

Benchmark prints a summary of the results. Detailed results are saved in a +pandas dataframe, and can be used to generate figures. The analysis & figures +are saved in the benchmark folder.

+
results.head()
+
+order_list = [
+    "CSP + SVM",
+    "Tangent Space LR",
+    "EN Grid",
+    "CSP + LDA Grid",
+    "Keras_EEGNet_8_2",
+]
+
+
+
+
+

Plotting the results#

+

We can plot the results using the codecarbon_plot function, generated +below. This function takes the dataframe returned by the benchmark +function as input, and returns a pyplot figure. +The order_list argument is used to specify the order of the pipelines in +the plot.

+
codecarbon_plot(results, order_list, country="(France)")
+
+
+
+
The result expected will be the following image, but varying depending on the

machine and the country used to run the example.

+carbon_example +
+
+
+

Total running time of the script: ( 0 minutes 0.000 seconds)

+

Estimated memory usage: 0 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/external/index.html b/docs/auto_examples/external/index.html new file mode 100644 index 00000000..85a0e566 --- /dev/null +++ b/docs/auto_examples/external/index.html @@ -0,0 +1,728 @@ + + + + + + + + + + + + External examples — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

External examples#

+

You need to install external dependencies to run these examples. These consist mostly of +various classifier implementations. When using poetry, you can use

+

poetry install --extras external

+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
+
+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/external/plot_learning_curve_p300_external.html b/docs/auto_examples/external/plot_learning_curve_p300_external.html new file mode 100644 index 00000000..b3981374 --- /dev/null +++ b/docs/auto_examples/external/plot_learning_curve_p300_external.html @@ -0,0 +1,1105 @@ + + + + + + + + + + + + Within Session P300 with Learning Curve — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Within Session P300 with Learning Curve#

+

This example shows how to perform a within session analysis while also +creating learning curves for a P300 dataset. +Additionally, we will evaluate external code. Make sure to have tdlda installed +, which can be found in requirements_external.txt

+

We will compare three pipelines :

+
    +
  • Riemannian geometry

  • +
  • Jumping Means-based Linear Discriminant Analysis

  • +
  • Time-Decoupled Linear Discriminant Analysis

  • +
+

We will use the P300 paradigm, which uses the AUC as metric.

+
# Authors: Jan Sosulski
+#
+# License: BSD (3-clause)
+
+import warnings
+
+import matplotlib.pyplot as plt
+import numpy as np
+import seaborn as sns
+from pyriemann.estimation import XdawnCovariances
+from pyriemann.tangentspace import TangentSpace
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.pipeline import make_pipeline
+from tdlda import TimeDecoupledLda
+from tdlda import Vectorizer as JumpingMeansVectorizer
+
+import moabb
+from moabb.datasets import BNCI2014_009
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import P300
+
+
+# getting rid of the warnings about the future (on s'en fout !)
+warnings.simplefilter(action="ignore", category=FutureWarning)
+warnings.simplefilter(action="ignore", category=RuntimeWarning)
+
+moabb.set_log_level("info")
+
+
+
+

Create pipelines#

+

Pipelines must be a dict of sklearn pipeline transformer.

+
processing_sampling_rate = 128
+pipelines = {}
+
+# We have to do this because the classes are called 'Target' and 'NonTarget'
+# but the evaluation function uses a LabelEncoder, transforming them
+# to 0 and 1
+labels_dict = {"Target": 1, "NonTarget": 0}
+
+# Riemannian geometry based classification
+pipelines["RG+LDA"] = make_pipeline(
+    XdawnCovariances(nfilter=5, estimator="lwf", xdawn_estimator="scm"),
+    TangentSpace(),
+    LDA(solver="lsqr", shrinkage="auto"),
+)
+
+# Simple LDA pipeline using averaged feature values in certain time intervals
+jumping_mean_ivals = [
+    [0.10, 0.139],
+    [0.14, 0.169],
+    [0.17, 0.199],
+    [0.20, 0.229],
+    [0.23, 0.269],
+    [0.27, 0.299],
+    [0.30, 0.349],
+    [0.35, 0.409],
+    [0.41, 0.449],
+    [0.45, 0.499],
+]
+jmv = JumpingMeansVectorizer(
+    fs=processing_sampling_rate, jumping_mean_ivals=jumping_mean_ivals
+)
+
+pipelines["JM+LDA"] = make_pipeline(jmv, LDA(solver="lsqr", shrinkage="auto"))
+
+# Time-decoupled Covariance classifier, needs information about number of
+# channels and time intervals
+c = TimeDecoupledLda(N_channels=16, N_times=10)
+# TD-LDA needs to know about the used jumping means intervals
+c.preproc = jmv
+pipelines["JM+TD-LDA"] = make_pipeline(jmv, c)
+
+
+
+
+

Evaluation#

+

We define the paradigm (P300) and use the BNCI 2014-009 dataset for it. +The evaluation will return a dataframe containing AUCs for each permutation +and dataset size.

+
paradigm = P300(resample=processing_sampling_rate)
+dataset = BNCI2014_009()
+# Remove the slicing of the subject list to evaluate multiple subjects
+dataset.subject_list = dataset.subject_list[0:1]
+datasets = [dataset]
+overwrite = True  # set to True if we want to overwrite cached results
+data_size = dict(policy="ratio", value=np.geomspace(0.02, 1, 6))
+# When the training data is sparse, perform more permutations than when we have
+# a lot of data
+n_perms = np.floor(np.geomspace(20, 2, len(data_size["value"]))).astype(int)
+print(n_perms)
+# Guarantee reproducibility
+np.random.seed(7536298)
+evaluation = WithinSessionEvaluation(
+    paradigm=paradigm,
+    datasets=datasets,
+    data_size=data_size,
+    n_perms=n_perms,
+    suffix="examples_lr",
+    overwrite=overwrite,
+)
+
+results = evaluation.process(pipelines)
+
+
+
[20 12  7  5  3  2]
+
+BNCI2014-009-WithinSession:   0%|          | 0/1 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+
+BNCI2014-009-WithinSession: 100%|##########| 1/1 [01:56<00:00, 116.33s/it]
+BNCI2014-009-WithinSession: 100%|##########| 1/1 [01:56<00:00, 116.33s/it]
+
+
+
+
+

Plot Results#

+

Here we plot the results.

+
fig, ax = plt.subplots(facecolor="white", figsize=[8, 4])
+
+n_subs = len(dataset.subject_list)
+
+if n_subs > 1:
+    r = results.groupby(["pipeline", "subject", "data_size"]).mean().reset_index()
+else:
+    r = results
+
+sns.pointplot(data=r, x="data_size", y="score", hue="pipeline", ax=ax, palette="Set1")
+
+errbar_meaning = "subjects" if n_subs > 1 else "permutations"
+title_str = f"Errorbar shows Mean-CI across {errbar_meaning}"
+ax.set_xlabel("Amount of training samples")
+ax.set_ylabel("ROC AUC")
+ax.set_title(title_str)
+fig.tight_layout()
+plt.show()
+
+
+Errorbar shows Mean-CI across permutations

Total running time of the script: ( 1 minutes 58.646 seconds)

+

Estimated memory usage: 13 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/external/sg_execution_times.html b/docs/auto_examples/external/sg_execution_times.html new file mode 100644 index 00000000..263861e1 --- /dev/null +++ b/docs/auto_examples/external/sg_execution_times.html @@ -0,0 +1,530 @@ + + + + + + + + + + + + Computation times — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Computation times#

+

01:58.646 total execution time for auto_examples_external files:

+ + + + + + + +

Within Session P300 with Learning Curve (plot_learning_curve_p300_external.py)

01:58.646

12.9 MB

+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/index.html b/docs/auto_examples/index.html new file mode 100644 index 00000000..4407ac78 --- /dev/null +++ b/docs/auto_examples/index.html @@ -0,0 +1,865 @@ + + + + + + + + + + + + Examples — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Examples#

+

These examples demonstrate how to use MOABB, and its main concepts the +dataset, paradigm and evaluation. Those examples are using +only a small number of subjects, and a small number of sessions, to +keep the execution time short. In practice, you should use all the +subjects and sessions available in the dataset.

+
Change Download Directory +

Change Download Directory

+
Change Download Directory
+
Benchmarking with MOABB showing the CO2 footprint +

Benchmarking with MOABB showing the CO2 footprint

+
Benchmarking with MOABB showing the CO2 footprint
+
Load Model (Scikit, Pytorch, Keras) with MOABB +

Load Model (Scikit, Pytorch, Keras) with MOABB

+
Load Model (Scikit, Pytorch, Keras) with MOABB
+
Convert a MOABB dataset to BIDS +

Convert a MOABB dataset to BIDS

+
Convert a MOABB dataset to BIDS
+
Spectral analysis of the trials +

Spectral analysis of the trials

+
Spectral analysis of the trials
+
Example of P300 classification with different epoch size. +

sphx_glr_auto_examples_noplot_vr_pc_p300_different_epoch_size.py

+
Example of P300 classification with different epoch size.
+
Examples of how to use MOABB to benchmark pipelines. +

Examples of how to use MOABB to benchmark pipelines.

+
Examples of how to use MOABB to benchmark pipelines.
+
Benchmarking on MOABB with Tensorflow deep net architectures +

Benchmarking on MOABB with Tensorflow deep net architectures

+
Benchmarking on MOABB with Tensorflow deep net architectures
+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures +

Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures

+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures
+
Benchmarking with MOABB with Grid Search +

Benchmarking with MOABB with Grid Search

+
Benchmarking with MOABB with Grid Search
+
Cross-session motor imagery with deep learning EEGNet v4 model +

Cross-session motor imagery with deep learning EEGNet v4 model

+
Cross-session motor imagery with deep learning EEGNet v4 model
+
Cross-Session Motor Imagery +

Cross-Session Motor Imagery

+
Cross-Session Motor Imagery
+
Cross-Session on Multiple Datasets +

Cross-Session on Multiple Datasets

+
Cross-Session on Multiple Datasets
+
Cross-Subject SSVEP +

Cross-Subject SSVEP

+
Cross-Subject SSVEP
+
Cache on disk intermediate data processing states +

Cache on disk intermediate data processing states

+
Cache on disk intermediate data processing states
+
Explore Paradigm Object +

Explore Paradigm Object

+
Explore Paradigm Object
+
Fixed interval windows processing +

Fixed interval windows processing

+
Fixed interval windows processing
+
Within Session P300 +

Within Session P300

+
Within Session P300
+
Within Session SSVEP +

Within Session SSVEP

+
Within Session SSVEP
+
+
+
+
+

Advanced examples#

+

These examples show various advanced topics:

+
    +
  • using scikit-learn pipeline with MNE inputs

  • +
  • selecting electrodes or resampling signal

  • +
  • using filterbank approach in motor imagery

  • +
  • apply statistics for meta-analysis

  • +
  • using a gridsearch in within-subject decoding

  • +
+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
GridSearch within a session +

GridSearch within a session

+
GridSearch within a session
+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
+
+

External examples#

+

You need to install external dependencies to run these examples. These consist mostly of +various classifier implementations. When using poetry, you can use

+

poetry install --extras external

+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
+
+

Evaluation with learning curve#

+

These examples demonstrate how to make evaluations using only a subset of +available example. For example, if you consider a dataset with 100 trials for +each class, you could evaluate several pipelines by using only a fraction of +these trials. To ensure the robustness of the results, you need to specify the +number of permutations. If you use 10 trials per class and 20 permutations, +each pipeline will be evaluated on a subset of 10 trials chosen randomly, that +will be repeated 20 times with different trial subsets.

+
Within Session Motor Imagery with Learning Curve +

Within Session Motor Imagery with Learning Curve

+
Within Session Motor Imagery with Learning Curve
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
+
+ +

Gallery generated by Sphinx-Gallery

+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/learning_curve/index.html b/docs/auto_examples/learning_curve/index.html new file mode 100644 index 00000000..4b2ee953 --- /dev/null +++ b/docs/auto_examples/learning_curve/index.html @@ -0,0 +1,735 @@ + + + + + + + + + + + + Evaluation with learning curve — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Evaluation with learning curve#

+

These examples demonstrate how to make evaluations using only a subset of +available example. For example, if you consider a dataset with 100 trials for +each class, you could evaluate several pipelines by using only a fraction of +these trials. To ensure the robustness of the results, you need to specify the +number of permutations. If you use 10 trials per class and 20 permutations, +each pipeline will be evaluated on a subset of 10 trials chosen randomly, that +will be repeated 20 times with different trial subsets.

+
Within Session Motor Imagery with Learning Curve +

Within Session Motor Imagery with Learning Curve

+
Within Session Motor Imagery with Learning Curve
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
+
+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/learning_curve/plot_learning_curve_motor_imagery.html b/docs/auto_examples/learning_curve/plot_learning_curve_motor_imagery.html new file mode 100644 index 00000000..309cd4a1 --- /dev/null +++ b/docs/auto_examples/learning_curve/plot_learning_curve_motor_imagery.html @@ -0,0 +1,931 @@ + + + + + + + + + + + + Within Session Motor Imagery with Learning Curve — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Within Session Motor Imagery with Learning Curve#

+

This example shows how to perform a within session motor imagery analysis on the +very popular dataset 2a from the BCI competition IV.

+

We will compare two pipelines :

+
    +
  • CSP + LDA

  • +
  • Riemannian Geometry + Logistic Regression

  • +
+

We will use the LeftRightImagery paradigm. This will restrict the analysis +to two classes (left- vs right-hand) and use AUC as metric.

+
# Original author: Alexandre Barachant <alexandre.barachant@gmail.com>
+# Learning curve modification: Jan Sosulski
+#
+# License: BSD (3-clause)
+
+import matplotlib.pyplot as plt
+import numpy as np
+import seaborn as sns
+from mne.decoding import CSP
+from pyriemann.estimation import Covariances
+from pyriemann.tangentspace import TangentSpace
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.linear_model import LogisticRegression
+from sklearn.pipeline import make_pipeline
+
+import moabb
+from moabb.datasets import BNCI2014_001
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import LeftRightImagery
+
+
+moabb.set_log_level("info")
+
+
+
+

Create Pipelines#

+

Pipelines must be a dict of sklearn pipeline transformer.

+

The CSP implementation from MNE is used. We selected 8 CSP components, as +usually done in the literature.

+

The Riemannian geometry pipeline consists in covariance estimation, tangent +space mapping and finally a logistic regression for the classification.

+
pipelines = {}
+
+pipelines["CSP+LDA"] = make_pipeline(
+    CSP(n_components=8), LDA(solver="lsqr", shrinkage="auto")
+)
+
+pipelines["RG+LR"] = make_pipeline(
+    Covariances(), TangentSpace(), LogisticRegression(solver="lbfgs")
+)
+
+
+
+
+

Evaluation#

+

We define the paradigm (LeftRightImagery) and the dataset (BNCI2014_001). +The evaluation will return a DataFrame containing a single AUC score for +each subject / session of the dataset, and for each pipeline.

+

Results are saved into the database, so that if you add a new pipeline, it +will not run again the evaluation unless a parameter has changed. Results can +be overwritten if necessary.

+
paradigm = LeftRightImagery()
+dataset = BNCI2014_001()
+dataset.subject_list = dataset.subject_list[:1]
+datasets = [dataset]
+overwrite = True  # set to True if we want to overwrite cached results
+# Evaluate for a specific number of training samples per class
+data_size = dict(policy="per_class", value=np.array([5, 10, 30, 50]))
+# When the training data is sparse, perform more permutations than when we have a lot of data
+n_perms = np.floor(np.geomspace(20, 2, len(data_size["value"]))).astype(int)
+evaluation = WithinSessionEvaluation(
+    paradigm=paradigm,
+    datasets=datasets,
+    suffix="examples",
+    overwrite=overwrite,
+    data_size=data_size,
+    n_perms=n_perms,
+)
+
+results = evaluation.process(pipelines)
+
+print(results.head())
+
+
+
BNCI2014-001-WithinSession:   0%|          | 0/1 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-001-WithinSession: 100%|##########| 1/1 [00:34<00:00, 34.38s/it]
+BNCI2014-001-WithinSession: 100%|##########| 1/1 [00:34<00:00, 34.38s/it]
+      score      time  samples  ...  n_sessions       dataset pipeline
+0  0.704762  0.052010     10.0  ...           2  BNCI2014-001  CSP+LDA
+1  0.885714  0.057023     20.0  ...           2  BNCI2014-001  CSP+LDA
+2  1.000000  0.102005     60.0  ...           2  BNCI2014-001  CSP+LDA
+3  0.990476  0.191809    100.0  ...           2  BNCI2014-001  CSP+LDA
+4  0.480952  0.043582     10.0  ...           2  BNCI2014-001  CSP+LDA
+
+[5 rows x 11 columns]
+
+
+
+
+

Plot Results#

+

We plot the accuracy as a function of the number of training samples, for +each pipeline

+
fig, ax = plt.subplots(facecolor="white", figsize=[8, 4])
+
+n_subs = len(dataset.subject_list)
+
+if n_subs > 1:
+    r = results.groupby(["pipeline", "subject", "data_size"]).mean().reset_index()
+else:
+    r = results
+
+sns.pointplot(data=r, x="data_size", y="score", hue="pipeline", ax=ax, palette="Set1")
+
+errbar_meaning = "subjects" if n_subs > 1 else "permutations"
+title_str = f"Errorbar shows Mean-CI across {errbar_meaning}"
+ax.set_xlabel("Amount of training samples")
+ax.set_ylabel("ROC AUC")
+ax.set_title(title_str)
+fig.tight_layout()
+plt.show()
+
+
+Errorbar shows Mean-CI across permutations

Total running time of the script: ( 0 minutes 36.283 seconds)

+

Estimated memory usage: 257 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/learning_curve/plot_learning_curve_p300.html b/docs/auto_examples/learning_curve/plot_learning_curve_p300.html new file mode 100644 index 00000000..fc6e264a --- /dev/null +++ b/docs/auto_examples/learning_curve/plot_learning_curve_p300.html @@ -0,0 +1,1032 @@ + + + + + + + + + + + + Within Session P300 with Learning Curve — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Within Session P300 with Learning Curve#

+

This example shows how to perform a within session analysis while also +creating learning curves for a P300 dataset. +Additionally, we will evaluate external code. Make sure to have tdlda installed, which +can be found in requirements_external.txt

+

We will compare two pipelines :

+
    +
  • Riemannian geometry with Linear Discriminant Analysis

  • +
  • XDAWN and Linear Discriminant Analysis

  • +
+

We will use the P300 paradigm, which uses the AUC as metric.

+
# Authors: Jan Sosulski
+#
+# License: BSD (3-clause)
+
+import warnings
+
+import matplotlib.pyplot as plt
+import numpy as np
+import seaborn as sns
+from mne.decoding import Vectorizer
+from pyriemann.estimation import XdawnCovariances
+from pyriemann.spatialfilters import Xdawn
+from pyriemann.tangentspace import TangentSpace
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.pipeline import make_pipeline
+
+import moabb
+from moabb.datasets import BNCI2014_009
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import P300
+
+
+# getting rid of the warnings about the future (on s'en fout !)
+warnings.simplefilter(action="ignore", category=FutureWarning)
+warnings.simplefilter(action="ignore", category=RuntimeWarning)
+
+moabb.set_log_level("info")
+
+
+
+

Create Pipelines#

+

Pipelines must be a dict of sklearn pipeline transformer.

+ +

We have to do this because the classes are called ‘Target’ and ‘NonTarget’ +but the evaluation function uses a LabelEncoder, transforming them +to 0 and 1

+
labels_dict = {"Target": 1, "NonTarget": 0}
+
+# Riemannian geometry based classification
+pipelines["RG+LDA"] = make_pipeline(
+    XdawnCovariances(nfilter=5, estimator="lwf", xdawn_estimator="scm"),
+    TangentSpace(),
+    LDA(solver="lsqr", shrinkage="auto"),
+)
+
+pipelines["Xdw+LDA"] = make_pipeline(
+    Xdawn(nfilter=2, estimator="scm"), Vectorizer(), LDA(solver="lsqr", shrinkage="auto")
+)
+
+
+
+
+

Evaluation#

+

We define the paradigm (P300) and use all three datasets available for it. +The evaluation will return a DataFrame containing AUCs for each permutation +and dataset size.

+
paradigm = P300(resample=processing_sampling_rate)
+dataset = BNCI2014_009()
+# Remove the slicing of the subject list to evaluate multiple subjects
+dataset.subject_list = dataset.subject_list[1:2]
+datasets = [dataset]
+overwrite = True  # set to True if we want to overwrite cached results
+data_size = dict(policy="ratio", value=np.geomspace(0.02, 1, 4))
+# When the training data is sparse, perform more permutations than when we have a lot of data
+n_perms = np.floor(np.geomspace(20, 2, len(data_size["value"]))).astype(int)
+# Guarantee reproducibility
+np.random.seed(7536298)
+evaluation = WithinSessionEvaluation(
+    paradigm=paradigm,
+    datasets=datasets,
+    data_size=data_size,
+    n_perms=n_perms,
+    suffix="examples_lr",
+    overwrite=overwrite,
+)
+
+results = evaluation.process(pipelines)
+
+
+
BNCI2014-009-WithinSession:   0%|          | 0/1 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_shrunk_covariance.py:327: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/covariance/_empirical_covariance.py:95: UserWarning: Only one sample available. You may want to reshape your data array
+  warnings.warn(
+
+BNCI2014-009-WithinSession: 100%|##########| 1/1 [01:05<00:00, 65.35s/it]
+BNCI2014-009-WithinSession: 100%|##########| 1/1 [01:05<00:00, 65.35s/it]
+
+
+
+
+

Plot Results#

+

We plot the accuracy as a function of the number of training samples, for +each pipeline

+
fig, ax = plt.subplots(facecolor="white", figsize=[8, 4])
+
+n_subs = len(dataset.subject_list)
+
+if n_subs > 1:
+    r = results.groupby(["pipeline", "subject", "data_size"]).mean().reset_index()
+else:
+    r = results
+
+sns.pointplot(data=r, x="data_size", y="score", hue="pipeline", ax=ax, palette="Set1")
+
+errbar_meaning = "subjects" if n_subs > 1 else "permutations"
+title_str = f"Errorbar shows Mean-CI across {errbar_meaning}"
+ax.set_xlabel("Amount of training samples")
+ax.set_ylabel("ROC AUC")
+ax.set_title(title_str)
+fig.tight_layout()
+plt.show()
+
+
+Errorbar shows Mean-CI across permutations

Total running time of the script: ( 1 minutes 7.230 seconds)

+

Estimated memory usage: 11 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/learning_curve/sg_execution_times.html b/docs/auto_examples/learning_curve/sg_execution_times.html new file mode 100644 index 00000000..934f2f09 --- /dev/null +++ b/docs/auto_examples/learning_curve/sg_execution_times.html @@ -0,0 +1,534 @@ + + + + + + + + + + + + Computation times — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + + + + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/load_model.html b/docs/auto_examples/load_model.html new file mode 100644 index 00000000..64bfd3d9 --- /dev/null +++ b/docs/auto_examples/load_model.html @@ -0,0 +1,839 @@ + + + + + + + + + + + + Load Model (Scikit, Pytorch, Keras) with MOABB — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Load Model (Scikit, Pytorch, Keras) with MOABB#

+

This example shows how to use load the pretrained pipeline in MOABB.

+
# Authors: Igor Carrara <igor.carrara@inria.fr>
+#
+# License: BSD (3-clause)
+
+from pickle import load
+
+import keras
+import torch
+from braindecode import EEGClassifier
+from braindecode.models import EEGInception
+from scikeras.wrappers import KerasClassifier
+from sklearn.pipeline import Pipeline, make_pipeline
+from skorch.callbacks import EarlyStopping, EpochScoring
+from skorch.dataset import ValidSplit
+
+from moabb import set_log_level
+from moabb.pipelines.features import StandardScaler_Epoch
+from moabb.utils import setup_seed
+
+
+set_log_level("info")
+
+
+

In this example, we will use the results computed by the following examples

+ +
+
# Set up reproducibility of Tensorflow and PyTorch
+setup_seed(42)
+
+
+

Loading the Scikit-learn pipelines

+
with open(
+    "./results/Models_WithinSession/Zhou2016/1/0/CSP + SVM/fitted_model_best.pkl",
+    "rb",
+) as pickle_file:
+    CSP_SVM_Trained = load(pickle_file)
+
+
+

Loading the Keras model +We load the single Keras model, if we want we can set in the exact same pipeline.

+
model_Keras = keras.models.load_model(
+    "./results/Models_WithinSession/BNCI2014-001/1/1E/Keras_DeepConvNet/kerasdeepconvnet_fitted_model_best.h5"
+)
+# Now we need to instantiate a new SciKeras object since we only saved the Keras model
+Keras_DeepConvNet_Trained = KerasClassifier(model_Keras)
+# Create the pipelines
+
+
+pipes_keras = Pipeline(
+    [
+        ("StandardScaler_Epoch", StandardScaler_Epoch),
+        ("Keras_DeepConvNet_Trained", Keras_DeepConvNet_Trained),
+    ]
+)
+
+
+

Loading the PyTorch model

+
# Hyperparameter
+LEARNING_RATE = 0.0001
+WEIGHT_DECAY = 0
+BATCH_SIZE = 64
+SEED = 42
+VERBOSE = 1
+EPOCH = 2
+PATIENCE = 3
+
+# Define a Skorch classifier
+clf = EEGClassifier(
+    module=EEGInception,
+    optimizer=torch.optim.Adam,
+    optimizer__lr=LEARNING_RATE,
+    batch_size=BATCH_SIZE,
+    max_epochs=EPOCH,
+    train_split=ValidSplit(0.2, random_state=SEED),
+    callbacks=[
+        EarlyStopping(monitor="valid_loss", patience=PATIENCE),
+        EpochScoring(
+            scoring="accuracy", on_train=True, name="train_acc", lower_is_better=False
+        ),
+        EpochScoring(
+            scoring="accuracy", on_train=False, name="valid_acc", lower_is_better=False
+        ),
+    ],
+    verbose=VERBOSE,  # Not printing the results for each epoch
+)
+
+clf.initialize()
+
+f_params = "./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_model.pkl"
+f_optimizer = "./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_optim.pkl"
+f_history = "./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_history.json"
+
+clf.load_params(f_params=f_params, f_optimizer=f_optimizer, f_history=f_history)
+
+# Create the pipelines
+pipes_pytorch = make_pipeline(clf)
+
+
+

Total running time of the script: ( 0 minutes 0.000 seconds)

+

Estimated memory usage: 0 MB

+ +

Gallery generated by Sphinx-Gallery

+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/noplot_bids_conversion.html b/docs/auto_examples/noplot_bids_conversion.html new file mode 100644 index 00000000..9934bc10 --- /dev/null +++ b/docs/auto_examples/noplot_bids_conversion.html @@ -0,0 +1,884 @@ + + + + + + + + + + + + Convert a MOABB dataset to BIDS — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Convert a MOABB dataset to BIDS#

+

The Brain Imaging Data Structure (BIDS) format +is standard for storing neuroimaging data. +It follows fixed principles to facilitate the +sharing of neuroimaging data between researchers.

+

The MOABB library allows to convert any MOABB dataset to +BIDS [1] and [2].

+

In this example, we will convert the AlexMI dataset to BIDS using the +option cache_config=dict(path=temp_dir, save_raw=True) of the get_data +method from the dataset object.

+

This will automatically save the raw data in the BIDS format and allow to use +a cache for the next time the dataset is used.

+

We will use the AlexMI dataset [3], one of the smallest in +people and one that can be downloaded quickly.

+
# Authors: Pierre Guetschel <pierre.guetschel@gmail.com>
+#
+# License: BSD (3-clause)
+
+import shutil
+import tempfile
+from pathlib import Path
+
+import mne
+
+from moabb import set_log_level
+from moabb.datasets import AlexMI
+
+
+set_log_level("info")
+
+
+
+

Basic usage#

+

Here, we will save the BIDS version of the dataset in a temporary folder

+
temp_dir = Path(tempfile.mkdtemp())
+# The conversion of any MOABB dataset to a BIDS-compliant structure can be done
+# by simply calling its ``get_data`` method and using the ``cache_config``
+# parameter. This parameter is a dictionary.
+dataset = AlexMI()
+_ = dataset.get_data(cache_config=dict(path=temp_dir, save_raw=True))
+
+
+
+
+

Before / after folder structure#

+

To investigate what was saved, we will first define a function to print +the folder structure of a given path:

+
def print_tree(p: Path, last=True, header=""):
+    elbow = "└──"
+    pipe = "│  "
+    tee = "├──"
+    blank = "   "
+    print(header + (elbow if last else tee) + p.name)
+    if p.is_dir():
+        children = list(p.iterdir())
+        for i, c in enumerate(children):
+            print_tree(
+                c, header=header + (blank if last else pipe), last=i == len(children) - 1
+            )
+
+
+

Now, we will retrieve the location of the original dataset. It is stored +in the MNE data directory, which can be found with the "MNE_DATA" key:

+
mne_data = Path(mne.get_config("MNE_DATA"))
+print(f"MNE data directory: {mne_data}")
+
+
+

Now, we can print the folder structure of the original dataset:

+
print("Before conversion:")
+print_tree(mne_data / "MNE-alexeeg-data")
+
+
+

As we can see, before conversion, all the data (i.e. from all subjects, +sessions and runs) is stored in a single folder. This follows no particular +standard and can vary from one dataset to another.

+

After conversion, the data is stored in a BIDS-compliant way:

+
print("After conversion:")
+print_tree(temp_dir / "MNE-BIDS-alexandre-motor-imagery")
+
+
+

In the BIDS version of our dataset, the raw files are saved in EDF. +The data is organized in a hierarchy of folders, +starting with the subjects, then the sessions, and then the runs. Metadata +files are stored to describe the data. For more details on the BIDS +structure, please refer to the BIDS website +and the BIDS spec.

+

Under the hood, saving datasets to BIDS is done through the caching system +of MOABB. Only raw EEG files are officially supported by the BIDS +specification. +However, MOABB’s caching mechanism also offers the possibility to save +the data in a pseudo-BIDS after different preprocessing steps. +In particular, we can save mne.Epochs and np.ndarray objects. +For more details on the caching system, +please refer to the tutorial Cache on disk intermediate data processing states.

+
+
+

Cleanup#

+

Finally, we can delete the temporary folder:

+
shutil.rmtree(temp_dir)
+
+
+
+
+

References#

+ +

Total running time of the script: ( 0 minutes 0.000 seconds)

+

Estimated memory usage: 0 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/noplot_phmd_ml_spectrum.html b/docs/auto_examples/noplot_phmd_ml_spectrum.html new file mode 100644 index 00000000..e9303554 --- /dev/null +++ b/docs/auto_examples/noplot_phmd_ml_spectrum.html @@ -0,0 +1,823 @@ + + + + + + + + + + + + Spectral analysis of the trials — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Spectral analysis of the trials#

+

This example demonstrates how to perform spectral +analysis on epochs extracted from a specific subject +within the moabb.datasets.Cattan2019_PHMD dataset.

+
# Authors: Pedro Rodrigues <pedro.rodrigues01@gmail.com>
+# Modified by: Gregoire Cattan <gcattan@hotmail.fr>
+# License: BSD (3-clause)
+
+import warnings
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+from moabb.datasets import Cattan2019_PHMD
+from moabb.paradigms import RestingStateToP300Adapter
+
+
+warnings.filterwarnings("ignore")
+
+
+
+

Initialization#

+
    +
  1. Specify the channel and subject to compute the power spectrum.

  2. +
  3. Create an instance of the moabb.datasets.Cattan2019_PHMD dataset.

  4. +
  5. Create an instance of the moabb.paradigms.RestingStateToP300Adapter paradigm. +By default, the data is filtered between 1-35 Hz, +and epochs are extracted from 10 to 50 seconds after event tagging.

  6. +
+
# Select channel and subject for the remaining of the example.
+channel = "Cz"
+subject = 1
+
+dataset = Cattan2019_PHMD()
+events = ["on", "off"]
+paradigm = RestingStateToP300Adapter(events=events, channels=[channel])
+
+
+
+
+

Estimate Power Spectral Density#

+
    +
  1. Obtain the epochs for the specified subject.

  2. +
  3. Use Welch’s method to estimate the power spectral density.

  4. +
+
f, S, _, y = paradigm.psd(subject, dataset)
+
+
+
+
+

Display of the data#

+

Plot the averaged Power Spectral Density (PSD) for each label condition, +using the selected channel specified at the beginning of the script.

+
fig, ax = plt.subplots(facecolor="white", figsize=(8.2, 5.1))
+for condition in events:
+    mean_power = np.mean(S[y == condition], axis=0).flatten()
+    ax.plot(f, 10 * np.log10(mean_power), label=condition)
+
+ax.set_xlim(paradigm.fmin, paradigm.fmax)
+ax.set_ylim(100, 135)
+ax.set_ylabel("Spectrum Magnitude (dB)", fontsize=14)
+ax.set_xlabel("Frequency (Hz)", fontsize=14)
+ax.set_title("PSD for Channel " + channel, fontsize=16)
+ax.legend()
+fig.show()
+
+
+

Total running time of the script: ( 0 minutes 0.000 seconds)

+

Estimated memory usage: 0 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/noplot_vr_pc_p300_different_epoch_size.html b/docs/auto_examples/noplot_vr_pc_p300_different_epoch_size.html new file mode 100644 index 00000000..b11adc2c --- /dev/null +++ b/docs/auto_examples/noplot_vr_pc_p300_different_epoch_size.html @@ -0,0 +1,897 @@ + + + + + + + + + + + + Changing epoch size in P300 VR dataset — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +

Example of P300 classification with different epoch size.

+
+

Changing epoch size in P300 VR dataset#

+

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.

+

This example demonstrates the use of get_block_repetition, which allows +to specify the experimental blocks and repetitions for analysis.

+
# Authors: Pedro Rodrigues <pedro.rodrigues01@gmail.com>
+# Modified by: Gregoire Cattan <gcattan@hotmail.fr>
+# License: BSD (3-clause)
+
+import warnings
+
+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 Cattan2019_VR
+from moabb.paradigms import P300
+
+
+warnings.filterwarnings("ignore")
+
+
+
+

Initialization#

+
    +
  1. Create an instance of the dataset.

  2. +
  3. 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.

  4. +
  5. Encode categorical variable (Target/NonTarget) to numerical values. +We will be using label encoding.

  6. +
+
dataset = Cattan2019_VR()
+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 Cattan2019_VR 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}")
+
+            # 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"
+
+            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)):
+                # 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
+                )
+
+                X_test, y_test, _ = dataset.get_block_repetition(
+                    paradigm, [subject], blocks[test_idx], repetitions
+                )
+
+                # We use riemannian geometry processing techniques 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
+            scores_subject.append(np.mean(auc))
+
+        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 length"
+)
+
+
+

Total running time of the script: ( 0 minutes 0.000 seconds)

+

Estimated memory usage: 0 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_benchmark.html b/docs/auto_examples/plot_benchmark.html new file mode 100644 index 00000000..a6bcb950 --- /dev/null +++ b/docs/auto_examples/plot_benchmark.html @@ -0,0 +1,1158 @@ + + + + + + + + + + + + Examples of how to use MOABB to benchmark pipelines. — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Examples of how to use MOABB to benchmark pipelines.#

+
+
+

Benchmarking with MOABB#

+

This example shows how to use MOABB to benchmark a set of pipelines +on all available datasets. For this example, we will use only one +dataset to keep the computation time low, but this benchmark is designed +to easily scale to many datasets.

+
# Authors: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>
+#
+# License: BSD (3-clause)
+
+import matplotlib.pyplot as plt
+
+from moabb import benchmark, set_log_level
+from moabb.analysis.plotting import score_plot
+from moabb.paradigms import LeftRightImagery
+
+
+set_log_level("info")
+
+
+
+

Loading the pipelines#

+

The ML pipelines used in benchmark are defined in YAML files, following a +simple format. It simplifies sharing and reusing pipelines across benchmarks, +reproducing state-of-the-art results.

+

MOABB comes with complete list of pipelines that cover most of the successful +approaches in the literature. You can find them in the +pipelines folder. +For this example, we will use a folder with only 2 pipelines, to keep the +computation time low.

+

This is an example of a pipeline defined in YAML, defining on which paradigms it +can be used, the original publication, and the steps to perform using a +scikit-learn API. In this case, a CSP + SVM pipeline, the covariance are estimated +to compute a CSP filter and then a linear SVM is trained on the CSP filtered +signals.

+
with open("sample_pipelines/CSP_SVM.yml", "r") as f:
+    lines = f.readlines()
+    for line in lines:
+        print(line, end="")
+
+
+
name: CSP + SVM
+paradigms:
+  - LeftRightImagery
+
+citations:
+  - https://doi.org/10.1007/BF01129656
+  - https://doi.org/10.1109/MSP.2008.4408441
+
+pipeline:
+  - name: Covariances
+    from: pyriemann.estimation
+    parameters:
+      estimator: oas
+
+  - name: CSP
+    from: pyriemann.spatialfilters
+    parameters:
+      nfilter: 6
+
+  - name: SVC
+    from: sklearn.svm
+    parameters:
+      kernel: "linear"
+
+
+

The sample_pipelines folder contains a second pipeline, a logistic regression +performed in the tangent space using Riemannian geometry.

+
+
+

Selecting the datasets (optional)#

+

If you want to limit your benchmark on a subset of datasets, you can use the +include_datasets and exclude_datasets arguments. You will need either +to provide the dataset’s object, or a the dataset’s code. To get the list of +available dataset’s code for a given paradigm, you can use the following command:

+ +
/home/runner/work/moabb/moabb/moabb/datasets/fake.py:93: RuntimeWarning: Setting non-standard config type: "MNE_DATASETS_FAKEDATASET-IMAGERY-10-2--60-60--120-120--FAKE1-FAKE2-FAKE3--C3-CZ-C4_PATH"
+  set_config(key, temp_dir)
+/home/runner/work/moabb/moabb/moabb/datasets/fake.py:93: RuntimeWarning: Setting non-standard config type: "MNE_DATASETS_FAKEVIRTUALREALITYDATASET-P300-21-1--60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60-60--120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120-120--TARGET-NONTARGET--C3-CZ-C4_PATH"
+  set_config(key, temp_dir)
+BNCI2014-001
+BNCI2014-004
+Cho2017
+GrosseWentrup2009
+Lee2019-MI
+PhysionetMotorImagery
+Schirrmeister2017
+Shin2017A
+Weibo2014
+Zhou2016
+
+
+

In this example, we will use only the last dataset, ‘Zhou 2016’.

+
+
+

Running the benchmark#

+

The benchmark is run using the benchmark function. You need to specify the +folder containing the pipelines to use, the kind of evaluation and the paradigm +to use. By default, the benchmark will use all available datasets for all +paradigms listed in the pipelines. You could restrict to specific evaluation and +paradigm using the evaluations and paradigms arguments.

+

To save computation time, the results are cached. If you want to re-run the +benchmark, you can set the overwrite argument to True.

+

It is possible to indicate the folder to cache the results and the one to save +the analysis & figures. By default, the results are saved in the results +folder, and the analysis & figures are saved in the benchmark folder.

+
results = benchmark(
+    pipelines="./sample_pipelines/",
+    evaluations=["WithinSession"],
+    paradigms=["LeftRightImagery"],
+    include_datasets=["Zhou2016"],
+    results="./results/",
+    overwrite=False,
+    plot=False,
+    output="./benchmark/",
+)
+
+
+
2024-04-18 14:42:47,545 INFO MainThread moabb.evaluations.base Processing dataset: Zhou2016
+
+Zhou2016-WithinSession:   0%|          | 0/4 [00:00<?, ?it/s]MNE_DATA is not already configured. It will be set to default location in the home directory - /home/runner/mne_data
+All datasets will be downloaded to this location, if anything is already downloaded, please move manually to this location
+/home/runner/work/moabb/moabb/moabb/datasets/download.py:55: RuntimeWarning: Setting non-standard config type: "MNE_DATASETS_ZHOU_PATH"
+  set_config(key, get_config("MNE_DATA"))
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  60 events (all good), 0 – 5 s, baseline off, ~8.0 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 30>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  59 events (all good), 0 – 5 s, baseline off, ~7.9 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 29>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+2024-04-18 14:42:51,361 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 1 | 0: Score 0.860
+2024-04-18 14:42:51,863 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 1 | 0: Score 0.909
+2024-04-18 14:42:52,268 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 1 | 1: Score 0.924
+2024-04-18 14:42:52,718 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 1 | 1: Score 0.926
+2024-04-18 14:42:53,110 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 1 | 2: Score 0.954
+2024-04-18 14:42:53,553 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 1 | 2: Score 0.964
+
+Zhou2016-WithinSession:  25%|##5       | 1/4 [00:06<00:18,  6.13s/it]/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  40 events (all good), 0 – 5 s, baseline off, ~5.4 MB, data loaded,
+ 'left_hand': 20
+ 'right_hand': 20>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+2024-04-18 14:42:55,852 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 2 | 0: Score 0.916
+2024-04-18 14:42:56,315 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 2 | 0: Score 0.910
+2024-04-18 14:42:56,692 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 2 | 1: Score 0.753
+2024-04-18 14:42:57,123 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 2 | 1: Score 0.765
+2024-04-18 14:42:57,514 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 2 | 2: Score 0.906
+2024-04-18 14:42:57,953 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 2 | 2: Score 0.904
+
+Zhou2016-WithinSession:  50%|#####     | 2/4 [00:10<00:10,  5.11s/it]/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+2024-04-18 14:43:00,455 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 3 | 0: Score 0.972
+2024-04-18 14:43:00,897 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 3 | 0: Score 0.994
+2024-04-18 14:43:01,289 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 3 | 1: Score 0.980
+2024-04-18 14:43:01,739 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 3 | 1: Score 0.990
+2024-04-18 14:43:02,130 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 3 | 2: Score 0.990
+2024-04-18 14:43:02,579 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 3 | 2: Score 0.992
+
+Zhou2016-WithinSession:  75%|#######5  | 3/4 [00:15<00:04,  4.89s/it]/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning:   Could not parse meas date from the header. Setting to None.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/Zhou2016.py:111: RuntimeWarning: Could not define the number of bytes automatically. Defaulting to 2.
+  raw = read_raw_cnt(fname, preload=True, eog=["VEOU", "VEOL"])
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  40 events (all good), 0 – 5 s, baseline off, ~5.4 MB, data loaded,
+ 'left_hand': 20
+ 'right_hand': 20>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+2024-04-18 14:43:04,857 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 4 | 0: Score 0.993
+2024-04-18 14:43:05,276 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 4 | 0: Score 0.995
+2024-04-18 14:43:05,676 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 4 | 1: Score 0.972
+2024-04-18 14:43:06,131 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 4 | 1: Score 0.972
+2024-04-18 14:43:06,526 INFO MainThread moabb.evaluations.base CSP + SVM | Zhou2016 | 4 | 2: Score 0.968
+2024-04-18 14:43:06,968 INFO MainThread moabb.evaluations.base Tangent Space LR | Zhou2016 | 4 | 2: Score 0.978
+
+Zhou2016-WithinSession: 100%|##########| 4/4 [00:19<00:00,  4.69s/it]
+Zhou2016-WithinSession: 100%|##########| 4/4 [00:19<00:00,  4.89s/it]
+    dataset     evaluation          pipeline  avg score
+0  Zhou2016  WithinSession         CSP + SVM   0.932315
+1  Zhou2016  WithinSession  Tangent Space LR   0.941601
+
+
+

Benchmark prints a summary of the results. Detailed results are saved in a +pandas dataframe, and can be used to generate figures. The analysis & figures +are saved in the benchmark folder.

+
score_plot(results)
+plt.show()
+
+
+Scores per dataset and algorithm
2024-04-18 14:43:07,464 WARNING MainThread moabb.analysis.plotting Dataset names are too similar, turning off name shortening
+/home/runner/work/moabb/moabb/moabb/analysis/plotting.py:70: UserWarning: The palette list has more values (6) than needed (2), which may not be intended.
+  sea.stripplot(
+
+
+

Total running time of the script: ( 0 minutes 20.819 seconds)

+

Estimated memory usage: 352 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_benchmark_DL.html b/docs/auto_examples/plot_benchmark_DL.html new file mode 100644 index 00000000..8d32d976 --- /dev/null +++ b/docs/auto_examples/plot_benchmark_DL.html @@ -0,0 +1,1486 @@ + + + + + + + + + + + + Benchmarking on MOABB with Tensorflow deep net architectures — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Benchmarking on MOABB with Tensorflow deep net architectures#

+

This example shows how to use MOABB to benchmark a set of Deep Learning pipeline (Tensorflow) +on all available datasets. +For this example, we will use only one dataset to keep the computation time low, but this benchmark is designed +to easily scale to many datasets.

+
# Authors: Igor Carrara <igor.carrara@inria.fr>
+#
+# License: BSD (3-clause)
+
+import os
+
+import matplotlib.pyplot as plt
+import tensorflow as tf
+from absl.logging import ERROR, set_verbosity
+from tensorflow import keras
+
+from moabb import benchmark, set_log_level
+from moabb.analysis.plotting import score_plot
+from moabb.datasets import BNCI2014_001
+from moabb.utils import setup_seed
+
+
+set_log_level("info")
+# Avoid output Warning
+set_verbosity(ERROR)
+os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
+
+# Print Information Tensorflow
+print(f"Tensorflow Version: {tf.__version__}")
+print(f"Keras Version: {keras.__version__}")
+
+CPU = len(tf.config.list_physical_devices("CPU")) > 0
+print("CPU is", "AVAILABLE" if CPU else "NOT AVAILABLE")
+
+GPU = len(tf.config.list_physical_devices("GPU")) > 0
+print("GPU is", "AVAILABLE" if GPU else "NOT AVAILABLE")
+
+
+
Tensorflow Version: 2.11.1
+Keras Version: 2.11.0
+CPU is AVAILABLE
+GPU is NOT AVAILABLE
+
+
+

In this example, we will use only the dataset BNCI2014_001.

+
+

Running the benchmark#

+

The benchmark is run using the benchmark function. You need to specify the +folder containing the pipelines to use, the kind of evaluation and the paradigm +to use. By default, the benchmark will use all available datasets for all +paradigms listed in the pipelines. You could restrict to specific evaluation and +paradigm using the evaluations and paradigms arguments.

+

To save computation time, the results are cached. If you want to re-run the +benchmark, you can set the overwrite argument to True.

+

It is possible to indicate the folder to cache the results and the one to save +the analysis & figures. By default, the results are saved in the results +folder, and the analysis & figures are saved in the benchmark folder.

+

This code is implemented to run on CPU. If you’re using a GPU, do not use multithreading +(i.e. set n_jobs=1)

+
# Set up reproducibility of Tensorflow
+setup_seed(42)
+
+# Restrict this example only on the first two subject of BNCI2014_001
+dataset = BNCI2014_001()
+dataset.subject_list = dataset.subject_list[:2]
+datasets = [dataset]
+
+results = benchmark(
+    pipelines="./pipelines_DL",
+    evaluations=["WithinSession"],
+    paradigms=["LeftRightImagery"],
+    include_datasets=datasets,
+    results="./results/",
+    overwrite=False,
+    plot=False,
+    output="./benchmark/",
+    n_jobs=-1,
+)
+
+
+
BNCI2014-001-WithinSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/download.py:55: RuntimeWarning: Setting non-standard config type: "MNE_DATASETS_BNCI_PATH"
+  set_config(key, get_config("MNE_DATA"))
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/paradigms/base.py:355: RuntimeWarning: Concatenation of Annotations within Epochs is not supported yet. All annotations will be dropped.
+  X = mne.concatenate_epochs(X)
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+
+BNCI2014-001-WithinSession:  50%|#####     | 1/2 [04:27<04:27, 267.40s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/paradigms/base.py:355: RuntimeWarning: Concatenation of Annotations within Epochs is not supported yet. All annotations will be dropped.
+  X = mne.concatenate_epochs(X)
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+/home/runner/work/moabb/moabb/moabb/pipelines/features.py:160: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return X.get_data()
+
+BNCI2014-001-WithinSession: 100%|##########| 2/2 [09:01<00:00, 271.58s/it]
+BNCI2014-001-WithinSession: 100%|##########| 2/2 [09:01<00:00, 270.95s/it]
+        dataset     evaluation              pipeline  avg score
+0  BNCI2014-001  WithinSession        Keras_EEGITNet   0.583231
+1  BNCI2014-001  WithinSession        Keras_EEGTCNet   0.499898
+2  BNCI2014-001  WithinSession          Keras_EEGNeX   0.569677
+3  BNCI2014-001  WithinSession      Keras_EEGNet_8_2   0.517636
+4  BNCI2014-001  WithinSession     Keras_DeepConvNet   0.521548
+5  BNCI2014-001  WithinSession  Keras_ShallowConvNet   0.619575
+
+
+

The deep learning architectures implemented in MOABB are: +- Shallow Convolutional Network [1] +- Deep Convolutional Network [1] +- EEGNet [2] +- EEGTCNet [3] +- EEGNex [4] +- EEGITNet [5]

+

Benchmark prints a summary of the results. Detailed results are saved in a +pandas dataframe, and can be used to generate figures. The analysis & figures +are saved in the benchmark folder.

+
score_plot(results)
+plt.show()
+
+
+Scores per dataset and algorithm
+
+

References#

+ +

Total running time of the script: ( 9 minutes 3.512 seconds)

+

Estimated memory usage: 996 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_benchmark_braindecode.html b/docs/auto_examples/plot_benchmark_braindecode.html new file mode 100644 index 00000000..9af3b796 --- /dev/null +++ b/docs/auto_examples/plot_benchmark_braindecode.html @@ -0,0 +1,1456 @@ + + + + + + + + + + + + Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures#

+

This example shows how to use MOABB to benchmark a set of Braindecode pipelines (deep learning +architectures) on all available datasets. +For this example, we will use only 2 datasets to keep the computation time low, but this benchmark is designed +to easily scale to many datasets.

+
# Authors: Igor Carrara <igor.carrara@inria.fr>
+#          Bruno Aristimunha <b.aristimunha@gmail.com>
+#          Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>
+#
+# License: BSD (3-clause)
+
+import os
+
+import matplotlib.pyplot as plt
+import torch
+from absl.logging import ERROR, set_verbosity
+
+from moabb import benchmark, set_log_level
+from moabb.analysis.plotting import score_plot
+from moabb.datasets import BNCI2014_001, BNCI2014_004
+from moabb.utils import setup_seed
+
+
+set_log_level("info")
+# Avoid output Warning
+set_verbosity(ERROR)
+os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
+
+# Print Information PyTorch
+print(f"Torch Version: {torch.__version__}")
+
+# Set up GPU if it is there
+cuda = torch.cuda.is_available()
+device = "cuda" if cuda else "cpu"
+print("GPU is", "AVAILABLE" if cuda else "NOT AVAILABLE")
+
+
+
Torch Version: 1.13.1+cu117
+GPU is NOT AVAILABLE
+
+
+

In this example, we will use only 2 subjects from the dataset BNCI2014_001 and BNCI2014_004.

+
+

Running the benchmark#

+

The benchmark is run using the benchmark function. You need to specify the +folder containing the pipelines, the kind of evaluation, and the paradigm +to use. By default, the benchmark will use all available datasets for all +paradigms listed in the pipelines. You could restrict to specific evaluation and +paradigm using the evaluations and paradigms arguments.

+

To save computation time, the results are cached. If you want to re-run the +benchmark, you can set the overwrite argument to True.

+

It is possible to indicate the folder to cache the results and the one to save +the analysis & figures. By default, the results are saved in the results +folder, and the analysis & figures are saved in the benchmark folder.

+

This code is implemented to run on CPU. If you’re using a GPU, do not use multithreading +(i.e. set n_jobs=1)

+

In order to allow the benchmark function to work with return_epoch=True (Required to use Braindecode( +we need to call each pipeline as “braindecode_xxx…”, with xxx the name of the model to be +handled correctly by the benchmark function.

+
# Set up reproducibility of Tensorflow
+setup_seed(42)
+
+# Restrict this example only to the first two subjects of BNCI2014_001
+dataset = BNCI2014_001()
+dataset2 = BNCI2014_004()
+dataset.subject_list = dataset.subject_list[:2]
+dataset2.subject_list = dataset2.subject_list[:2]
+datasets = [dataset, dataset2]
+
+results = benchmark(
+    pipelines="./pipelines_braindecode",
+    evaluations=["CrossSession"],
+    paradigms=["LeftRightImagery"],
+    include_datasets=datasets,
+    results="./results/",
+    overwrite=False,
+    plot=False,
+    output="./benchmark/",
+    n_jobs=-1,
+)
+
+
+
BNCI2014-001-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/paradigms/base.py:355: RuntimeWarning: Concatenation of Annotations within Epochs is not supported yet. All annotations will be dropped.
+  X = mne.concatenate_epochs(X)
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5625        0.7963       0.4828        0.7777  0.3289
+      2       0.5156        0.9597       0.4828        0.7741  0.2913
+      3       0.4844        0.8870       0.4828        0.7706  0.2847
+      4       0.5625        0.7234       0.4828        0.7670  0.2986
+      5       0.4531        0.9164       0.4828        0.7637  0.2815
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5312        0.9508       0.4483        0.8963  0.2877
+      2       0.4062        0.9827       0.4828        0.8552  0.2886
+      3       0.4531        0.8892       0.4483        0.8198  0.2824
+      4       0.5000        0.8186       0.4828        0.7930  0.2816
+      5       0.5781        0.7252       0.5172        0.7710  0.2898
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/torch/nn/modules/conv.py:459: UserWarning: Using padding='same' with even kernel lengths and odd dilation may require a zero-padded copy of the input be created (Triggered internally at ../aten/src/ATen/native/Convolution.cpp:895.)
+  return F.conv2d(input, weight, bias, self.stride,
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5938        0.9143       0.4483        0.6988  0.6026
+      2       0.4219        1.0801       0.4483        0.6990  0.5695
+      3       0.4688        1.1433       0.4483        0.6992  0.5854
+Stopping since valid_loss has not improved in the last 3 epochs.
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4375        1.0006       0.5862        0.6848  0.5691
+      2       0.5625        0.9168       0.5862        0.6847  0.5687
+      3       0.4375        0.9807       0.5862        0.6847  0.5680
+      4       0.5000        0.9120       0.5517        0.6848  0.5803
+Stopping since valid_loss has not improved in the last 3 epochs.
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5312        0.6886       0.4828        0.6959  0.0957
+      2       0.5312        0.6834       0.4828        0.6959  0.0929
+      3       0.4688        0.7498       0.4828        0.6959  0.0904
+Stopping since valid_loss has not improved in the last 3 epochs.
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5312        0.7524       0.5172        0.6968  0.0911
+      2       0.4844        0.7341       0.5172        0.6968  0.0901
+      3       0.5625        0.6984       0.5517        0.6967  0.1030
+      4       0.4688        0.7200       0.5517        0.6967  0.0900
+      5       0.3750        0.7751       0.5517        0.6967  0.0897
+Stopping since valid_loss has not improved in the last 3 epochs.
+
+BNCI2014-001-CrossSession:  50%|#####     | 1/2 [00:16<00:16, 16.66s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/paradigms/base.py:355: RuntimeWarning: Concatenation of Annotations within Epochs is not supported yet. All annotations will be dropped.
+  X = mne.concatenate_epochs(X)
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4844        1.1032       0.4483        0.8907  0.2792
+      2       0.5156        1.2419       0.4483        0.9051  0.2806
+      3       0.4062        1.2040       0.4828        0.9284  0.2770
+Stopping since valid_loss has not improved in the last 3 epochs.
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4844        0.9918       0.5517        0.7643  0.2766
+      2       0.5156        1.0123       0.5517        0.7699  0.2815
+      3       0.5312        0.8275       0.5517        0.7746  0.2780
+Stopping since valid_loss has not improved in the last 3 epochs.
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.3906        0.9882       0.4828        0.7055  0.5708
+      2       0.4219        1.0244       0.4483        0.7052  0.5534
+      3       0.4531        0.8173       0.4483        0.7051  0.5517
+      4       0.6719        0.7267       0.4483        0.7052  0.5526
+      5       0.5156        0.7883       0.4483        0.7051  0.5652
+      6       0.5000        0.8663       0.4483        0.7050  0.5687
+      7       0.6250        0.7473       0.4483        0.7050  0.5671
+      8       0.4062        1.0788       0.4483        0.7049  0.5506
+      9       0.6250        0.7372       0.4483        0.7047  0.5509
+     10       0.6406        0.7057       0.4483        0.7046  0.5478
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5000        0.9530       0.4138        0.7191  0.5642
+      2       0.4531        0.9635       0.4138        0.7196  0.5586
+      3       0.4375        1.0339       0.4483        0.7200  0.5706
+Stopping since valid_loss has not improved in the last 3 epochs.
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5469        0.6845       0.5517        0.7019  0.0886
+      2       0.5938        0.6805       0.5172        0.7011  0.0885
+      3       0.4844        0.7353       0.5172        0.7003  0.0885
+      4       0.5469        0.7266       0.5172        0.6996  0.0890
+      5       0.5312        0.7256       0.5172        0.6990  0.0915
+      6       0.4375        0.7298       0.5172        0.6985  0.0886
+      7       0.5000        0.7288       0.5172        0.6982  0.0885
+      8       0.4375        0.7391       0.5172        0.6978  0.0890
+      9       0.6250        0.6962       0.5172        0.6977  0.1010
+     10       0.5469        0.6834       0.4828        0.6975  0.0908
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5938        0.6919       0.7241        0.6898  0.0883
+      2       0.4062        0.7714       0.7241        0.6897  0.0882
+      3       0.5469        0.6963       0.7241        0.6897  0.0881
+      4       0.4375        0.7377       0.7241        0.6896  0.0880
+      5       0.5000        0.7363       0.6897        0.6896  0.0887
+      6       0.5156        0.7001       0.6897        0.6896  0.0885
+      7       0.5156        0.7378       0.6897        0.6895  0.0882
+      8       0.4531        0.7472       0.6552        0.6895  0.0884
+      9       0.4688        0.7408       0.6552        0.6894  0.0883
+     10       0.5938        0.6808       0.6552        0.6894  0.0963
+
+BNCI2014-001-CrossSession: 100%|##########| 2/2 [00:35<00:00, 18.18s/it]
+BNCI2014-001-CrossSession: 100%|##########| 2/2 [00:35<00:00, 17.95s/it]
+
+BNCI2014-004-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  120 events (all good), 3 – 7.5 s, baseline off, ~3.1 MB, data loaded,
+ 'left_hand': 60
+ 'right_hand': 60>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  120 events (all good), 3 – 7.5 s, baseline off, ~3.1 MB, data loaded,
+ 'left_hand': 60
+ 'right_hand': 60>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  160 events (all good), 3 – 7.5 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 80
+ 'right_hand': 80>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  160 events (all good), 3 – 7.5 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 80
+ 'right_hand': 80>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  160 events (all good), 3 – 7.5 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 80
+ 'right_hand': 80>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/paradigms/base.py:355: RuntimeWarning: Concatenation of Annotations within Epochs is not supported yet. All annotations will be dropped.
+  X = mne.concatenate_epochs(X)
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5000        0.9412       0.5333        0.7847  0.7594
+      2       0.5335        0.8727       0.5500        0.7416  0.7642
+      3       0.5737        0.8113       0.6167        0.7199  0.7664
+      4       0.5759        0.8205       0.6083        0.6926  0.7703
+      5       0.5781        0.7918       0.6167        0.6812  0.7616
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4911        0.9524       0.4500        0.8850  0.7658
+      2       0.5513        0.8934       0.5167        0.9415  0.7567
+      3       0.5536        0.7919       0.5083        0.8066  0.7593
+      4       0.6027        0.7941       0.5750        0.7251  0.7494
+      5       0.5781        0.8269       0.5917        0.6804  0.7643
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4375        1.0705       0.4821        0.9701  0.7582
+      2       0.4866        0.9521       0.5357        0.7768  0.7647
+      3       0.5022        0.9376       0.5714        0.7491  0.7575
+      4       0.5268        0.8963       0.5714        0.7131  0.7483
+      5       0.5067        0.9043       0.5714        0.6777  0.7632
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4688        0.9724       0.4554        1.0812  0.7603
+      2       0.4866        0.9542       0.4732        1.0143  0.7495
+      3       0.5312        0.8730       0.4554        0.8869  0.7498
+      4       0.5379        0.8111       0.5268        0.7505  0.7631
+      5       0.6071        0.7723       0.6161        0.6848  0.8119
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4866        0.9824       0.5357        0.8263  0.7640
+      2       0.5201        0.8853       0.5446        0.7731  0.7575
+      3       0.5446        0.8878       0.5357        0.7244  0.7493
+      4       0.6183        0.7720       0.5804        0.6973  0.7621
+      5       0.5625        0.7895       0.6071        0.6804  0.7561
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4888        0.9862       0.4167        0.7044  1.0668
+      2       0.4933        0.9458       0.5167        0.6997  1.0587
+      3       0.5223        0.9007       0.5333        0.6956  1.0566
+      4       0.5022        0.8895       0.5417        0.6919  1.0588
+      5       0.5067        0.8896       0.5417        0.6886  1.0523
+      6       0.4754        1.0003       0.5417        0.6855  1.0551
+      7       0.5000        0.9454       0.5750        0.6824  1.0513
+      8       0.5268        0.8909       0.5750        0.6796  1.0576
+      9       0.5089        0.8969       0.6000        0.6771  1.0559
+     10       0.4844        0.9135       0.6083        0.6750  1.0518
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5000        1.0360       0.4500        0.7294  1.0609
+      2       0.5000        0.9948       0.4083        0.7211  1.0557
+      3       0.4978        1.0685       0.3083        0.7159  1.0566
+      4       0.4710        1.0047       0.4250        0.7137  1.0481
+      5       0.4576        1.0780       0.5167        0.7134  1.0867
+      6       0.4509        1.0808       0.5083        0.7148  1.0493
+      7       0.4978        1.0492       0.5333        0.7170  1.0534
+Stopping since valid_loss has not improved in the last 3 epochs.
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4754        0.9803       0.5000        0.6897  1.0641
+      2       0.4621        1.0309       0.5089        0.6886  1.0644
+      3       0.5379        0.9047       0.5089        0.6874  1.0559
+      4       0.5179        0.9489       0.5268        0.6862  1.0493
+      5       0.4955        0.9089       0.5268        0.6851  1.0524
+      6       0.4777        0.9684       0.5536        0.6838  1.0460
+      7       0.4955        1.0081       0.5536        0.6823  1.0524
+      8       0.5179        0.9537       0.5536        0.6809  1.0828
+      9       0.4955        0.9676       0.5625        0.6793  1.0421
+     10       0.4621        1.0062       0.5625        0.6775  1.0502
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5379        0.8202       0.5446        0.6786  1.0581
+      2       0.5201        0.9291       0.5446        0.6790  1.0485
+      3       0.5022        0.8798       0.5446        0.6799  1.0450
+Stopping since valid_loss has not improved in the last 3 epochs.
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5112        0.9420       0.4107        0.7095  1.0523
+      2       0.4665        0.9857       0.4107        0.7093  1.0515
+      3       0.5647        0.8255       0.4375        0.7089  1.0493
+      4       0.4933        0.9507       0.4464        0.7084  1.0518
+      5       0.5089        0.9066       0.4464        0.7081  1.0445
+      6       0.5067        0.9766       0.4286        0.7079  1.0464
+      7       0.5246        0.9010       0.4107        0.7078  1.0450
+      8       0.5312        0.9108       0.4107        0.7076  1.0477
+      9       0.4688        0.9700       0.3929        0.7073  1.0593
+     10       0.4777        0.9619       0.4018        0.7067  1.0533
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4754        0.7894       0.4667        0.6935  0.2001
+      2       0.5022        0.7780       0.4750        0.6936  0.1877
+      3       0.4598        0.7743       0.5000        0.6937  0.1879
+Stopping since valid_loss has not improved in the last 3 epochs.
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4955        0.7396       0.4917        0.6933  0.1917
+      2       0.4464        0.7537       0.4833        0.6933  0.1921
+      3       0.5112        0.7361       0.4833        0.6933  0.1901
+      4       0.5156        0.7248       0.4667        0.6932  0.1878
+      5       0.4621        0.7457       0.4833        0.6931  0.1997
+      6       0.4888        0.7283       0.4917        0.6930  0.1905
+      7       0.4732        0.7365       0.5250        0.6928  0.1907
+      8       0.4531        0.7461       0.5167        0.6927  0.1901
+      9       0.4821        0.7176       0.5333        0.6925  0.1896
+     10       0.5156        0.7074       0.5417        0.6924  0.1956
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4978        0.7155       0.5179        0.6923  0.1899
+      2       0.4911        0.7209       0.5536        0.6921  0.1894
+      3       0.5223        0.7165       0.5893        0.6920  0.1893
+      4       0.5469        0.7056       0.5714        0.6919  0.1980
+      5       0.4464        0.7321       0.5446        0.6917  0.1894
+      6       0.5112        0.7238       0.5357        0.6916  0.1885
+      7       0.5067        0.7045       0.5714        0.6914  0.1894
+      8       0.5156        0.7187       0.5714        0.6912  0.1874
+      9       0.5491        0.7017       0.5804        0.6910  0.1991
+     10       0.5223        0.7005       0.5804        0.6909  0.1893
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4955        0.7409       0.4554        0.6935  0.1924
+      2       0.5045        0.7237       0.4375        0.6935  0.1967
+      3       0.5089        0.7291       0.4464        0.6935  0.1856
+Stopping since valid_loss has not improved in the last 3 epochs.
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4888        0.7749       0.4375        0.6947  0.2022
+      2       0.5045        0.7734       0.4732        0.6943  0.1885
+      3       0.4643        0.7679       0.4732        0.6940  0.1891
+      4       0.4710        0.7534       0.5000        0.6937  0.1865
+      5       0.4933        0.7502       0.5179        0.6934  0.1868
+      6       0.4866        0.7324       0.5268        0.6931  0.1864
+      7       0.5067        0.7374       0.5625        0.6928  0.1967
+      8       0.4911        0.7315       0.5446        0.6925  0.1851
+      9       0.5000        0.7234       0.5536        0.6922  0.1859
+     10       0.4866        0.7206       0.5536        0.6919  0.1861
+
+BNCI2014-004-CrossSession:  50%|#####     | 1/2 [01:17<01:17, 77.33s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  120 events (all good), 3 – 7.5 s, baseline off, ~3.1 MB, data loaded,
+ 'left_hand': 60
+ 'right_hand': 60>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  120 events (all good), 3 – 7.5 s, baseline off, ~3.1 MB, data loaded,
+ 'left_hand': 60
+ 'right_hand': 60>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  160 events (all good), 3 – 7.5 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 80
+ 'right_hand': 80>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  120 events (all good), 3 – 7.5 s, baseline off, ~3.1 MB, data loaded,
+ 'left_hand': 60
+ 'right_hand': 60>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  160 events (all good), 3 – 7.5 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 80
+ 'right_hand': 80>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/paradigms/base.py:355: RuntimeWarning: Concatenation of Annotations within Epochs is not supported yet. All annotations will be dropped.
+  X = mne.concatenate_epochs(X)
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4576        0.9212       0.4375        1.1639  0.7525
+      2       0.5022        0.8720       0.4821        0.7823  0.7507
+      3       0.5335        0.8371       0.5089        0.7264  0.7602
+      4       0.4911        0.8292       0.5714        0.7198  0.7742
+      5       0.5268        0.8260       0.5536        0.7208  0.7589
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4955        0.9150       0.3929        1.2350  0.7655
+      2       0.4754        0.9059       0.4643        0.7855  0.7651
+      3       0.5446        0.8017       0.5536        0.7591  0.7626
+      4       0.5268        0.7990       0.5714        0.7518  0.7547
+      5       0.5379        0.7903       0.5446        0.7513  0.7653
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5078        0.9001       0.4904        1.2544  0.6607
+      2       0.5130        0.8694       0.5000        0.8166  0.6558
+      3       0.5417        0.8114       0.5288        0.7452  0.6476
+      4       0.5469        0.7868       0.5481        0.7339  0.6540
+      5       0.5651        0.7777       0.5385        0.7282  0.6464
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4442        0.9124       0.5804        1.2664  0.7575
+      2       0.5067        0.8408       0.5893        0.9500  0.7614
+      3       0.4821        0.8736       0.5714        0.7983  0.7596
+      4       0.5201        0.8417       0.5714        0.7416  0.7571
+      5       0.4933        0.8451       0.5179        0.7253  0.7493
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5286        0.8927       0.4327        0.9024  0.6672
+      2       0.4922        0.9043       0.5000        0.9090  0.6508
+      3       0.5234        0.8309       0.4904        0.9290  0.6442
+      4       0.4922        0.8563       0.5096        0.8682  0.6592
+      5       0.5286        0.8604       0.5192        0.7945  0.6484
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5067        0.9233       0.4911        0.6927  1.0451
+      2       0.4866        0.9082       0.4911        0.6967  1.0446
+      3       0.4978        0.9327       0.4196        0.7006  1.0472
+Stopping since valid_loss has not improved in the last 3 epochs.
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5000        0.9779       0.4643        0.6946  1.0581
+      2       0.4799        1.0024       0.5000        0.6943  1.0564
+      3       0.4576        1.0652       0.5179        0.6937  1.0578
+      4       0.4799        1.0139       0.5357        0.6934  1.0541
+      5       0.5112        0.9484       0.5268        0.6934  1.0537
+      6       0.5067        0.9618       0.5357        0.6934  1.0519
+Stopping since valid_loss has not improved in the last 3 epochs.
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4844        0.9147       0.4519        0.6934  0.9077
+      2       0.4740        0.9491       0.4519        0.6932  0.9077
+      3       0.5260        0.8936       0.5096        0.6933  0.9069
+      4       0.4766        0.9165       0.4904        0.6936  0.9059
+Stopping since valid_loss has not improved in the last 3 epochs.
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4911        0.9356       0.4018        0.7045  1.0479
+      2       0.4844        1.0194       0.3750        0.7040  1.0444
+      3       0.5067        0.9080       0.3482        0.7033  1.0452
+      4       0.5312        0.8844       0.3839        0.7028  1.0493
+      5       0.5223        0.9085       0.4196        0.7021  1.0495
+      6       0.4933        0.8773       0.4554        0.7016  1.0488
+      7       0.5067        0.9077       0.4286        0.7010  1.0628
+      8       0.5089        0.8976       0.4643        0.7006  1.0610
+      9       0.4799        0.9441       0.4821        0.7003  1.0582
+     10       0.4821        0.9229       0.4732        0.6999  1.0490
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/braindecode/models/base.py:180: UserWarning: LogSoftmax final layer will be removed! Please adjust your loss function accordingly (e.g. CrossEntropyLoss)!
+  warnings.warn("LogSoftmax final layer will be removed! " +
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4792        0.9699       0.5096        0.6884  0.9182
+      2       0.5260        0.9294       0.5481        0.6878  0.9062
+      3       0.4922        0.9464       0.5673        0.6874  0.9093
+      4       0.5260        0.8568       0.5865        0.6870  0.9119
+      5       0.5078        0.9270       0.5577        0.6867  0.9131
+      6       0.4974        0.9287       0.5865        0.6864  0.9078
+      7       0.4714        0.9542       0.5769        0.6861  0.9123
+      8       0.5182        0.8983       0.5769        0.6857  0.9147
+      9       0.4948        0.9354       0.5962        0.6854  0.9079
+     10       0.4609        0.9492       0.5962        0.6852  0.8993
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5179        0.7209       0.5268        0.6928  0.1947
+      2       0.5290        0.7116       0.4464        0.6937  0.1931
+      3       0.4978        0.7059       0.4286        0.6947  0.2039
+Stopping since valid_loss has not improved in the last 3 epochs.
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4866        0.7080       0.5089        0.6927  0.1961
+      2       0.5737        0.7016       0.5804        0.6916  0.1932
+      3       0.5156        0.7296       0.6071        0.6906  0.2034
+      4       0.5290        0.7251       0.6071        0.6897  0.1939
+      5       0.5379        0.7288       0.6071        0.6888  0.1934
+      6       0.5290        0.7088       0.6071        0.6881  0.1927
+      7       0.5223        0.7038       0.6071        0.6874  0.1898
+      8       0.5134        0.7170       0.6071        0.6866  0.2013
+      9       0.5357        0.7024       0.6071        0.6860  0.1923
+     10       0.5312        0.6996       0.6071        0.6854  0.1918
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5312        0.7613       0.5000        0.6930  0.1761
+      2       0.4870        0.7672       0.5000        0.6929  0.1667
+      3       0.4948        0.7538       0.5096        0.6929  0.1676
+Stopping since valid_loss has not improved in the last 3 epochs.
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5045        0.7197       0.4375        0.6944  0.2031
+      2       0.4710        0.7331       0.4464        0.6943  0.1905
+      3       0.4821        0.7176       0.4286        0.6943  0.1905
+      4       0.4866        0.7136       0.4464        0.6942  0.1914
+      5       0.4621        0.7352       0.4286        0.6941  0.1916
+      6       0.5134        0.7145       0.4375        0.6940  0.2016
+      7       0.4888        0.7101       0.4375        0.6939  0.1917
+      8       0.5089        0.7191       0.4375        0.6938  0.1924
+      9       0.5022        0.7145       0.4375        0.6938  0.1923
+     10       0.5469        0.6903       0.4464        0.6938  0.1903
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5182        0.7293       0.4038        0.6941  0.1678
+      2       0.5208        0.6988       0.4135        0.6942  0.1643
+      3       0.4792        0.7340       0.4712        0.6943  0.1641
+Stopping since valid_loss has not improved in the last 3 epochs.
+
+BNCI2014-004-CrossSession: 100%|##########| 2/2 [02:23<00:00, 70.78s/it]
+BNCI2014-004-CrossSession: 100%|##########| 2/2 [02:23<00:00, 71.77s/it]
+        dataset    evaluation                       pipeline  avg score
+0  BNCI2014-001  CrossSession    braindecode_ShallowFBCSPNet   0.508102
+1  BNCI2014-001  CrossSession  braindecode_EEGNetv4_resample   0.508005
+2  BNCI2014-001  CrossSession       braindecode_EEGInception   0.485629
+3  BNCI2014-004  CrossSession    braindecode_ShallowFBCSPNet   0.551979
+4  BNCI2014-004  CrossSession  braindecode_EEGNetv4_resample   0.489484
+5  BNCI2014-004  CrossSession       braindecode_EEGInception   0.519427
+
+
+

The deep learning architectures implemented in MOABB using Braindecode are:

+
    +
  • Shallow Convolutional Network [1]

  • +
  • Deep Convolutional Network [1]

  • +
  • EEGNetv4 [2]

  • +
  • EEGInception [3]

  • +
+

Benchmark prints a summary of the results. Detailed results are saved in a +pandas dataframe, and can be used to generate figures. The analysis & figures +are saved in the benchmark folder.

+
score_plot(results)
+plt.show()
+
+
+Scores per dataset and algorithm
/home/runner/work/moabb/moabb/moabb/analysis/plotting.py:70: UserWarning: The palette list has more values (6) than needed (3), which may not be intended.
+  sea.stripplot(
+
+
+
+
+

References#

+ +

Total running time of the script: ( 3 minutes 1.175 seconds)

+

Estimated memory usage: 582 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_benchmark_grid_search.html b/docs/auto_examples/plot_benchmark_grid_search.html new file mode 100644 index 00000000..2e40cdbc --- /dev/null +++ b/docs/auto_examples/plot_benchmark_grid_search.html @@ -0,0 +1,1047 @@ + + + + + + + + + + + + Benchmarking with MOABB with Grid Search — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_braindecode.html b/docs/auto_examples/plot_braindecode.html new file mode 100644 index 00000000..82313d91 --- /dev/null +++ b/docs/auto_examples/plot_braindecode.html @@ -0,0 +1,1137 @@ + + + + + + + + + + + + Cross-session motor imagery with deep learning EEGNet v4 model — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Cross-session motor imagery with deep learning EEGNet v4 model#

+

This example shows how to use BrainDecode in combination with MOABB evaluation. +In this example, we use the architecture EEGNetv4.

+
# Authors: Igor Carrara <igor.carrara@inria.fr>
+#          Bruno Aristimunha <b.aristimunha@gmail.com>
+#
+# License: BSD (3-clause)
+
+import matplotlib.pyplot as plt
+import mne
+import seaborn as sns
+import torch
+from braindecode import EEGClassifier
+from braindecode.models import EEGNetv4
+from sklearn.pipeline import make_pipeline
+from skorch.callbacks import EarlyStopping, EpochScoring
+from skorch.dataset import ValidSplit
+
+from moabb.datasets import BNCI2014_001
+from moabb.evaluations import CrossSessionEvaluation
+from moabb.paradigms import MotorImagery
+from moabb.utils import setup_seed
+
+
+mne.set_log_level(False)
+
+# Print Information PyTorch
+print(f"Torch Version: {torch.__version__}")
+
+# Set up GPU if it is there
+cuda = torch.cuda.is_available()
+device = "cuda" if cuda else "cpu"
+print("GPU is", "AVAILABLE" if cuda else "NOT AVAILABLE")
+
+
+
Torch Version: 1.13.1+cu117
+GPU is NOT AVAILABLE
+
+
+

In this example, we will use only the dataset BNCI2014_001.

+
+

Running the benchmark#

+

This example uses the CrossSession evaluation procedure. We focus on the dataset BNCI2014_001 and only on 1 subject +to reduce computational time.

+

To keep the computational time low, the epoch is reduced. In a real situation, we suggest using the following: +EPOCH = 1000 +PATIENCE = 300

+

This code is implemented to run on the CPU. If you’re using a GPU, do not use multithreading +(i.e. set n_jobs=1)

+
# Set random seed to be able to reproduce results
+seed = 42
+setup_seed(seed)
+
+# Ensure that all operations are deterministic on GPU (if used) for reproducibility
+torch.backends.cudnn.deterministic = True
+torch.backends.cudnn.benchmark = False
+
+# Hyperparameter
+LEARNING_RATE = 0.0625 * 0.01  # parameter taken from Braindecode
+WEIGHT_DECAY = 0  # parameter taken from Braindecode
+BATCH_SIZE = 64  # parameter taken from BrainDecode
+EPOCH = 10
+PATIENCE = 3
+fmin = 4
+fmax = 100
+tmin = 0
+tmax = None
+
+# Load the dataset
+dataset = BNCI2014_001()
+events = ["right_hand", "left_hand"]
+paradigm = MotorImagery(
+    events=events, n_classes=len(events), fmin=fmin, fmax=fmax, tmin=tmin, tmax=tmax
+)
+subjects = [1]
+X, _, _ = paradigm.get_data(dataset=dataset, subjects=subjects)
+
+
+
/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+
+
+
+
+

Create Pipelines#

+

In order to create a pipeline, we need to load a model from braindecode. +the second step is to define a skorch model using EEGClassifier from braindecode +that allows converting the PyTorch model in a scikit-learn classifier. +Here, we will use the EEGNet v4 model [1] . +This model has mandatory hyperparameters (the number of channels, the number of classes, +and the temporal length of the input) but we do not need to specify them because they will +be set dynamically by EEGClassifier using the input data during the call to the .fit() method.

+
# Define a Skorch classifier
+clf = EEGClassifier(
+    module=EEGNetv4,
+    optimizer=torch.optim.Adam,
+    optimizer__lr=LEARNING_RATE,
+    batch_size=BATCH_SIZE,
+    max_epochs=EPOCH,
+    train_split=ValidSplit(0.2, random_state=seed),
+    device=device,
+    callbacks=[
+        EarlyStopping(monitor="valid_loss", patience=PATIENCE),
+        EpochScoring(
+            scoring="accuracy", on_train=True, name="train_acc", lower_is_better=False
+        ),
+        EpochScoring(
+            scoring="accuracy", on_train=False, name="valid_acc", lower_is_better=False
+        ),
+    ],
+    verbose=1,  # Not printing the results for each epoch
+)
+
+# Create the pipelines
+pipes = {}
+pipes["EEGNetV4"] = make_pipeline(clf)
+
+
+
+
+

Evaluation#

+
dataset.subject_list = dataset.subject_list[:2]
+
+evaluation = CrossSessionEvaluation(
+    paradigm=paradigm,
+    datasets=dataset,
+    suffix="braindecode_example",
+    overwrite=True,
+    return_epochs=True,
+    n_jobs=1,
+)
+
+results = evaluation.process(pipes)
+
+print(results.head())
+
+
+
/home/runner/work/moabb/moabb/moabb/analysis/results.py:93: RuntimeWarning: Setting non-standard config type: "MOABB_RESULTS"
+  set_config("MOABB_RESULTS", osp.join(osp.expanduser("~"), "mne_data"))
+
+BNCI2014-001-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/paradigms/base.py:355: RuntimeWarning: Concatenation of Annotations within Epochs is not supported yet. All annotations will be dropped.
+  X = mne.concatenate_epochs(X)
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5156        0.7659       0.5172        0.6932  0.2121
+      2       0.5781        0.7363       0.5172        0.6925  0.1820
+      3       0.4375        0.7591       0.5517        0.6919  0.1808
+      4       0.5938        0.6669       0.5172        0.6913  0.2040
+      5       0.5781        0.6621       0.5172        0.6907  0.1819
+      6       0.5312        0.7085       0.4828        0.6903  0.1808
+      7       0.5469        0.7184       0.5172        0.6900  0.1797
+      8       0.4531        0.7167       0.5172        0.6897  0.1813
+      9       0.5938        0.6647       0.5172        0.6894  0.1812
+     10       0.5156        0.6890       0.5172        0.6890  0.1984
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.5156        0.7365       0.4138        0.7091  0.1826
+      2       0.5781        0.6883       0.4483        0.7075  0.1808
+      3       0.6094        0.6824       0.4483        0.7060  0.1827
+      4       0.5312        0.7151       0.4138        0.7049  0.1975
+      5       0.4844        0.7221       0.4138        0.7040  0.1793
+      6       0.5469        0.7016       0.4483        0.7032  0.1806
+      7       0.5781        0.6593       0.4483        0.7025  0.1804
+      8       0.5469        0.6934       0.4828        0.7019  0.1805
+      9       0.5469        0.6745       0.4828        0.7014  0.1794
+     10       0.5469        0.6874       0.4828        0.7010  0.2066
+
+BNCI2014-001-CrossSession:  50%|#####     | 1/2 [00:06<00:06,  6.61s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'right_hand': 12
+ 'left_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/paradigms/base.py:355: RuntimeWarning: Concatenation of Annotations within Epochs is not supported yet. All annotations will be dropped.
+  X = mne.concatenate_epochs(X)
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4219        0.7449       0.6207        0.6832  0.1823
+      2       0.4688        0.7881       0.6207        0.6865  0.1799
+      3       0.5000        0.7344       0.6207        0.6874  0.1904
+Stopping since valid_loss has not improved in the last 3 epochs.
+  epoch    train_acc    train_loss    valid_acc    valid_loss     dur
+-------  -----------  ------------  -----------  ------------  ------
+      1       0.4844        0.7113       0.5517        0.6901  0.1811
+      2       0.4531        0.7591       0.5517        0.6905  0.1803
+      3       0.4531        0.7438       0.5517        0.6908  0.1804
+Stopping since valid_loss has not improved in the last 3 epochs.
+
+BNCI2014-001-CrossSession: 100%|##########| 2/2 [00:10<00:00,  5.17s/it]
+BNCI2014-001-CrossSession: 100%|##########| 2/2 [00:10<00:00,  5.39s/it]
+      score      time  samples  ... n_sessions       dataset  pipeline
+0  0.521026  2.118917    144.0  ...          2  BNCI2014-001  EEGNetV4
+1  0.494985  2.049863    144.0  ...          2  BNCI2014-001  EEGNetV4
+2  0.493441  0.926365    144.0  ...          2  BNCI2014-001  EEGNetV4
+3  0.544367  0.923720    144.0  ...          2  BNCI2014-001  EEGNetV4
+
+[4 rows x 9 columns]
+
+
+
+
+

Plot Results#

+
plt.figure()
+sns.barplot(data=results, y="score", x="subject", palette="viridis")
+plt.show()
+
+
+plot braindecode
+
+

References#

+ +

Total running time of the script: ( 0 minutes 14.669 seconds)

+

Estimated memory usage: 354 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_cross_session_motor_imagery.html b/docs/auto_examples/plot_cross_session_motor_imagery.html new file mode 100644 index 00000000..c1ae2fa9 --- /dev/null +++ b/docs/auto_examples/plot_cross_session_motor_imagery.html @@ -0,0 +1,1032 @@ + + + + + + + + + + + + Cross-Session Motor Imagery — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Cross-Session Motor Imagery#

+

This example show how to perform a cross session motor imagery analysis on the +very popular dataset 2a from the BCI competition IV.

+

We will compare two pipelines :

+
    +
  • CSP+LDA

  • +
  • Riemannian Geometry+Logistic Regression

  • +
+

We will use the LeftRightImagery paradigm. This will restrict the analysis +to two classes (left hand versus right hand) and use AUC as metric.

+

The cross session evaluation context will evaluate performance using a leave +one session out cross-validation. For each session in the dataset, a model +is trained on every other session and performance are evaluated on the current +session.

+
# Authors: Alexandre Barachant <alexandre.barachant@gmail.com>
+#          Sylvain Chevallier <sylvain.chevallier@uvsq.fr>
+#
+# License: BSD (3-clause)
+
+import matplotlib.pyplot as plt
+import seaborn as sns
+from mne.decoding import CSP
+from pyriemann.estimation import Covariances
+from pyriemann.tangentspace import TangentSpace
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.linear_model import LogisticRegression
+from sklearn.pipeline import make_pipeline
+
+import moabb
+from moabb.datasets import BNCI2014_001
+from moabb.evaluations import CrossSessionEvaluation
+from moabb.paradigms import LeftRightImagery
+
+
+moabb.set_log_level("info")
+
+
+
+

Create Pipelines#

+

Pipelines must be a dict of sklearn pipeline transformer.

+

The CSP implementation is based on the MNE implementation. We selected 8 CSP +components, as usually done in the literature.

+

The Riemannian geometry pipeline consists in covariance estimation, tangent +space mapping and finally a logistic regression for the classification.

+
pipelines = {}
+
+pipelines["CSP+LDA"] = make_pipeline(CSP(n_components=8), LDA())
+
+pipelines["RG+LR"] = make_pipeline(
+    Covariances(), TangentSpace(), LogisticRegression(solver="lbfgs")
+)
+
+
+
+
+

Evaluation#

+

We define the paradigm (LeftRightImagery) and the dataset (BNCI2014_001). +The evaluation will return a DataFrame containing a single AUC score for +each subject / session of the dataset, and for each pipeline.

+

Results are saved into the database, so that if you add a new pipeline, it +will not run again the evaluation unless a parameter has changed. Results can +be overwritten if necessary.

+
paradigm = LeftRightImagery()
+# Because this is being auto-generated we only use 2 subjects
+dataset = BNCI2014_001()
+dataset.subject_list = dataset.subject_list[:2]
+datasets = [dataset]
+overwrite = False  # set to True if we want to overwrite cached results
+evaluation = CrossSessionEvaluation(
+    paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite
+)
+
+results = evaluation.process(pipelines)
+
+print(results.head())
+
+
+
BNCI2014-001-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+
+BNCI2014-001-CrossSession:  50%|#####     | 1/2 [00:04<00:04,  4.14s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+/home/runner/work/moabb/moabb/.venv/lib/python3.9/site-packages/sklearn/preprocessing/_function_transformer.py:312: FutureWarning: The current default of copy=False will change to copy=True in 1.7. Set the value of copy explicitly to avoid this warning
+  return func(X, **(kw_args if kw_args else {}))
+
+BNCI2014-001-CrossSession: 100%|##########| 2/2 [00:08<00:00,  4.01s/it]
+BNCI2014-001-CrossSession: 100%|##########| 2/2 [00:08<00:00,  4.03s/it]
+      score      time  samples  ... n_sessions       dataset  pipeline
+0  0.950424  0.257004    144.0  ...          2  BNCI2014-001     RG+LR
+1  0.962963  0.260381    144.0  ...          2  BNCI2014-001     RG+LR
+2  0.574846  0.241112    144.0  ...          2  BNCI2014-001     RG+LR
+3  0.585648  0.241607    144.0  ...          2  BNCI2014-001     RG+LR
+4  0.931713  0.326427    144.0  ...          2  BNCI2014-001   CSP+LDA
+
+[5 rows x 9 columns]
+
+
+
+
+

Plot Results#

+

Here we plot the results. We first make a pointplot with the average +performance of each pipeline across session and subjects. +The second plot is a paired scatter plot. Each point representing the score +of a single session. An algorithm will outperform another is most of the +points are in its quadrant.

+
fig, axes = plt.subplots(1, 2, figsize=[8, 4], sharey=True)
+
+sns.stripplot(
+    data=results,
+    y="score",
+    x="pipeline",
+    ax=axes[0],
+    jitter=True,
+    alpha=0.5,
+    zorder=1,
+    palette="Set1",
+)
+sns.pointplot(data=results, y="score", x="pipeline", ax=axes[0], palette="Set1")
+
+axes[0].set_ylabel("ROC AUC")
+axes[0].set_ylim(0.5, 1)
+
+paired = results.pivot_table(
+    values="score", columns="pipeline", index=["subject", "session"]
+)
+paired = paired.reset_index()
+
+sns.regplot(data=paired, y="RG+LR", x="CSP+LDA", ax=axes[1], fit_reg=False)
+axes[1].plot([0, 1], [0, 1], ls="--", c="k")
+axes[1].set_xlim(0.5, 1)
+
+plt.show()
+
+
+plot cross session motor imagery
/home/runner/work/moabb/moabb/examples/plot_cross_session_motor_imagery.py:103: FutureWarning: Passing `palette` without assigning `hue` is deprecated.
+  sns.stripplot(
+
+
+

Total running time of the script: ( 0 minutes 10.019 seconds)

+

Estimated memory usage: 332 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_cross_session_multiple_datasets.html b/docs/auto_examples/plot_cross_session_multiple_datasets.html new file mode 100644 index 00000000..428366d1 --- /dev/null +++ b/docs/auto_examples/plot_cross_session_multiple_datasets.html @@ -0,0 +1,1028 @@ + + + + + + + + + + + + Cross-Session on Multiple Datasets — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Cross-Session on Multiple Datasets#

+

This example shows how to perform a cross-session analysis on two MI datasets +using a CSP+LDA pipeline

+

The cross session evaluation context will evaluate performance using a leave +one session out cross-validation. For each session in the dataset, a model +is trained on every other session and performance are evaluated on the current +session.

+
# Authors: Sylvain Chevallier <sylvain.chevallier@uvsq.fr>
+#
+# License: BSD (3-clause)
+
+import warnings
+
+import matplotlib.pyplot as plt
+import seaborn as sns
+from mne.decoding import CSP
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.pipeline import make_pipeline
+
+import moabb
+from moabb.datasets import BNCI2014_001, Zhou2016
+from moabb.evaluations import CrossSessionEvaluation
+from moabb.paradigms import LeftRightImagery
+
+
+warnings.simplefilter(action="ignore", category=FutureWarning)
+warnings.simplefilter(action="ignore", category=RuntimeWarning)
+moabb.set_log_level("info")
+
+
+
+

Loading Dataset#

+

Load 2 subjects of BNCI 2014-004 and Zhou2016 datasets, with 2 session each

+
subj = [1, 2]
+datasets = [Zhou2016(), BNCI2014_001()]
+for d in datasets:
+    d.subject_list = subj
+
+
+
+
+

Choose Paradigm#

+

We select the paradigm MI, applying a bandpass filter (8-35 Hz) on +the data and we will keep only left- and right-hand motor imagery

+
paradigm = LeftRightImagery(fmin=8, fmax=35)
+
+
+
+
+

Create Pipelines#

+

Use the Common Spatial Patterns with 8 components and a Linear Discriminant +Analysis classifier.

+
pipeline = {}
+pipeline["CSP+LDA"] = make_pipeline(CSP(n_components=8), LDA())
+
+
+
+
+

Get Data (optional)#

+

To get access to the EEG signals downloaded from the dataset, you could +use dataset.get_data(subjects=[subject_id]) to obtain the EEG under +an MNE format, stored in a dictionary of sessions and runs. +Otherwise, paradigm.get_data(dataset=dataset, subjects=[subject_id]) +allows to obtain the EEG data in sklearn format, the labels and the meta +information. The data are preprocessed according to the paradigm +requirements.

+
# X_all, labels_all, meta_all = [], [], []
+# for d in datasets:
+#     # sessions = d.get_data(subjects=[2])
+#     X, labels, meta = paradigm.get_data(dataset=d, subjects=[2])
+#     X_all.append(X)
+#     labels_all.append(labels)
+#     meta_all.append(meta)
+
+
+
+
+

Evaluation#

+

The evaluation will return a DataFrame containing a single AUC score for +each subject / session of the dataset, and for each pipeline.

+
overwrite = True  # set to True if we want to overwrite cached results
+
+evaluation = CrossSessionEvaluation(
+    paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite
+)
+results = evaluation.process(pipeline)
+
+print(results.head())
+
+
+
Zhou2016-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  60 events (all good), 0 – 5 s, baseline off, ~8.0 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 30>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  59 events (all good), 0 – 5 s, baseline off, ~7.9 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 29>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+
+Zhou2016-CrossSession:  50%|#####     | 1/2 [00:03<00:03,  3.81s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  40 events (all good), 0 – 5 s, baseline off, ~5.4 MB, data loaded,
+ 'left_hand': 20
+ 'right_hand': 20>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+
+Zhou2016-CrossSession: 100%|##########| 2/2 [00:06<00:00,  3.29s/it]
+Zhou2016-CrossSession: 100%|##########| 2/2 [00:06<00:00,  3.37s/it]
+
+BNCI2014-001-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-001-CrossSession:  50%|#####     | 1/2 [00:02<00:02,  2.97s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-001-CrossSession: 100%|##########| 2/2 [00:05<00:00,  2.99s/it]
+BNCI2014-001-CrossSession: 100%|##########| 2/2 [00:05<00:00,  2.99s/it]
+      score      time  samples subject  ... channels  n_sessions   dataset pipeline
+0  0.851412  0.375433    200.0       1  ...       14           3  Zhou2016  CSP+LDA
+1  0.935200  0.263264    219.0       1  ...       14           3  Zhou2016  CSP+LDA
+2  0.939200  0.212352    219.0       1  ...       14           3  Zhou2016  CSP+LDA
+3  0.908000  0.195292    190.0       2  ...       14           3  Zhou2016  CSP+LDA
+4  0.770370  0.174092    200.0       2  ...       14           3  Zhou2016  CSP+LDA
+
+[5 rows x 9 columns]
+
+
+
+
+

Plot Results#

+

Here we plot the results, indicating the score for each session and subject

+
sns.catplot(
+    data=results,
+    x="session",
+    y="score",
+    hue="subject",
+    col="dataset",
+    kind="bar",
+    palette="viridis",
+)
+plt.show()
+
+
+dataset = Zhou2016, dataset = BNCI2014-001

Total running time of the script: ( 0 minutes 15.440 seconds)

+

Estimated memory usage: 316 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_cross_subject_ssvep.html b/docs/auto_examples/plot_cross_subject_ssvep.html new file mode 100644 index 00000000..57c3c505 --- /dev/null +++ b/docs/auto_examples/plot_cross_subject_ssvep.html @@ -0,0 +1,924 @@ + + + + + + + + + + + + Cross-Subject SSVEP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Cross-Subject SSVEP#

+

This example shows how to perform a cross-subject analysis on an SSVEP dataset. +We will compare four pipelines :

+
    +
  • Riemannian Geometry

  • +
  • CCA

  • +
  • TRCA

  • +
  • MsetCCA

  • +
+

We will use the SSVEP paradigm, which uses the AUC as metric.

+
# Authors: Sylvain Chevallier <sylvain.chevallier@uvsq.fr>
+#
+# License: BSD (3-clause)
+
+import warnings
+
+import matplotlib.pyplot as plt
+import pandas as pd
+import seaborn as sns
+from pyriemann.estimation import Covariances
+from pyriemann.tangentspace import TangentSpace
+from sklearn.linear_model import LogisticRegression
+from sklearn.pipeline import make_pipeline
+
+import moabb
+from moabb.datasets import Kalunga2016
+from moabb.evaluations import CrossSubjectEvaluation
+from moabb.paradigms import SSVEP, FilterBankSSVEP
+from moabb.pipelines import SSVEP_CCA, SSVEP_TRCA, ExtendedSSVEPSignal, SSVEP_MsetCCA
+
+
+warnings.simplefilter(action="ignore", category=FutureWarning)
+warnings.simplefilter(action="ignore", category=RuntimeWarning)
+moabb.set_log_level("info")
+
+
+
+

Loading Dataset#

+

We will load the data from the first 2 subjects of the SSVEP_Exo dataset +and compare two algorithms on this set. One of the algorithms could only +process class associated with a stimulation frequency, we will thus drop +the resting class. As the resting class is the last defined class, picking +the first three classes (out of four) allows to focus only on the stimulation +frequency.

+ +
+
+

Choose Paradigm#

+

We define the paradigms (SSVEP, SSVEP TRCA, SSVEP MsetCCA, and FilterBankSSVEP) and +use the dataset Kalunga2016. All 3 SSVEP paradigms applied a bandpass filter (10-42 Hz) on +the data, which include all stimuli frequencies and their first harmonics, +while the FilterBankSSVEP paradigm uses as many bandpass filters as +there are stimulation frequencies (here 3). For each stimulation frequency +the EEG is filtered with a 1 Hz-wide bandpass filter centered on the +frequency. This results in n_classes copies of the signal, filtered for each +class, as used in the filterbank motor imagery paradigms.

+
paradigm = SSVEP(fmin=10, fmax=42, n_classes=3)
+paradigm_TRCA = SSVEP(fmin=10, fmax=42, n_classes=3)
+paradigm_MSET_CCA = SSVEP(fmin=10, fmax=42, n_classes=3)
+paradigm_fb = FilterBankSSVEP(filters=None, n_classes=3)
+
+
+

Classes are defined by the frequency of the stimulation, here we use +the first two frequencies of the dataset, 13 and 17 Hz. +The evaluation function uses a LabelEncoder, transforming them +to 0 and 1

+ +
+
+

Create Pipelines#

+

Pipelines must be a dict of sklearn pipeline transformer. +The first pipeline uses Riemannian geometry, by building an extended +covariance matrices from the signal filtered around the considered +frequency and applying a logistic regression in the tangent plane. +The second pipeline relies on the above defined CCA classifier. +The third pipeline relies on the TRCA algorithm, +and the fourth uses the MsetCCA algorithm. Both CCA based methods +(i.e. CCA and MsetCCA) used 3 CCA components.

+
+
+
+
+

Evaluation#

+

The evaluation will return a DataFrame containing an accuracy score for +each subject / session of the dataset, and for each pipeline.

+

Results are saved into the database, so that if you add a new pipeline, it +will not run again the evaluation unless a parameter has changed. Results can +be overwritten if necessary.

+
overwrite = False  # set to True if we want to overwrite cached results
+
+evaluation = CrossSubjectEvaluation(
+    paradigm=paradigm, datasets=dataset, overwrite=overwrite
+)
+results = evaluation.process(pipelines)
+
+
+

Filter bank processing, determine the filter automatically from the +stimulation frequency values of events.

+ +

TRCA processing also relies on filter bank that is automatically designed.

+ +

MsetCCA processing

+ +

After processing the four, we simply concatenate the results.

+
results = pd.concat([results, results_fb, results_TRCA, results_MSET_CCA])
+
+
+
+
+

Plot Results#

+

Here we display the results as stripplot, with a pointplot for error bar.

+
fig, ax = plt.subplots(facecolor="white", figsize=[8, 4])
+sns.stripplot(
+    data=results,
+    y="score",
+    x="pipeline",
+    ax=ax,
+    jitter=True,
+    alpha=0.5,
+    zorder=1,
+    palette="Set1",
+)
+sns.pointplot(data=results, y="score", x="pipeline", ax=ax, palette="Set1")
+ax.set_ylabel("Accuracy")
+ax.set_ylim(0.1, 0.6)
+plt.show()
+
+
+plot cross subject ssvep

Total running time of the script: ( 0 minutes 4.207 seconds)

+

Estimated memory usage: 9 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_disk_cache.html b/docs/auto_examples/plot_disk_cache.html new file mode 100644 index 00000000..cfc6a0ad --- /dev/null +++ b/docs/auto_examples/plot_disk_cache.html @@ -0,0 +1,1090 @@ + + + + + + + + + + + + Cache on disk intermediate data processing states — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Cache on disk intermediate data processing states#

+

This example shows how intermediate data processing +states can be cached on disk to speed up the loading +of this data in subsequent calls.

+

When a MOABB paradigm processes a dataset, it will +first apply processing steps to the raw data, this is +called the raw_pipeline. Then, it will convert the +raw data into epochs and apply processing steps on the +epochs, this is called the epochs_pipeline. +Finally, it will eventually convert the epochs into arrays, +this is called the array_pipeline. In summary:

+

raw_pipeline –> epochs_pipeline –> array_pipeline

+

After each step, MOABB offers the possibility to save on disk +the result of the step. This is done by setting the cache_config +parameter of the paradigm’s get_data method. +The cache_config parameter is a dictionary that can take all +the parameters of moabb.datasets.base.CacheConfig as keys, +they are the following: use, save_raw, save_epochs, +save_array, overwrite_raw, overwrite_epochs, +overwrite_array, and path. You can also directly pass a +CacheConfig object as cache_config.

+

If use=False, the save_* and overwrite_* +parameters are ignored.

+

When trying to use the cache (i.e. use=True), MOABB will +first check if there exist a cache of the result of the full +pipeline (i.e. raw_pipeline –> epochs_pipeline -> +array_pipeline). +If there is none, we remove the last step of the pipeline and +look for its cached result. We keep removing steps and looking +for a cached result until we find one or until we reach an +empty pipeline. +Every time, if the overwrite_* parameter +of the corresponding step is true, we first try to erase the +cache of this step. +Once a cache has been found or the empty pipeline has been reached, +depending on the case we either load the cache or the original dataset. +Then, apply the missing steps one by one and save their result +if their corresponding save_* parameter is true.

+

By default, only the result of the raw_pipeline is saved. +This is usually a good compromise between speed and disk space +because, when using cached raw data, the epochs can be obtained +without preloading the whole raw signals, only the necessary +intervals. Yet, because only the raw data is cached, the epoching +parameters can be changed without creating a new cache each time. +However, if your epoching parameters are fixed, you can directly +cache the epochs or the arrays to speed up the loading and +reduce the disk space used.

+
+

Note

+

The cache_config parameter is also available for the get_data +method of the datasets. It works the same way as for a +paradigm except that it will save un-processed raw recordings.

+
+
# Authors: Pierre Guetschel <pierre.guetschel@gmail.com>
+#
+# License: BSD (3-clause)
+
+import shutil
+import tempfile
+
+
+
import time
+from pathlib import Path
+
+from moabb import set_log_level
+from moabb.datasets import Zhou2016
+from moabb.paradigms import LeftRightImagery
+
+
+set_log_level("info")
+
+
+
+

Basic usage#

+

The cache_config parameter is a dictionary that has the +following default values:

+
default_cache_config = dict(
+    save_raw=False,
+    save_epochs=False,
+    save_array=False,
+    use=False,
+    overwrite_raw=False,
+    overwrite_epochs=False,
+    overwrite_array=False,
+    path=None,
+)
+
+
+

You don not need to specify all the keys of cache_config, only the ones +you want to change.

+

By default, the cache is saved at the MNE data directory (i.e. when +path=None). The MNE data directory can be found with +mne.get_config('MNE_DATA'). For this example, we will save it in a +temporary directory instead:

+ +

We will use the Zhou2016 dataset and the LeftRightImagery paradigm in this +example, but this works for any dataset and paradigm pair.:

+ +

And we will only use the first subject for this example:

+
subjects = [1]
+
+
+

Then, saving a cache can simply be done by setting the desired parameters +in the cache_config dictionary:

+
cache_config = dict(
+    use=True,
+    save_raw=True,
+    save_epochs=True,
+    save_array=True,
+    path=temp_dir,
+)
+_ = paradigm.get_data(dataset, subjects, cache_config=cache_config)
+
+
+
/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  60 events (all good), 0 – 5 s, baseline off, ~8.0 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 30>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  59 events (all good), 0 – 5 s, baseline off, ~7.9 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 29>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+
+
+
+
+

Time comparison#

+

Now, we will compare the time it takes to load the with different levels of +cache. For this, we will use the cache saved in the previous block and +overwrite the steps results one by one so that we can compare the time it +takes to load the data and compute the missing steps with an increasing +number of missing steps.

+

Using array cache:

+
cache_config = dict(
+    use=True,
+    path=temp_dir,
+    save_raw=False,
+    save_epochs=False,
+    save_array=False,
+    overwrite_raw=False,
+    overwrite_epochs=False,
+    overwrite_array=False,
+)
+t0 = time.time()
+_ = paradigm.get_data(dataset, subjects, cache_config=cache_config)
+t_array = time.time() - t0
+
+
+

Using epochs cache:

+
cache_config = dict(
+    use=True,
+    path=temp_dir,
+    save_raw=False,
+    save_epochs=False,
+    save_array=False,
+    overwrite_raw=False,
+    overwrite_epochs=False,
+    overwrite_array=True,
+)
+t0 = time.time()
+_ = paradigm.get_data(dataset, subjects, cache_config=cache_config)
+t_epochs = time.time() - t0
+
+
+

Using raw cache:

+
cache_config = dict(
+    use=True,
+    path=temp_dir,
+    save_raw=False,
+    save_epochs=False,
+    save_array=False,
+    overwrite_raw=False,
+    overwrite_epochs=True,
+    overwrite_array=True,
+)
+t0 = time.time()
+_ = paradigm.get_data(dataset, subjects, cache_config=cache_config)
+t_raw = time.time() - t0
+
+
+
/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  60 events (all good), 0 – 5 s, baseline off, ~8.0 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 30>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  59 events (all good), 0 – 5 s, baseline off, ~7.9 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 29>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+
+
+

Using no cache:

+
cache_config = dict(
+    use=False,
+    path=temp_dir,
+    save_raw=False,
+    save_epochs=False,
+    save_array=False,
+    overwrite_raw=False,
+    overwrite_epochs=False,
+    overwrite_array=False,
+)
+t0 = time.time()
+_ = paradigm.get_data(dataset, subjects, cache_config=cache_config)
+t_nocache = time.time() - t0
+
+
+
/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  60 events (all good), 0 – 5 s, baseline off, ~8.0 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 30>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  59 events (all good), 0 – 5 s, baseline off, ~7.9 MB, data loaded,
+ 'left_hand': 30
+ 'right_hand': 29>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  50 events (all good), 0 – 5 s, baseline off, ~6.7 MB, data loaded,
+ 'left_hand': 25
+ 'right_hand': 25>
+  warn(f"warnEpochs {epochs}")
+
+
+

Time needed to load the data with different levels of cache:

+
print(f"Using array cache: {t_array:.2f} seconds")
+print(f"Using epochs cache: {t_epochs:.2f} seconds")
+print(f"Using raw cache: {t_raw:.2f} seconds")
+print(f"Without cache: {t_nocache:.2f} seconds")
+
+
+
Using array cache: 0.31 seconds
+Using epochs cache: 0.49 seconds
+Using raw cache: 0.78 seconds
+Without cache: 2.35 seconds
+
+
+

As you can see, using a raw cache is more than 5 times faster than +without cache. +This is because when using the raw cache, the data is not preloaded, only +the desired epochs are loaded in memory.

+

Using the epochs cache is a little faster than the raw cache. This is because +there are several preprocessing steps done after the epoching by the +epochs_pipeline. This difference would be greater if the resample +argument was different that the sampling frequency of the dataset. Indeed, +the data loading time is directly proportional to its sampling frequency +and the resampling is done by the epochs_pipeline.

+

Finally, we observe very little difference between array and epochs cache. +The main interest of the array cache is when the user passes a +computationally heavy but fixed additional preprocessing (for example +computing the covariance matrices of the epochs). This can be done by using +the postprocess_pipeline argument. The output of this additional pipeline +(necessary a numpy array) will be saved to avoid re-computing it each time.

+
+
+

Technical details#

+

Under the hood, the cache is saved on disk in a Brain Imaging Data Structure +(BIDS) compliant format. More details on this structure can be found in the +tutorial ./plot_bids_conversion.

+

However, there are two particular aspects of the way MOABB saves the data +that are not specific to BIDS:

+
    +
  • For each file, we set a +description key. +This key is a code that corresponds to a hash of the +pipeline that was used to generate the data (i.e. from raw to the state +of the cache). This code is unique for each different pipeline and allows +to identify all the files that were generated by the same pipeline.

  • +
  • Once we finish saving all the files for a given combination of dataset, +subject, and pipeline, we write a file ending in "_lockfile.json" at +the root directory of this subject. This file serves two purposes:

    +
      +
    • It indicates that the cache is complete for this subject and pipeline. +If it is not present, it means that something went wrong during the +saving process and the cache is incomplete.

    • +
    • The file contains the un-hashed string representation of the pipeline. +Therefore, it can be used to identify the pipeline used without having +to decode the description key.

    • +
    +
  • +
+
+
+

Cleanup#

+

Finally, we can delete the temporary folder:

+ +

Total running time of the script: ( 0 minutes 27.185 seconds)

+

Estimated memory usage: 325 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_explore_paradigm.html b/docs/auto_examples/plot_explore_paradigm.html new file mode 100644 index 00000000..652a24f4 --- /dev/null +++ b/docs/auto_examples/plot_explore_paradigm.html @@ -0,0 +1,1449 @@ + + + + + + + + + + + + Explore Paradigm Object — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Explore Paradigm Object#

+

A paradigm defines how the raw data will be converted to trials ready +to be processed by a decoding algorithm. This is a function of the paradigm +used, i.e. in motor imagery one can have two-class, multi-class, +or continuous paradigms; similarly, different preprocessing is necessary +for ERP vs ERD paradigms.

+

A paradigm also defines the appropriate evaluation metric, for example AUC +for binary classification problems, accuracy for multiclass, or kappa +coefficients for continuous paradigms.

+
+
This tutorial explores the paradigm object, with 3 examples of paradigm :
    +
  • MotorImagery

  • +
  • FilterBankMotorImagery

  • +
  • LeftRightImagery

  • +
+
+
+
# Authors: Alexandre Barachant <alexandre.barachant@gmail.com>
+#          Sylvain Chevallier <sylvain.chevallier@uvsq.fr>
+#
+# License: BSD (3-clause)
+
+import numpy as np
+
+from moabb.datasets import BNCI2014_001
+from moabb.paradigms import FilterBankMotorImagery, LeftRightImagery, MotorImagery
+
+
+print(__doc__)
+
+
+
+

MotorImagery#

+

First, let’s take an example of the MotorImagery paradigm.

+
paradigm = MotorImagery(n_classes=4)
+
+print(paradigm.__doc__)
+
+
+
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.
+
+    fmin: float (default 8)
+        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.
+
+
+

The function get_data allow you to access preprocessed data from a dataset. +this function will return 3 objects. A numpy array containing the +preprocessed EEG data, the labels, and a dataframe with metadata.

+
print(paradigm.get_data.__doc__)
+
+
+
Return the data for a list of subject.
+
+return the data, labels and a dataframe with metadata. the dataframe
+will contain at least the following columns
+
+- subject : the subject indice
+- session : the session indice
+- run : the run indice
+
+Parameters
+----------
+dataset:
+    A dataset instance.
+subjects: List of int
+    List of subject number
+return_epochs: boolean
+    This flag specifies whether to return only the data array or the
+    complete processed mne.Epochs
+return_raws: boolean
+    To return raw files and events, to ensure compatibility with braindecode.
+    Mutually exclusive with return_epochs
+cache_config: dict | CacheConfig
+    Configuration for caching of datasets. See :class:`moabb.datasets.base.CacheConfig` for details.
+postprocess_pipeline: Pipeline | None
+    Optional pipeline to apply to the data after the preprocessing.
+    This pipeline will either receive :class:`mne.io.BaseRaw`, :class:`mne.Epochs`
+    or :func:`np.ndarray` as input, depending on the values of ``return_epochs``
+    and ``return_raws``.
+    This pipeline must return an ``np.ndarray``.
+    This pipeline must be "fixed" because it will not be trained,
+    i.e. no call to ``fit`` will be made.
+
+Returns
+-------
+X : Union[np.ndarray, mne.Epochs]
+    the data that will be used as features for the model
+    Note: if return_epochs=True,  this is mne.Epochs
+    if return_epochs=False, this is np.ndarray
+labels: np.ndarray
+    the labels for training / evaluating the model
+metadata: pd.DataFrame
+    A dataframe containing the metadata.
+
+
+

Lets take the example of the BNCI2014_001 dataset, known as the dataset IIa +from the BCI competition IV. We will load the data from the subject 1. +When calling get_data, the paradigm will retrieve the data from the +specified list of subjects, apply preprocessing (by default, a bandpass +between 7 and 35 Hz), epoch the data (with interval specified by the dataset, +unless superseded by the paradigm) and return the corresponding objects.

+ +
/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  48 events (all good), 2 – 6 s, baseline off, ~8.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12
+ 'feet': 12
+ 'tongue': 12>
+  warn(f"warnEpochs {epochs}")
+
+
+

The epoched data is a 3D array, with epochs on the first dimension (here +576 trials), channels on the second (22 channels) and time sample on the last +one.

+
print(X.shape)
+
+
+
(576, 22, 1001)
+
+
+

Labels contains the labels corresponding to each trial. in the case of this +dataset, we have the 4 types of motor imagery that was performed.

+
print(np.unique(y))
+
+
+
['feet' 'left_hand' 'right_hand' 'tongue']
+
+
+

Metadata have at least 3 columns: subject, session and run.

+
    +
  • subject is the subject id of the corresponding trial

  • +
  • session is the session id. A session denotes a recording made without +removing the EEG cap.

  • +
  • run is the individual continuous recording made during a session. A session +may or may not contain multiple runs.

  • +
+
print(metadata.head())
+
+
+
   subject session run
+0        1  0train   0
+1        1  0train   0
+2        1  0train   0
+3        1  0train   0
+4        1  0train   0
+
+
+

For this data, we have one subject, 2 sessions (2 different recording days) +and 6 runs per session.

+
print(metadata.describe(include="all"))
+
+
+
        subject session  run
+count     576.0     576  576
+unique      NaN       2    6
+top         NaN  0train    0
+freq        NaN     288   96
+mean        1.0     NaN  NaN
+std         0.0     NaN  NaN
+min         1.0     NaN  NaN
+25%         1.0     NaN  NaN
+50%         1.0     NaN  NaN
+75%         1.0     NaN  NaN
+max         1.0     NaN  NaN
+
+
+

Paradigm objects can also return the list of all dataset compatible. Here +it will return the list all the imagery datasets from the MOABB.

+ +
['AlexandreMotorImagery', 'BNCI2014-001', 'BNCI2014-002', 'BNCI2014-004', 'BNCI2015-001', 'BNCI2015-004', 'Cho2017', 'FakeDataset-imagery-10-2--60-60--120-120--fake1-fake2-fake3--c3-cz-c4', 'GrosseWentrup2009', 'Lee2019-MI', 'Ofner2017', 'PhysionetMotorImagery', 'Schirrmeister2017', 'Shin2017A', 'Weibo2014', 'Zhou2016']
+
+
+
+
+

FilterBank MotorImagery#

+

FilterBankMotorImagery is the same paradigm, but with a different +preprocessing. In this case, it applies a bank of 6 bandpass filter on the data +before concatenating the output.

+
paradigm = FilterBankMotorImagery()
+
+print(paradigm.__doc__)
+
+
+
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.
+
+
+

Therefore, the output X is a 4D array, with trial x channel x time x filter

+ +
/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+(288, 22, 1001, 6)
+
+
+
+
+

LeftRight MotorImagery#

+

LeftRightImagery is a variation over the BaseMotorImagery paradigm, +restricted to left- and right-hand events.

+
paradigm = LeftRightImagery()
+
+print(paradigm.__doc__)
+
+
+
Motor Imagery for left hand/right hand classification.
+
+    Metric is 'roc_auc'
+
+
+

The compatible dataset list is a subset of motor imagery dataset that +contains at least left and right hand events.

+ +
['BNCI2014-001', 'BNCI2014-004', 'Cho2017', 'GrosseWentrup2009', 'Lee2019-MI', 'PhysionetMotorImagery', 'Schirrmeister2017', 'Shin2017A', 'Weibo2014', 'Zhou2016']
+
+
+

So if we apply this to our original dataset, it will only return trials +corresponding to left- and right-hand motor imagination.

+ +
/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+['left_hand' 'right_hand']
+
+
+

Total running time of the script: ( 0 minutes 23.021 seconds)

+

Estimated memory usage: 799 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_fixed_interval_windows.html b/docs/auto_examples/plot_fixed_interval_windows.html new file mode 100644 index 00000000..4afa91c1 --- /dev/null +++ b/docs/auto_examples/plot_fixed_interval_windows.html @@ -0,0 +1,907 @@ + + + + + + + + + + + + Fixed interval windows processing — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Fixed interval windows processing#

+

This example shows how to process a dataset using the +moabb.paradigms.FixedIntervalWindowsProcessing paradigm. This paradigm +creates epochs at fixed intervals, ignoring the stim +channel and events of the datasets. Therefore, it is +compatible with all the datasets. Unfortunately, +this paradigm is not compatible with the MOABB evaluation +framework. However, it can be used to process datasets +for unsupervised algorithms.

+

In this example, we will use the Zhou2016 dataset because +it is relatively small and can be downloaded quickly.

+
# Authors: Pierre Guetschel <pierre.guetschel@gmail.com>
+#
+# License: BSD (3-clause)
+
+
+
import matplotlib.pyplot as plt
+import mne
+import numpy as np
+
+from moabb import set_log_level
+from moabb.datasets import Zhou2016
+from moabb.paradigms import FixedIntervalWindowsProcessing, MotorImagery
+
+
+set_log_level("info")
+
+
+
+

Process a dataset#

+

To process a dataset with +moabb.paradigms.FixedIntervalWindowsProcessing , you can use the +method as with every other paradigm. The only additional parameters are +length, stride, start_offset, and stop_offset. They are +all parametrised in seconds. length is the length of the epochs, +stride is the time between the onset of two consecutive epochs, +start_offset is the offset between each run start and their first +epoch, and stop_offset is the offset between each run start and their +last epoch. The default values are length=5, stride=10, +start_offset=0, and stop_offset=None (i.e. end of the run).

+

An example usage of moabb.paradigms.FixedIntervalWindowsProcessing +with the moabb.datasets.Zhou2016 dataset:

+
dataset = Zhou2016()
+processing = FixedIntervalWindowsProcessing(
+    # new parameters:
+    length=100,
+    stride=50,
+    start_offset=300,
+    stop_offset=900,  # we epoch 10 minutes per run, starting at 5 minutes (i.e. 300 seconds)
+    # parameters common with other paradigms:
+    resample=100,
+    fmin=7,
+    fmax=45,
+    baseline=None,
+    channels=None,
+)
+X, labels, metadata = processing.get_data(dataset=dataset, subjects=[1])
+
+
+
/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  10 events (all good), 0 – 100 s, baseline off, ~26.7 MB, data loaded,
+ 'Window': 10>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  10 events (all good), 0 – 100 s, baseline off, ~26.7 MB, data loaded,
+ 'Window': 10>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  10 events (all good), 0 – 100 s, baseline off, ~26.7 MB, data loaded,
+ 'Window': 10>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  10 events (all good), 0 – 100 s, baseline off, ~26.7 MB, data loaded,
+ 'Window': 10>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  10 events (all good), 0 – 100 s, baseline off, ~26.7 MB, data loaded,
+ 'Window': 10>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  10 events (all good), 0 – 100 s, baseline off, ~26.7 MB, data loaded,
+ 'Window': 10>
+  warn(f"warnEpochs {epochs}")
+
+
+

In this dataset, there are three sessions per subject and two runs per +session:

+
for column in metadata.columns:
+    print(f"{column}s: {metadata[column].unique()}")
+
+
+
subjects: [1]
+sessions: ['0' '1' '2']
+runs: ['0' '1']
+
+
+

We expect to obtained (stop_offset - start_offset - length) / stride; +i.e. (900-300-100)/50=10 epochs per run. Here we have 3*2=6 runs. +And indeed, we obtain +a total of 6*10=60 epochs:

+
print(f"Number of epochs: {len(X)}")
+
+
+
Number of epochs: 60
+
+
+
+

Note

+

To apply a bank of bandpass filters, you can use the +moabb.paradigms.FilterBankFixedIntervalWindowsProcessing +paradigm instead.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_within_session_p300.html b/docs/auto_examples/plot_within_session_p300.html new file mode 100644 index 00000000..bf662d03 --- /dev/null +++ b/docs/auto_examples/plot_within_session_p300.html @@ -0,0 +1,902 @@ + + + + + + + + + + + + Within Session P300 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Within Session P300#

+

This example shows how to perform a within session analysis on three different +P300 datasets.

+

We will compare two pipelines :

+
    +
  • Riemannian geometry

  • +
  • XDAWN with Linear Discriminant Analysis

  • +
+

We will use the P300 paradigm, which uses the AUC as metric.

+
# Authors: Pedro Rodrigues <pedro.rodrigues01@gmail.com>
+#
+# License: BSD (3-clause)
+
+import warnings
+
+import matplotlib.pyplot as plt
+import seaborn as sns
+from mne.decoding import Vectorizer
+from pyriemann.estimation import Xdawn, XdawnCovariances
+from pyriemann.tangentspace import TangentSpace
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.pipeline import make_pipeline
+
+import moabb
+from moabb.datasets import BNCI2014_009
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import P300
+
+
+

getting rid of the warnings about the future

+
warnings.simplefilter(action="ignore", category=FutureWarning)
+warnings.simplefilter(action="ignore", category=RuntimeWarning)
+
+moabb.set_log_level("info")
+
+
+
+

Create Pipelines#

+

Pipelines must be a dict of sklearn pipeline transformer.

+
pipelines = {}
+
+
+

We have to do this because the classes are called ‘Target’ and ‘NonTarget’ +but the evaluation function uses a LabelEncoder, transforming them +to 0 and 1

+
labels_dict = {"Target": 1, "NonTarget": 0}
+
+pipelines["RG+LDA"] = make_pipeline(
+    XdawnCovariances(
+        nfilter=2, classes=[labels_dict["Target"]], estimator="lwf", xdawn_estimator="scm"
+    ),
+    TangentSpace(),
+    LDA(solver="lsqr", shrinkage="auto"),
+)
+
+pipelines["Xdw+LDA"] = make_pipeline(
+    Xdawn(nfilter=2, estimator="scm"), Vectorizer(), LDA(solver="lsqr", shrinkage="auto")
+)
+
+
+
+
+

Evaluation#

+

We define the paradigm (P300) and use all three datasets available for it. +The evaluation will return a DataFrame containing a single AUC score for +each subject / session of the dataset, and for each pipeline.

+

Results are saved into the database, so that if you add a new pipeline, it +will not run again the evaluation unless a parameter has changed. Results can +be overwritten if necessary.

+
paradigm = P300(resample=128)
+dataset = BNCI2014_009()
+dataset.subject_list = dataset.subject_list[:2]
+datasets = [dataset]
+overwrite = True  # set to True if we want to overwrite cached results
+evaluation = WithinSessionEvaluation(
+    paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=overwrite
+)
+results = evaluation.process(pipelines)
+
+
+
BNCI2014-009-WithinSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-009-WithinSession:  50%|#####     | 1/2 [00:09<00:09,  9.78s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  576 events (all good), 0 – 0.800781 s, baseline off, ~14.5 MB, data loaded,
+ 'Target': 96
+ 'NonTarget': 480>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-009-WithinSession: 100%|##########| 2/2 [00:19<00:00,  9.62s/it]
+BNCI2014-009-WithinSession: 100%|##########| 2/2 [00:19<00:00,  9.64s/it]
+
+
+
+
+

Plot Results#

+

Here we plot the results to compare the two pipelines

+
fig, ax = plt.subplots(facecolor="white", figsize=[8, 4])
+
+sns.stripplot(
+    data=results,
+    y="score",
+    x="pipeline",
+    ax=ax,
+    jitter=True,
+    alpha=0.5,
+    zorder=1,
+    palette="Set1",
+)
+sns.pointplot(data=results, y="score", x="pipeline", ax=ax, palette="Set1")
+
+ax.set_ylabel("ROC AUC")
+ax.set_ylim(0.5, 1)
+
+plt.show()
+
+
+plot within session p300

Total running time of the script: ( 0 minutes 21.487 seconds)

+

Estimated memory usage: 19 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/plot_within_session_ssvep.html b/docs/auto_examples/plot_within_session_ssvep.html new file mode 100644 index 00000000..1949a879 --- /dev/null +++ b/docs/auto_examples/plot_within_session_ssvep.html @@ -0,0 +1,975 @@ + + + + + + + + + + + + Within Session SSVEP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Within Session SSVEP#

+

This Example show how to perform a within-session SSVEP analysis on the +MAMEM dataset 3, using a CCA pipeline.

+

The within-session evaluation assesses the performance of a classification +pipeline using a 5-fold cross-validation. The reported metric (here, accuracy) +is the average of all fold.

+
# Authors: Sylvain Chevallier <sylvain.chevallier@uvsq.fr>
+#
+# License: BSD (3-clause)
+
+import warnings
+
+import matplotlib.pyplot as plt
+import seaborn as sns
+from sklearn.pipeline import make_pipeline
+
+import moabb
+from moabb.datasets import MAMEM3
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import SSVEP
+from moabb.pipelines import SSVEP_CCA
+
+
+warnings.simplefilter(action="ignore", category=FutureWarning)
+warnings.simplefilter(action="ignore", category=RuntimeWarning)
+moabb.set_log_level("info")
+
+
+
+

Loading Dataset#

+

Load 2 subjects of MAMEM3 dataset

+ +
+
+

Choose Paradigm#

+

We select the paradigm SSVEP, applying a bandpass filter (3-15 Hz) on +the data and we keep only the first 3 classes, that is stimulation +frequency of 6.66, 7.50 and 8.57 Hz.

+
paradigm = SSVEP(fmin=3, fmax=15, n_classes=3)
+
+
+
+
+

Create Pipelines#

+

Use a Canonical Correlation Analysis classifier

+ +
+
+

Get Data (optional)#

+

To get access to the EEG signals downloaded from the dataset, you could +use dataset.get_data(subjects=[subject_id]) to obtain the EEG under +MNE format, stored in a dictionary of sessions and runs. +Otherwise, paradigm.get_data(dataset=dataset, subjects=[subject_id]) +allows to obtain the EEG data in scikit format, the labels and the meta +information. In paradigm.get_data, the EEG are preprocessed according +to the paradigm requirement.

+
# sessions = dataset.get_data(subjects=[3])
+# X, labels, meta = paradigm.get_data(dataset=dataset, subjects=[3])
+
+
+
+
+

Evaluation#

+

The evaluation will return a DataFrame containing a single AUC score for +each subject and pipeline.

+
overwrite = True  # set to True if we want to overwrite cached results
+
+evaluation = WithinSessionEvaluation(
+    paradigm=paradigm, datasets=dataset, suffix="examples", overwrite=overwrite
+)
+results = evaluation.process(pipeline)
+
+print(results.head())
+
+
+
MAMEM3-WithinSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  5 events (all good), 1 – 4 s, baseline off, ~236 kB, data loaded,
+ '6.66': 3
+ '7.50': 0
+ '8.57': 2>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  4 events (all good), 1 – 4 s, baseline off, ~194 kB, data loaded,
+ '6.66': 1
+ '7.50': 0
+ '8.57': 3>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  5 events (all good), 1 – 4 s, baseline off, ~236 kB, data loaded,
+ '6.66': 3
+ '7.50': 0
+ '8.57': 2>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  4 events (all good), 1 – 4 s, baseline off, ~194 kB, data loaded,
+ '6.66': 1
+ '7.50': 0
+ '8.57': 3>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  5 events (all good), 1 – 4 s, baseline off, ~236 kB, data loaded,
+ '6.66': 3
+ '7.50': 0
+ '8.57': 2>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  4 events (all good), 1 – 4 s, baseline off, ~194 kB, data loaded,
+ '6.66': 1
+ '7.50': 0
+ '8.57': 3>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  5 events (all good), 1 – 4 s, baseline off, ~236 kB, data loaded,
+ '6.66': 3
+ '7.50': 0
+ '8.57': 2>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  4 events (all good), 1 – 4 s, baseline off, ~194 kB, data loaded,
+ '6.66': 1
+ '7.50': 0
+ '8.57': 3>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  5 events (all good), 1 – 4 s, baseline off, ~236 kB, data loaded,
+ '6.66': 3
+ '7.50': 0
+ '8.57': 2>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  4 events (all good), 1 – 4 s, baseline off, ~194 kB, data loaded,
+ '6.66': 1
+ '7.50': 0
+ '8.57': 3>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+
+MAMEM3-WithinSession:  50%|#####     | 1/2 [00:02<00:02,  2.16s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  5 events (all good), 1 – 4 s, baseline off, ~236 kB, data loaded,
+ '6.66': 3
+ '7.50': 0
+ '8.57': 2>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  4 events (all good), 1 – 4 s, baseline off, ~194 kB, data loaded,
+ '6.66': 1
+ '7.50': 0
+ '8.57': 3>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  5 events (all good), 1 – 4 s, baseline off, ~236 kB, data loaded,
+ '6.66': 3
+ '7.50': 0
+ '8.57': 2>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  4 events (all good), 1 – 4 s, baseline off, ~194 kB, data loaded,
+ '6.66': 1
+ '7.50': 0
+ '8.57': 3>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  5 events (all good), 1 – 4 s, baseline off, ~236 kB, data loaded,
+ '6.66': 3
+ '7.50': 0
+ '8.57': 2>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  4 events (all good), 1 – 4 s, baseline off, ~194 kB, data loaded,
+ '6.66': 1
+ '7.50': 0
+ '8.57': 3>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  5 events (all good), 1 – 4 s, baseline off, ~236 kB, data loaded,
+ '6.66': 3
+ '7.50': 0
+ '8.57': 2>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  4 events (all good), 1 – 4 s, baseline off, ~194 kB, data loaded,
+ '6.66': 1
+ '7.50': 0
+ '8.57': 3>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  5 events (all good), 1 – 4 s, baseline off, ~236 kB, data loaded,
+ '6.66': 3
+ '7.50': 0
+ '8.57': 2>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  4 events (all good), 1 – 4 s, baseline off, ~194 kB, data loaded,
+ '6.66': 1
+ '7.50': 0
+ '8.57': 3>
+  warn(f"warnEpochs {epochs}")
+No hdf5_path provided, models will not be saved.
+
+MAMEM3-WithinSession: 100%|##########| 2/2 [00:04<00:00,  2.07s/it]
+MAMEM3-WithinSession: 100%|##########| 2/2 [00:04<00:00,  2.08s/it]
+      score      time  samples subject  ... channels  n_sessions  dataset pipeline
+0  0.688889  0.048859     45.0       1  ...       14           1   MAMEM3      CCA
+1  0.266667  0.048093     45.0       3  ...       14           1   MAMEM3      CCA
+
+[2 rows x 9 columns]
+
+
+
+
+

Plot Results#

+

Here we plot the results, indicating the score for each subject

+
plt.figure()
+sns.barplot(data=results, y="score", x="session", hue="subject", palette="viridis")
+
+
+plot within session ssvep
<Axes: xlabel='session', ylabel='score'>
+
+
+

And the computation time in seconds

+
plt.figure()
+ax = sns.barplot(data=results, y="time", x="session", hue="subject", palette="Reds")
+ax.set_ylabel("Time (s)")
+plt.show()
+
+
+plot within session ssvep

Total running time of the script: ( 0 minutes 7.174 seconds)

+

Estimated memory usage: 10 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_examples/sg_execution_times.html b/docs/auto_examples/sg_execution_times.html new file mode 100644 index 00000000..c9ca68d2 --- /dev/null +++ b/docs/auto_examples/sg_execution_times.html @@ -0,0 +1,602 @@ + + + + + + + + + + + + Computation times — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Computation times#

+

16:10.695 total execution time for auto_examples files:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Benchmarking on MOABB with Tensorflow deep net architectures (plot_benchmark_DL.py)

09:03.512

995.8 MB

Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures (plot_benchmark_braindecode.py)

03:01.175

581.9 MB

Benchmarking with MOABB with Grid Search (plot_benchmark_grid_search.py)

01:34.763

243.2 MB

Cache on disk intermediate data processing states (plot_disk_cache.py)

00:27.185

324.9 MB

Explore Paradigm Object (plot_explore_paradigm.py)

00:23.021

798.7 MB

Within Session P300 (plot_within_session_p300.py)

00:21.487

19.4 MB

Examples of how to use MOABB to benchmark pipelines. (plot_benchmark.py)

00:20.819

352.5 MB

Cross-Session on Multiple Datasets (plot_cross_session_multiple_datasets.py)

00:15.440

315.7 MB

Cross-session motor imagery with deep learning EEGNet v4 model (plot_braindecode.py)

00:14.669

354.1 MB

Cross-Session Motor Imagery (plot_cross_session_motor_imagery.py)

00:10.019

332.1 MB

Fixed interval windows processing (plot_fixed_interval_windows.py)

00:07.223

303.6 MB

Within Session SSVEP (plot_within_session_ssvep.py)

00:07.174

9.9 MB

Cross-Subject SSVEP (plot_cross_subject_ssvep.py)

00:04.207

8.8 MB

Change Download Directory (changing_download_directory.py)

00:00.000

0.0 MB

Benchmarking with MOABB showing the CO2 footprint (example_codecarbon.py)

00:00.000

0.0 MB

Load Model (Scikit, Pytorch, Keras) with MOABB (load_model.py)

00:00.000

0.0 MB

Convert a MOABB dataset to BIDS (noplot_bids_conversion.py)

00:00.000

0.0 MB

Spectral analysis of the trials (noplot_phmd_ml_spectrum.py)

00:00.000

0.0 MB

sphx_glr_auto_examples_noplot_vr_pc_p300_different_epoch_size.py (noplot_vr_pc_p300_different_epoch_size.py)

00:00.000

0.0 MB

+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_tutorials/4_adding_a_dataset.html b/docs/auto_tutorials/4_adding_a_dataset.html new file mode 100644 index 00000000..80efbb42 --- /dev/null +++ b/docs/auto_tutorials/4_adding_a_dataset.html @@ -0,0 +1,917 @@ + + + + + + + + + + + + Tutorial 4: Creating a dataset class — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Tutorial 4: Creating a dataset class#

+
# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier
+#
+# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019
+
+import mne
+import numpy as np
+from pyriemann.classification import MDM
+from pyriemann.estimation import Covariances
+from scipy.io import loadmat, savemat
+from sklearn.pipeline import make_pipeline
+
+from moabb.datasets import download as dl
+from moabb.datasets.base import BaseDataset
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import LeftRightImagery
+
+
+
+

Creating some Data#

+

To illustrate the creation of a dataset class in MOABB, we first create an +example dataset saved in .mat file. It contains a single fake recording on +8 channels lasting for 150 seconds (sampling frequency 256 Hz). We have +included the script that creates this dataset and have uploaded it online. +The fake dataset is available on the +Zenodo website

+
def create_example_dataset():
+    """Create a fake example for a dataset."""
+    sfreq = 256
+    t_recording = 150
+    t_trial = 1  # duration of a trial
+    intertrial = 2  # time between end of a trial and the next one
+    n_chan = 8
+
+    x = np.zeros((n_chan + 1, t_recording * sfreq))  # electrodes + stimulus
+    stim = np.zeros(t_recording * sfreq)
+    t_offset = 1.0  # offset where the trials start
+    n_trials = 40
+
+    rep = np.linspace(0, 4 * t_trial, t_trial * sfreq)
+    signal = np.sin(2 * np.pi / t_trial * rep)
+    for n in range(n_trials):
+        label = n % 2 + 1  # alternate between class 0 and class 1
+        tn = int(t_offset * sfreq + n * (t_trial + intertrial) * sfreq)
+        stim[tn] = label
+        noise = 0.1 * np.random.randn(n_chan, len(signal))
+        x[:-1, tn : (tn + t_trial * sfreq)] = label * signal + noise
+    x[-1, :] = stim
+    return x, sfreq
+
+
+# Create the fake data
+for subject in [1, 2, 3]:
+    x, fs = create_example_dataset()
+    filename = "subject_" + str(subject).zfill(2) + ".mat"
+    mdict = {}
+    mdict["x"] = x
+    mdict["fs"] = fs
+    savemat(filename, mdict)
+
+
+
+
+

Creating a Dataset Class#

+

We will create now a dataset class using the fake data simulated with the +code from above. For this, we first need to import the right classes from +MOABB:

+
    +
  • dl is a very useful script that downloads automatically a dataset online +if it is not yet available in the user’s computer. The script knows where +to download the files because we create a global variable telling the URL +where to fetch the data.

  • +
  • BaseDataset is the basic class that we overload to create our dataset.

  • +
+

The global variable with the dataset’s URL should specify an online +repository where all the files are stored.

+
ExampleDataset_URL = "https://sandbox.zenodo.org/record/369543/files/"
+
+
+

The ExampleDataset needs to implement only 3 functions:

+
    +
  • __init__ for indicating the parameter of the dataset

  • +
  • _get_single_subject_data to define how to process the data once they +have been downloaded

  • +
  • data_path to define how the data are downloaded.

  • +
+
class ExampleDataset(BaseDataset):
+    """Dataset used to exemplify the creation of a dataset class in MOABB.
+
+    The data samples have been simulated and has no physiological
+    meaning whatsoever.
+    """
+
+    def __init__(self):
+        super().__init__(
+            subjects=[1, 2, 3],
+            sessions_per_subject=1,
+            events={"left_hand": 1, "right_hand": 2},
+            code="ExampleDataset",
+            interval=[0, 0.75],
+            paradigm="imagery",
+            doi="",
+        )
+
+    def _get_single_subject_data(self, subject):
+        """Return data for a single subject."""
+        file_path_list = self.data_path(subject)
+
+        data = loadmat(file_path_list[0])
+        x = data["x"]
+        fs = data["fs"]
+        ch_names = ["ch" + str(i) for i in range(8)] + ["stim"]
+        ch_types = ["eeg" for i in range(8)] + ["stim"]
+        info = mne.create_info(ch_names, fs, ch_types)
+        raw = mne.io.RawArray(x, info)
+
+        sessions = {}
+        sessions["0"] = {}
+        sessions["0"]["0"] = raw
+        return sessions
+
+    def data_path(
+        self, subject, path=None, force_update=False, update_path=None, verbose=None
+    ):
+        """Download the data from one subject."""
+        if subject not in self.subject_list:
+            raise (ValueError("Invalid subject number"))
+
+        url = "{:s}subject_0{:d}.mat".format(ExampleDataset_URL, subject)
+        path = dl.data_dl(url, "ExampleDataset")
+        return [path]  # it has to return a list
+
+
+
+
+

Using the ExampleDataset#

+

Now that the ExampleDataset is defined, it could be instantiated directly. +The rest of the code follows the steps described in the previous tutorials.

+
dataset = ExampleDataset()
+
+paradigm = LeftRightImagery()
+X, labels, meta = paradigm.get_data(dataset=dataset, subjects=[1])
+
+evaluation = WithinSessionEvaluation(
+    paradigm=paradigm, datasets=dataset, overwrite=False, suffix="newdataset"
+)
+pipelines = {}
+pipelines["MDM"] = make_pipeline(Covariances("oas"), MDM(metric="riemann"))
+scores = evaluation.process(pipelines)
+
+print(scores)
+
+
+
+
+

Pushing on MOABB Github#

+

If you want to make your dataset available to everyone, you could upload +your data on public server (like Zenodo or Figshare) and signal that you +want to add your dataset to MOABB in the dedicated issue. # noqa: E501 +You could then follow the instructions on how to contribute # noqa: E501

+

Total running time of the script: ( 0 minutes 0.000 seconds)

+

Estimated memory usage: 0 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_tutorials/index.html b/docs/auto_tutorials/index.html new file mode 100644 index 00000000..0fbf57f6 --- /dev/null +++ b/docs/auto_tutorials/index.html @@ -0,0 +1,746 @@ + + + + + + + + + + + + Getting Started — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Getting Started#

+
Tutorial 4: Creating a dataset class +

Tutorial 4: Creating a dataset class

+
Tutorial 4: Creating a dataset class
+
Tutorial 5: Creating a dataset class +

Tutorial 5: Creating a dataset class

+
Tutorial 5: Creating a dataset class
+
Tutorial 0: Getting Started +

Tutorial 0: Getting Started

+
Tutorial 0: Getting Started
+
Tutorial 1: Simple Motor Imagery +

Tutorial 1: Simple Motor Imagery

+
Tutorial 1: Simple Motor Imagery
+
Tutorial 2: Using multiple datasets +

Tutorial 2: Using multiple datasets

+
Tutorial 2: Using multiple datasets
+
Tutorial 3: Benchmarking multiple pipelines +

Tutorial 3: Benchmarking multiple pipelines

+
Tutorial 3: Benchmarking multiple pipelines
+
+
+ +

Gallery generated by Sphinx-Gallery

+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_tutorials/noplot_tutorial_5_build_a_custom_dataset.html b/docs/auto_tutorials/noplot_tutorial_5_build_a_custom_dataset.html new file mode 100644 index 00000000..d4b1b5de --- /dev/null +++ b/docs/auto_tutorials/noplot_tutorial_5_build_a_custom_dataset.html @@ -0,0 +1,870 @@ + + + + + + + + + + + + Tutorial 5: Creating a dataset class — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Tutorial 5: Creating a dataset class#

+
# Author: Gregoire Cattan
+#
+# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019
+
+from pyriemann.classification import MDM
+from pyriemann.estimation import ERPCovariances
+from sklearn.pipeline import make_pipeline
+
+from moabb.datasets import Cattan2019_VR
+from moabb.datasets.braininvaders import BI2014a
+from moabb.datasets.compound_dataset import CompoundDataset
+from moabb.datasets.utils import blocks_reps
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms.p300 import P300
+
+
+
+

Initialization#

+

This tutorial illustrates how to use the CompoundDataset to: +1) Select a few subjects/sessions/runs in an existing dataset +2) Merge two CompoundDataset into a new one +3) … and finally use this new dataset on a pipeline +(this steps is not specific to CompoundDataset)

+

Let’s define a paradigm and a pipeline for evaluation first.

+
paradigm = P300()
+pipelines = {}
+pipelines["MDM"] = make_pipeline(ERPCovariances(estimator="lwf"), MDM(metric="riemann"))
+
+
+
+
+

Creation a selection of subject#

+

We are going to great two CompoundDataset, namely CustomDataset1 & 2. +A CompoundDataset accepts a subjects_list of subjects. +It is a list of tuple. A tuple contains 4 values: +- the original dataset +- the subject number to select +- the sessions. It can be:

+
+
    +
  • a session name (‘0’)

  • +
  • a list of sessions ([‘0’, ‘1’])

  • +
  • None to select all the sessions attributed to a subject

  • +
+
+
    +
  • the runs. As for sessions, it can be a single run name, a list or None` (to select all runs).

  • +
+
class CustomDataset1(CompoundDataset):
+    def __init__(self):
+        biVR = Cattan2019_VR(virtual_reality=True, screen_display=True)
+        runs = blocks_reps([0, 2], [0, 1, 2, 3, 4], biVR.n_repetitions)
+        subjects_list = [
+            (biVR, 1, "0VR", runs),
+            (biVR, 2, "0VR", runs),
+        ]
+        CompoundDataset.__init__(
+            self,
+            subjects_list=subjects_list,
+            code="CustomDataset1",
+            interval=[0, 1.0],
+        )
+
+
+class CustomDataset2(CompoundDataset):
+    def __init__(self):
+        bi2014 = BI2014a()
+        subjects_list = [
+            (bi2014, 4, None, None),
+            (bi2014, 7, None, None),
+        ]
+        CompoundDataset.__init__(
+            self,
+            subjects_list=subjects_list,
+            code="CustomDataset2",
+            interval=[0, 1.0],
+        )
+
+
+
+
+

Merging the datasets#

+

We are now going to merge the two CompoundDataset into a single one. +The implementation is straight forward. Instead of providing a list of subjects, +you should provide a list of CompoundDataset. +subjects_list = [CustomDataset1(), CustomDataset2()]

+
class CustomDataset3(CompoundDataset):
+    def __init__(self):
+        subjects_list = [CustomDataset1(), CustomDataset2()]
+        CompoundDataset.__init__(
+            self,
+            subjects_list=subjects_list,
+            code="CustomDataset3",
+            interval=[0, 1.0],
+        )
+
+
+
+
+

Evaluate and display#

+

Let’s use a WithinSessionEvaluation to evaluate our new dataset. +If you already new how to do this, nothing changed: +The CompoundDataset can be used as a normal dataset.

+
datasets = [CustomDataset3()]
+evaluation = WithinSessionEvaluation(
+    paradigm=paradigm, datasets=datasets, overwrite=False, suffix="newdataset"
+)
+scores = evaluation.process(pipelines)
+
+print(scores)
+
+
+

Total running time of the script: ( 0 minutes 0.000 seconds)

+

Estimated memory usage: 0 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_tutorials/plot_Getting_Started.html b/docs/auto_tutorials/plot_Getting_Started.html new file mode 100644 index 00000000..85314c7a --- /dev/null +++ b/docs/auto_tutorials/plot_Getting_Started.html @@ -0,0 +1,979 @@ + + + + + + + + + + + + Tutorial 0: Getting Started — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Tutorial 0: Getting Started#

+

This tutorial takes you through a basic working example of how to use this +codebase, including all the different components, up to the results +generation. If you’d like to know about the statistics and plotting, see the +next tutorial.

+
# Authors: Vinay Jayaram <vinayjayaram13@gmail.com>
+#
+# License: BSD (3-clause)
+
+
+
+

Introduction#

+

To use the codebase you need an evaluation and a paradigm, some algorithms, +and a list of datasets to run it all on. You can find those in the following +submodules; detailed tutorials are given for each of them.

+
import numpy as np
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.model_selection import GridSearchCV
+from sklearn.pipeline import make_pipeline
+from sklearn.svm import SVC
+
+
+

If you would like to specify the logging level when it is running, you can +use the standard python logging commands through the top-level moabb module

+
import moabb
+from moabb.datasets import BNCI2014_001, utils
+from moabb.evaluations import CrossSessionEvaluation
+from moabb.paradigms import LeftRightImagery
+from moabb.pipelines.features import LogVariance
+
+
+

In order to create pipelines within a script, you will likely need at least +the make_pipeline function. They can also be specified via a .yml file. Here +we will make a couple pipelines just for convenience

+ +
+
+

Create pipelines#

+

We create two pipelines: channel-wise log variance followed by LDA, and +channel-wise log variance followed by a cross-validated SVM (note that a +cross-validation via scikit-learn cannot be described in a .yml file). For +later in the process, the pipelines need to be in a dictionary where the key +is the name of the pipeline and the value is the Pipeline object

+
pipelines = {}
+pipelines["AM+LDA"] = make_pipeline(LogVariance(), LDA())
+parameters = {"C": np.logspace(-2, 2, 10)}
+clf = GridSearchCV(SVC(kernel="linear"), parameters)
+pipe = make_pipeline(LogVariance(), clf)
+
+pipelines["AM+SVM"] = pipe
+
+
+
+
+

Datasets#

+

Datasets can be specified in many ways: Each paradigm has a property +‘datasets’ which returns the datasets that are appropriate for that paradigm

+ +
[<moabb.datasets.bnci.BNCI2014_001 object at 0x7fce0463cf40>, <moabb.datasets.bnci.BNCI2014_004 object at 0x7fce0463ce80>, <moabb.datasets.gigadb.Cho2017 object at 0x7fce0463c1c0>, <moabb.datasets.mpi_mi.GrosseWentrup2009 object at 0x7fce0463c190>, <moabb.datasets.Lee2019.Lee2019_MI object at 0x7fce0463cd00>, <moabb.datasets.physionet_mi.PhysionetMI object at 0x7fce0463c700>, <moabb.datasets.schirrmeister2017.Schirrmeister2017 object at 0x7fce0463cfd0>, <moabb.datasets.bbci_eeg_fnirs.Shin2017A object at 0x7fce0463c5e0>, <moabb.datasets.Weibo2014.Weibo2014 object at 0x7fce0463c370>, <moabb.datasets.Zhou2016.Zhou2016 object at 0x7fce0463ca90>]
+
+
+

Or you can run a search through the available datasets:

+
print(utils.dataset_search(paradigm="imagery", min_subjects=6))
+
+
+
[<moabb.datasets.alex_mi.AlexMI object at 0x7fce0463c7f0>, <moabb.datasets.bnci.BNCI2014_001 object at 0x7fce0463ce80>, <moabb.datasets.bnci.BNCI2014_002 object at 0x7fce0463cf10>, <moabb.datasets.bnci.BNCI2014_004 object at 0x7fce0463c9a0>, <moabb.datasets.bnci.BNCI2015_001 object at 0x7fce0463c9d0>, <moabb.datasets.bnci.BNCI2015_004 object at 0x7fce0463c310>, <moabb.datasets.gigadb.Cho2017 object at 0x7fce0463cbb0>, <moabb.datasets.fake.FakeDataset object at 0x7fce0463ce20>, <moabb.datasets.mpi_mi.GrosseWentrup2009 object at 0x7fce0463c850>, <moabb.datasets.Lee2019.Lee2019_MI object at 0x7fce0463c100>, <moabb.datasets.upper_limb.Ofner2017 object at 0x7fce0463cf40>, <moabb.datasets.physionet_mi.PhysionetMI object at 0x7fce0463c970>, <moabb.datasets.schirrmeister2017.Schirrmeister2017 object at 0x7fce0463c5b0>, <moabb.datasets.bbci_eeg_fnirs.Shin2017A object at 0x7fce0463c280>, <moabb.datasets.Weibo2014.Weibo2014 object at 0x7fce0463c940>]
+
+
+

Or you can simply make your own list (which we do here due to computational +constraints)

+ +
+
+

Paradigm#

+

Paradigms define the events, epoch time, bandpass, and other preprocessing +parameters. They have defaults that you can read in the documentation, or you +can simply set them as we do here. A single paradigm defines a method for +going from continuous data to trial data of a fixed size. To learn more look +at the tutorial Exploring Paradigms

+ +
+
+

Evaluation#

+

An evaluation defines how the training and test sets are chosen. This could +be cross-validated within a single recording, or across days, or sessions, or +subjects. This also is the correct place to specify multiple threads.

+
evaluation = CrossSessionEvaluation(
+    paradigm=paradigm, datasets=datasets, suffix="examples", overwrite=False
+)
+results = evaluation.process(pipelines)
+
+
+
BNCI2014-001-CrossSession:   0%|          | 0/2 [00:00<?, ?it/s]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-001-CrossSession:  50%|#####     | 1/2 [00:03<00:03,  3.36s/it]/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+/home/runner/work/moabb/moabb/moabb/datasets/preprocessing.py:273: UserWarning: warnEpochs <Epochs |  24 events (all good), 2 – 6 s, baseline off, ~4.1 MB, data loaded,
+ 'left_hand': 12
+ 'right_hand': 12>
+  warn(f"warnEpochs {epochs}")
+
+BNCI2014-001-CrossSession: 100%|##########| 2/2 [00:06<00:00,  3.33s/it]
+BNCI2014-001-CrossSession: 100%|##########| 2/2 [00:06<00:00,  3.34s/it]
+
+
+

Results are returned as a pandas DataFrame, and from here you can do as you +want with them

+
print(results.head())
+
+
+
      score      time  samples  ... n_sessions       dataset  pipeline
+0  0.797068  0.149245    144.0  ...          2  BNCI2014-001    AM+SVM
+1  0.773920  0.139139    144.0  ...          2  BNCI2014-001    AM+SVM
+2  0.550733  0.247906    144.0  ...          2  BNCI2014-001    AM+SVM
+3  0.471451  0.168360    144.0  ...          2  BNCI2014-001    AM+SVM
+4  0.786458  0.024171    144.0  ...          2  BNCI2014-001    AM+LDA
+
+[5 rows x 9 columns]
+
+
+

Total running time of the script: ( 0 minutes 9.886 seconds)

+

Estimated memory usage: 306 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_tutorials/sg_execution_times.html b/docs/auto_tutorials/sg_execution_times.html new file mode 100644 index 00000000..26ced3e2 --- /dev/null +++ b/docs/auto_tutorials/sg_execution_times.html @@ -0,0 +1,550 @@ + + + + + + + + + + + + Computation times — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Computation times#

+

01:41.204 total execution time for auto_tutorials files:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

Tutorial 3: Benchmarking multiple pipelines (tutorial_3_benchmarking_multiple_pipelines.py)

00:55.412

326.1 MB

Tutorial 1: Simple Motor Imagery (tutorial_1_simple_example_motor_imagery.py)

00:21.492

580.9 MB

Tutorial 2: Using multiple datasets (tutorial_2_using_mulitple_datasets.py)

00:14.414

207.7 MB

Tutorial 0: Getting Started (plot_Getting_Started.py)

00:09.886

305.8 MB

Tutorial 4: Creating a dataset class (4_adding_a_dataset.py)

00:00.000

0.0 MB

Tutorial 5: Creating a dataset class (noplot_tutorial_5_build_a_custom_dataset.py)

00:00.000

0.0 MB

+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_tutorials/tutorial_1_simple_example_motor_imagery.html b/docs/auto_tutorials/tutorial_1_simple_example_motor_imagery.html new file mode 100644 index 00000000..9a7795d5 --- /dev/null +++ b/docs/auto_tutorials/tutorial_1_simple_example_motor_imagery.html @@ -0,0 +1,931 @@ + + + + + + + + + + + + Tutorial 1: Simple Motor Imagery — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Tutorial 1: Simple Motor Imagery#

+

In this example, we will go through all the steps to make a simple BCI +classification task, downloading a dataset and using a standard classifier. We +choose the dataset 2a from BCI Competition IV, a motor imagery task. We will +use a CSP to enhance the signal-to-noise ratio of the EEG epochs and a LDA to +classify these signals.

+
# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier
+#
+# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019
+
+import warnings
+
+import matplotlib.pyplot as plt
+import pandas as pd
+import seaborn as sns
+from mne.decoding import CSP
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.pipeline import make_pipeline
+
+import moabb
+from moabb.datasets import BNCI2014_001
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import LeftRightImagery
+
+
+moabb.set_log_level("info")
+warnings.filterwarnings("ignore")
+
+
+
+

Instantiating Dataset#

+

The first thing to do is to instantiate the dataset that we want to analyze. +MOABB has a list of many different datasets, each one containing all the +necessary information for describing them, such as the number of subjects, +size of trials, names of classes, etc.

+

The dataset class has methods for:

+
    +
  • downloading its files from some online source (e.g. Zenodo)

  • +
  • importing the data from the files in whatever extension they might be +(like .mat, .gdf, etc.) and instantiate a Raw object from the MNE package

  • +
+ +
+
+

Accessing EEG Recording#

+

As an example, we may access the EEG recording from a given session and a +given run as follows:

+
sessions = dataset.get_data(subjects=[1])
+
+
+

This returns a MNE Raw object that can be manipulated. This might be enough +for some users, since the pre-processing and epoching steps can be easily +done via MNE. However, to conduct an assessment of several classifiers on +multiple subjects, MOABB ends up being a more appropriate option.

+ +
+
+

Choosing a Paradigm#

+

Once we have instantiated a dataset, we have to choose a paradigm. This +object is responsible for filtering the data, epoching it, and extracting +the labels for each epoch. Note that each dataset comes with the names of +the paradigms to which it might be associated. It would not make sense to +process a P300 dataset with a MI paradigm object.

+
+
+
imagery
+
+
+

For the example below, we will consider the paradigm associated to +left-hand/right-hand motor imagery task, but there are other options in +MOABB for motor imagery, P300 or SSVEP.

+ +

We may check the list of all datasets available in MOABB for using with this +paradigm (note that BNCI2014_001 is in it)

+ +
[<moabb.datasets.bnci.BNCI2014_001 object at 0x7fcdfc9c0fa0>, <moabb.datasets.bnci.BNCI2014_004 object at 0x7fcdfc9c0070>, <moabb.datasets.gigadb.Cho2017 object at 0x7fcdfc9c0130>, <moabb.datasets.mpi_mi.GrosseWentrup2009 object at 0x7fcdf4d4aa30>, <moabb.datasets.Lee2019.Lee2019_MI object at 0x7fcdfc9c0340>, <moabb.datasets.physionet_mi.PhysionetMI object at 0x7fcdfc9c09d0>, <moabb.datasets.schirrmeister2017.Schirrmeister2017 object at 0x7fcdfc9c0d00>, <moabb.datasets.bbci_eeg_fnirs.Shin2017A object at 0x7fcdfc9c0310>, <moabb.datasets.Weibo2014.Weibo2014 object at 0x7fcdfc9c05b0>, <moabb.datasets.Zhou2016.Zhou2016 object at 0x7fcdfc9c04c0>]
+
+
+

The data from a list of subjects could be preprocessed and return as a 3D +numpy array X, follow a scikit-like format with the associated labels. +The meta object contains all information regarding the subject, the +session and the run associated to each trial.

+
X, labels, meta = paradigm.get_data(dataset=dataset, subjects=[1])
+
+
+
+
+

Create Pipeline#

+

Our goal is to evaluate the performance of a given classification pipeline +(or several of them) when it is applied to the epochs from the previously +chosen dataset. We will consider a very simple classification pipeline in +which the dimension of the epochs are reduced via a CSP step and then +classified via a linear discriminant analysis.

+
pipeline = make_pipeline(CSP(n_components=8), LDA())
+
+
+
+
+

Evaluation#

+

To evaluate the score of this pipeline, we use the evaluation class. When +instantiating it, we say which paradigm we want to consider, a list with the +datasets to analyze, and whether the scores should be recalculated each time +we run the evaluation or if MOABB should create a cache file.

+

Note that there are different ways of evaluating a classifier; in this +example, we choose WithinSessionEvaluation, which consists of doing a +cross-validation procedure where the training and testing partitions are from +the same recording session of the dataset. We could have used +CrossSessionEvaluation, which takes all but one session as training +partition and the remaining one as testing partition.

+
evaluation = WithinSessionEvaluation(
+    paradigm=paradigm,
+    datasets=[dataset],
+    overwrite=True,
+    hdf5_path=None,
+)
+
+
+

We obtain the results in the form of a pandas dataframe

+
results = evaluation.process({"csp+lda": pipeline})
+
+
+
BNCI2014-001-WithinSession:   0%|          | 0/3 [00:00<?, ?it/s]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-001-WithinSession:  33%|###3      | 1/3 [00:04<00:09,  4.73s/it]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-001-WithinSession:  67%|######6   | 2/3 [00:09<00:04,  4.52s/it]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-001-WithinSession: 100%|##########| 3/3 [00:13<00:00,  4.68s/it]
+BNCI2014-001-WithinSession: 100%|##########| 3/3 [00:13<00:00,  4.66s/it]
+
+
+

The results are stored in locally, to avoid recomputing the results each time. +It is saved in hdf5_path if defined or in ~/mne_data/results otherwise. +To export the results in CSV:

+
results.to_csv("./results_part2-1.csv")
+
+
+

To load previously obtained results saved in CSV

+
results = pd.read_csv("./results_part2-1.csv")
+
+
+
+
+

Plotting Results#

+

We create a figure with the seaborn package comparing the classification +score for each subject on each session. Note that the ‘subject’ field from +the results is given in terms of integers, but seaborn accepts only +strings for its labeling. This is why we create the field ‘subj’.

+
fig, ax = plt.subplots(figsize=(8, 7))
+results["subj"] = results["subject"].apply(str)
+sns.barplot(
+    x="score", y="subj", hue="session", data=results, orient="h", palette="viridis", ax=ax
+)
+plt.show()
+
+
+tutorial 1 simple example motor imagery

Total running time of the script: ( 0 minutes 21.492 seconds)

+

Estimated memory usage: 581 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_tutorials/tutorial_2_using_mulitple_datasets.html b/docs/auto_tutorials/tutorial_2_using_mulitple_datasets.html new file mode 100644 index 00000000..220a4d10 --- /dev/null +++ b/docs/auto_tutorials/tutorial_2_using_mulitple_datasets.html @@ -0,0 +1,843 @@ + + + + + + + + + + + + Tutorial 2: Using multiple datasets — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Tutorial 2: Using multiple datasets#

+

We extend the previous example to a case where we want to analyze the score of +a classifier with three different MI datasets instead of just one. As before, +we begin by importing all relevant libraries.

+
# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier
+#
+# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019
+
+import warnings
+
+import matplotlib.pyplot as plt
+import mne
+import seaborn as sns
+from mne.decoding import CSP
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.pipeline import make_pipeline
+
+import moabb
+from moabb.datasets import BNCI2014_001, Zhou2016
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import LeftRightImagery
+
+
+moabb.set_log_level("info")
+mne.set_log_level("CRITICAL")
+warnings.filterwarnings("ignore")
+
+
+
+

Initializing Datasets#

+

We instantiate the two different datasets that follow the MI paradigm +(with left-hand/right-hand classes) but were recorded with different number +of electrodes, different number of trials, etc.

+
datasets = [Zhou2016(), BNCI2014_001()]
+subj = [1, 2, 3]
+for d in datasets:
+    d.subject_list = subj
+
+
+

The following lines go exactly as in the previous example, where we end up +obtaining a pandas dataframe containing the results of the evaluation. We +could set overwrite to False to cache the results, avoiding to restart all +the evaluation from scratch if a problem occurs.

+
+
+
Zhou2016-WithinSession:   0%|          | 0/3 [00:00<?, ?it/s]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+Zhou2016-WithinSession:  33%|###3      | 1/3 [00:04<00:09,  4.72s/it]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+Zhou2016-WithinSession:  67%|######6   | 2/3 [00:08<00:04,  4.26s/it]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+Zhou2016-WithinSession: 100%|##########| 3/3 [00:12<00:00,  4.12s/it]
+Zhou2016-WithinSession: 100%|##########| 3/3 [00:12<00:00,  4.20s/it]
+
+BNCI2014-001-WithinSession:   0%|          | 0/3 [00:00<?, ?it/s]
+BNCI2014-001-WithinSession:   0%|          | 0/3 [00:00<?, ?it/s]
+
+
+
+
+

Plotting Results#

+

We plot the results using the seaborn library. Note how easy it +is to plot the results from the three datasets with just one line.

+
results["subj"] = [str(resi).zfill(2) for resi in results["subject"]]
+g = sns.catplot(
+    kind="bar",
+    x="score",
+    y="subj",
+    col="dataset",
+    data=results,
+    orient="h",
+    palette="viridis",
+)
+plt.show()
+
+
+dataset = Zhou2016, dataset = BNCI2014-001

Total running time of the script: ( 0 minutes 14.414 seconds)

+

Estimated memory usage: 208 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/auto_tutorials/tutorial_3_benchmarking_multiple_pipelines.html b/docs/auto_tutorials/tutorial_3_benchmarking_multiple_pipelines.html new file mode 100644 index 00000000..90bb8f38 --- /dev/null +++ b/docs/auto_tutorials/tutorial_3_benchmarking_multiple_pipelines.html @@ -0,0 +1,882 @@ + + + + + + + + + + + + Tutorial 3: Benchmarking multiple pipelines — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + +
+

Tutorial 3: Benchmarking multiple pipelines#

+

In this last part, we extend the previous example by assessing the +classification score of not one but three classification pipelines.

+
# Authors: Pedro L. C. Rodrigues, Sylvain Chevallier
+#
+# https://github.com/plcrodrigues/Workshop-MOABB-BCI-Graz-2019
+
+import warnings
+
+import matplotlib.pyplot as plt
+import mne
+import seaborn as sns
+from mne.decoding import CSP
+from pyriemann.classification import MDM
+from pyriemann.estimation import Covariances
+from pyriemann.tangentspace import TangentSpace
+from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
+from sklearn.pipeline import make_pipeline
+from sklearn.svm import SVC
+
+import moabb
+from moabb.datasets import BNCI2014_001, Zhou2016
+from moabb.evaluations import WithinSessionEvaluation
+from moabb.paradigms import LeftRightImagery
+
+
+mne.set_log_level("CRITICAL")
+moabb.set_log_level("info")
+warnings.filterwarnings("ignore")
+
+
+
+

Creating Pipelines#

+

We instantiate the three different classiciation pipelines to be considered +in the analysis. The object that gathers each pipeline is a dictionary. The +first pipeline is the CSP+LDA that we have seen in the previous parts. The +other two pipelines rely on Riemannian geometry, using an SVM classification +in the tangent space of the covariance matrices estimated from the EEG or a +MDM classifier that works directly on covariance matrices.

+
pipelines = {}
+pipelines["csp+lda"] = make_pipeline(CSP(n_components=8), LDA())
+pipelines["tgsp+svm"] = make_pipeline(
+    Covariances("oas"), TangentSpace(metric="riemann"), SVC(kernel="linear")
+)
+pipelines["MDM"] = make_pipeline(Covariances("oas"), MDM(metric="riemann"))
+
+
+

The following lines go exactly as in the previous tutorial, where we end up +obtaining a pandas dataframe containing the results of the evaluation.

+ +
BNCI2014-001-WithinSession:   0%|          | 0/3 [00:00<?, ?it/s]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-001-WithinSession:  33%|###3      | 1/3 [00:09<00:19,  9.96s/it]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-001-WithinSession:  67%|######6   | 2/3 [00:19<00:09,  9.74s/it]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+BNCI2014-001-WithinSession: 100%|##########| 3/3 [00:29<00:00,  9.79s/it]
+BNCI2014-001-WithinSession: 100%|##########| 3/3 [00:29<00:00,  9.80s/it]
+
+Zhou2016-WithinSession:   0%|          | 0/3 [00:00<?, ?it/s]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+Zhou2016-WithinSession:  33%|###3      | 1/3 [00:08<00:16,  8.47s/it]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+Zhou2016-WithinSession:  67%|######6   | 2/3 [00:16<00:07,  7.92s/it]No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+No hdf5_path provided, models will not be saved.
+
+Zhou2016-WithinSession: 100%|##########| 3/3 [00:23<00:00,  7.63s/it]
+Zhou2016-WithinSession: 100%|##########| 3/3 [00:23<00:00,  7.77s/it]
+
+
+

As overwrite is set to False, the results from the previous tutorial are reused and +only the new pipelines are evaluated. The results from “csp+lda” are not recomputed. +The results are saved in ~/mne_data/results if the parameter hdf5_path is not set.

+
+
+

Plotting Results#

+

The following plot shows a comparison of the three classification pipelines +for each subject of each dataset.

+
results["subj"] = [str(resi).zfill(2) for resi in results["subject"]]
+g = sns.catplot(
+    kind="bar",
+    x="score",
+    y="subj",
+    hue="pipeline",
+    col="dataset",
+    height=12,
+    aspect=0.5,
+    data=results,
+    orient="h",
+    palette="viridis",
+)
+plt.show()
+
+
+dataset = BNCI2014-001, dataset = Zhou2016

Total running time of the script: ( 0 minutes 55.412 seconds)

+

Estimated memory usage: 326 MB

+ +

Gallery generated by Sphinx-Gallery

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/cite.html b/docs/cite.html new file mode 100644 index 00000000..ea8f3a55 --- /dev/null +++ b/docs/cite.html @@ -0,0 +1,561 @@ + + + + + + + + + + + + Citing MOABB and related publications — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + + + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/dataset_summary.html b/docs/dataset_summary.html new file mode 100644 index 00000000..019bb9d9 --- /dev/null +++ b/docs/dataset_summary.html @@ -0,0 +1,1193 @@ + + + + + + + + + + + + Data Summary — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

A dataset handle and abstract low level access to the data. the dataset will +takes data stored locally, in the format in which they have been downloaded, +and will convert them into a MNE raw object. There are options to pool all the +different recording sessions per subject or to evaluate them separately.

+

See NeuroTechX/moabb for detail +on datasets (electrodes, number of trials, sessions, etc.)

+
+

Data Summary#

+

MOABB gather many datasets, here is list summarizing important information. Most of the +datasets are listed here but this list not complete yet, check API for complete +documentation.

+

Do not hesitate to help us complete this list. It is also possible to add new datasets, +there is a tutorial explaining how to do so, and we welcome warmly any new contributions!

+

See also Datasets-Support for supplementary +detail on datasets (class name, size, licence, etc.)

+
+
+

Motor Imagery#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Dataset

#Subj

#Chan

#Classes

#Trials

Trial length

Freq

#Session

#Runs

Total_trials

AlexMI

8

16

3

20

3s

512Hz

1

1

480

BNCI2014_001

9

22

4

144

4s

250Hz

2

6

62208

BNCI2014_002

14

15

2

80

5s

512Hz

1

8

17920

BNCI2014_004

9

3

2

360

4.5s

250Hz

5

1

32400

BNCI2015_001

12

13

2

200

5s

512Hz

3

1

14400

BNCI2015_004

9

30

5

80

7s

256Hz

2

1

7200

Cho2017

52

64

2

100

3s

512Hz

1

1

9800

Lee2019_MI

54

62

2

100

4s

1000Hz

2

1

11000

GrosseWentrup2009

10

128

2

150

7s

500Hz

1

1

3000

Schirrmeister2017

14

128

4

120

4s

500Hz

1

2

13440

Ofner2017

15

61

7

60

3s

512Hz

1

10

63000

PhysionetMI

109

64

4

23

3s

160Hz

1

1

69760

Shin2017A

29

30

2

30

10s

200Hz

3

1

5220

Shin2017B

29

30

2

30

10s

200Hz

3

1

5220

Weibo2014

10

60

7

80

4s

200Hz

1

1

5600

Zhou2016

4

14

3

160

5s

250Hz

3

2

11496

+
+
+

P300/ERP#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Dataset

#Subj

#Chan

#Trials / class

Trials length

Sampling rate

#Sessions

BNCI2014_008

8

8

3500 NT / 700 T

1s

256Hz

1

BNCI2014_009

10

16

1440 NT / 288 T

0.8s

256Hz

3

BNCI2015_003

10

8

1500 NT / 300 T

0.8s

256Hz

1

BI2012

25

16

640 NT / 128 T

1s

128Hz

2

BI2013a

24

16

3200 NT / 640 T

1s

512Hz

8 for subjects 1-7 else 1

BI2014a

64

16

990 NT / 198 T

1s

512Hz

up to 3

BI2014b

38

32

200 NT / 40 T

1s

512Hz

3

BI2015a

43

32

4131 NT / 825 T

1s

512Hz

3

BI2015b

44

32

2160 NT / 480 T

1s

512Hz

1

Cattan2019_VR

21

16

600 NT / 120 T

1s

512Hz

2

Huebner2017

13

31

364 NT / 112 T

0.9s

1000Hz

3

Huebner2018

12

31

364 NT / 112 T

0.9s

1000Hz

3

Sosulski2019

13

31

7500 NT / 1500 T

1.2s

1000Hz

1

EPFLP300

8

32

2753 NT / 551 T

1s

2048Hz

4

Lee2019_ERP

54

62

6900 NT / 1380 T

1s

1000Hz

2

+
+
+

SSVEP#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Dataset

#Subj

#Chan

#Classes

#Trials / class

Trials length

Sampling rate

#Sessions

Lee2019_SSVEP

54

62

4

50

4s

1000Hz

2

Kalunga2016

12

8

4

16

2s

256Hz

1

MAMEM1

10

256

5

12-15

3s

250Hz

1

MAMEM2

10

256

5

20-30

3s

250Hz

1

MAMEM3

10

14

4

20-30

3s

128Hz

1

Nakanishi2015

9

8

12

15

4.15s

256Hz

1

Wang2016

34

62

40

6

5s

250Hz

1

+
+
+

c-VEP#

+

Include neuro experiments where the participant is presented with psuedo-random noise-codes, +such as m-sequences, Gold codes, or any arbitrary “pseudo-random” code. Specifically, the +difference with SSVEP is that SSVEP presents periodic stimuli, while c-VEP presents +non-periodic stimuli. For a review of c-VEP BCI, see:

+

Martínez-Cagigal, V., Thielen, J., Santamaria-Vazquez, E., Pérez-Velasco, S., Desain, P.,& +Hornero, R. (2021). Brain–computer interfaces based on code-modulated visual evoked +potentials (c-VEP): A literature review. Journal of Neural Engineering, 18(6), 061002. +DOI: https://doi.org/10.1088/1741-2552/ac38cf

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Dataset

#Subj

#Sessions

Sampling rate

#Chan

Trials length

#Trial classes

#Trials / class

#Epochs classes

#Epochs / class

Codes

Presentation rate

Thielen2015

12

1

2048Hz

64

4.2s

36

3

2

27216 NT / 27216 T

Gold codes

120Hz

Thielen2021

30

1

512Hz

8

31.5s

20

5

2

18900 NT / 18900 T

Gold codes

60Hz

CastillosCVEP100

12

1

500Hz

32

2.2s

4

15/15/15/15

2

3525 NT / 3495 T

m-sequence

60Hz

CastillosCVEP40

12

1

500Hz

32

2.2s

4

15/15/15/15

2

3525 NT / 3495 T

m-sequence

60Hz

CastillosBurstVEP40

12

1

500Hz

32

2.2s

4

15/15/15/15

2

5820 NT / 1200 T

Burst-CVEP

60Hz

CastillosBurstVEP100

12

1

500Hz

32

2.2s

4

15/15/15/15

2

5820 NT / 1200 T

Burst-CVEP

60Hz

+
+
+

Resting States#

+

Include neuro experiments where the participant is not actively doing something. +For example, recoding the EEG of a subject while s/he is having the eye closed or opened +is a resting state experiment.

+ + + + + + + + + + + + + + + + + + + + + + + +

Dataset

#Subj

#Chan

#Classes

#Blocks / class

Trials length

Sampling rate

#Sessions

Cattan2019_PHMD

12

16

2

10

60s

512Hz

1

+
+
+

Compound Datasets#

+

Compound Datasets are datasets compounded with subjects from other datasets. +It is useful for merging different datasets (including other Compound Datasets), +select a sample of subject inside a dataset (e.g. subject with high/low performance).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Dataset

#Subj

#Original datasets

BI2014a_Il

17

BI2014a

BI2014b_Il

11

BI2014b

BI2015a_Il

2

BI2015a

BI2015b_Il

25

BI2015b

Cattan2019_VR_Il

4

Cattan2019_VR

BI_Il

59

BI2014a_Il BI2014b_Il BI2015a_Il BI2015b_Il Cattan2019_VR_Il

+
+

Submit a new dataset#

+

you can submit a new dataset by mentioning it to this +issue. The datasets +currently on our radar can be seen here, +but we are open to any suggestion.

+

If you want to actively contribute to inclusion of one new dataset, you can follow also this tutorial +tutorial.

+ +
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/datasets.html b/docs/datasets.html new file mode 100644 index 00000000..ecb6a78e --- /dev/null +++ b/docs/datasets.html @@ -0,0 +1,811 @@ + + + + + + + + + + + + Datasets — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Datasets#

+

A dataset handle and abstract low level access to the data. the dataset will +takes data stored locally, in the format in which they have been downloaded, +and will convert them into a MNE raw object. There are options to pool all the +different recording sessions per subject or to evaluate them separately.

+

See NeuroTechX/moabb for detail +on datasets (electrodes, number of trials, sessions, etc.)

+
+

Motor Imagery Datasets#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

AlexMI()

Alex Motor Imagery dataset.

BNCI2014_001()

BNCI 2014-001 Motor Imagery dataset.

BNCI2014_002()

BNCI 2014-002 Motor Imagery dataset.

BNCI2014_004()

BNCI 2014-004 Motor Imagery dataset.

BNCI2015_001()

BNCI 2015-001 Motor Imagery dataset.

BNCI2015_004()

BNCI 2015-004 Motor Imagery dataset.

Cho2017()

Motor Imagery dataset from Cho et al 2017.

Lee2019_MI([train_run, test_run, ...])

BMI/OpenBMI dataset for MI.

GrosseWentrup2009()

Munich Motor Imagery dataset.

Ofner2017([imagined, executed])

Motor Imagery ataset from Ofner et al 2017.

PhysionetMI([imagined, executed])

Physionet Motor Imagery dataset.

Schirrmeister2017()

High-gamma dataset described in Schirrmeister et al. 2017.

Shin2017A([accept])

Motor Imagey Dataset from Shin et al 2017.

Shin2017B([accept])

Mental Arithmetic Dataset from Shin et al 2017.

Weibo2014()

Motor Imagery dataset from Weibo et al 2014.

Zhou2016()

Motor Imagery dataset from Zhou et al 2016.

+
+
+

ERP Datasets#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

BI2012([Training, Online])

P300 dataset BI2012 from a "Brain Invaders" experiment.

BI2013a([NonAdaptive, Adaptive, Training, ...])

P300 dataset BI2013a from a "Brain Invaders" experiment.

BI2014a()

P300 dataset BI2014a from a "Brain Invaders" experiment.

BI2014b()

P300 dataset BI2014b from a "Brain Invaders" experiment.

BI2015a()

P300 dataset BI2015a from a "Brain Invaders" experiment.

BI2015b()

P300 dataset BI2015b from a "Brain Invaders" experiment.

Cattan2019_VR([virtual_reality, screen_display])

Dataset of an EEG-based BCI experiment in Virtual Reality using P300.

BNCI2014_008()

BNCI 2014-008 P300 dataset.

BNCI2014_009()

BNCI 2014-009 P300 dataset.

BNCI2015_003()

BNCI 2015-003 P300 dataset.

DemonsP300()

Visual P300 dataset recorded in Virtual Reality (VR) game Raccoons versus Demons.

EPFLP300()

P300 dataset from Hoffmann et al 2008.

Huebner2017([interval, raw_slice_offset, ...])

Learning from label proportions for a visual matrix speller (ERP) dataset from Hübner et al 2017 [R0a211c89d39d-1].

Huebner2018([interval, raw_slice_offset, ...])

Mixture of LLP and EM for a visual matrix speller (ERP) dataset from Hübner et al 2018 [R8f30fc0d0ace-1].

Lee2019_ERP([train_run, test_run, ...])

BMI/OpenBMI dataset for P300.

Sosulski2019([use_soas_as_sessions, ...])

P300 dataset from initial spot study.

+
+
+

SSVEP Datasets#

+ + + + + + + + + + + + + + + + + + + + + + + + +

Kalunga2016()

SSVEP Exo dataset.

Nakanishi2015()

SSVEP Nakanishi 2015 dataset.

Wang2016()

SSVEP Wang 2016 dataset.

MAMEM1()

SSVEP MAMEM 1 dataset.

MAMEM2()

SSVEP MAMEM 2 dataset.

MAMEM3()

SSVEP MAMEM 3 dataset.

Lee2019_SSVEP([train_run, test_run, ...])

BMI/OpenBMI dataset for SSVEP.

+
+
+

c-VEP Datasets#

+ + + + + + + + + + + + + + + + + + + + + +

Thielen2015()

c-VEP dataset from Thielen et al. (2015).

Thielen2021()

c-VEP dataset from Thielen et al. (2021).

CastillosBurstVEP40()

c-VEP and Burst-VEP dataset from Castillos et al. (2023).

CastillosBurstVEP100()

c-VEP and Burst-VEP dataset from Castillos et al. (2023).

CastillosCVEP40()

c-VEP and Burst-VEP dataset from Castillos et al. (2023).

CastillosCVEP100()

c-VEP and Burst-VEP dataset from Castillos et al. (2023).

+
+
+

Resting State Datasets#

+ + + + + + +

Cattan2019_PHMD()

Passive Head Mounted Display with Music Listening dataset.

+
+
+

Base & Utils#

+ + + + + + + + + + + + + + + +

base.BaseDataset(subjects, ...[, doi, ...])

Abstract Moabb BaseDataset.

base.CacheConfig([save_raw, save_epochs, ...])

Configuration for caching of datasets.

fake.FakeDataset([event_list, n_sessions, ...])

Fake Dataset for test purpose.

fake.FakeVirtualRealityDataset([seed])

Fake Cattan2019_VR dataset for test purpose.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

download.data_path(url, sign[, path, ...])

Get path to local copy of given dataset URL.

download.data_dl(url, sign[, path, ...])

Download file from url to specified path.

download.fs_issue_request(method, url, headers)

Wrapper for HTTP request.

download.fs_get_file_list(article_id[, version])

List all the files associated with a given article.

download.fs_get_file_hash(filelist)

Returns a dict associating figshare file id to MD5 hash.

download.fs_get_file_id(filelist)

Returns a dict associating filename to figshare file id.

download.fs_get_file_name(filelist)

Returns a dict associating figshare file id to filename.

utils.dataset_search([paradigm, ...])

Returns a list of datasets that match a given criteria.

utils.find_intersecting_channels(datasets[, ...])

Given a list of dataset instances return a list of channels shared by all datasets.

+
+
+
+

Compound Datasets#

+
+

ERP Datasets#

+ + + + + + + + + + + + + + + + + + + + + +

BI2014a_Il()

A selection of subject from BI2014a with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

BI2014b_Il()

A selection of subject from BI2014b with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

BI2015a_Il()

A selection of subject from BI2015a with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

BI2015b_Il()

A selection of subject from BI2015b with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

Cattan2019_VR_Il()

A selection of subject from Cattan2019_VR with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

BI_Il()

Subjects from braininvaders datasets with AUC < 0.7 with pipeline: ERPCovariances(estimator="lwf"), MDM(metric="riemann")

+
+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/evaluations.html b/docs/evaluations.html new file mode 100644 index 00000000..1fbe4935 --- /dev/null +++ b/docs/evaluations.html @@ -0,0 +1,570 @@ + + + + + + + + + + + + Evaluations — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Evaluations#

+

An evaluation defines how we go from trials per subject and session to a +generalization statistic (AUC score, f-score, accuracy, etc) – it can be +either within-recording-session accuracy, across-session within-subject +accuracy, across-subject accuracy, or other transfer learning settings.

+
+

Evaluations#

+ + + + + + + + + + + + +

WithinSessionEvaluation([n_perms, data_size])

Performance evaluation within session (k-fold cross-validation)

CrossSessionEvaluation(paradigm[, datasets, ...])

Cross-session performance evaluation.

CrossSubjectEvaluation(paradigm[, datasets, ...])

Cross-subject evaluation performance.

+
+
+

Base & Utils#

+ + + + + + +

base.BaseEvaluation(paradigm[, datasets, ...])

Base class that defines necessary operations for an evaluation.

+
+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.analysis.meta_analysis.collapse_session_scores.html b/docs/generated/moabb.analysis.meta_analysis.collapse_session_scores.html new file mode 100644 index 00000000..cbd91f13 --- /dev/null +++ b/docs/generated/moabb.analysis.meta_analysis.collapse_session_scores.html @@ -0,0 +1,756 @@ + + + + + + + + + + + + moabb.analysis.meta_analysis.collapse_session_scores — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.analysis.meta_analysis.collapse_session_scores#

+
+
+moabb.analysis.meta_analysis.collapse_session_scores(df)[source]#
+

Prepare results dataframe for computing statistics.

+
+
Parameters:
+

df (DataFrame) – results from evaluation

+
+
Returns:
+

df – Aggregated results, samples are index, columns are pipelines, +and values are scores

+
+
Return type:
+

DataFrame

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.analysis.meta_analysis.combine_effects.html b/docs/generated/moabb.analysis.meta_analysis.combine_effects.html new file mode 100644 index 00000000..ad88db4e --- /dev/null +++ b/docs/generated/moabb.analysis.meta_analysis.combine_effects.html @@ -0,0 +1,760 @@ + + + + + + + + + + + + moabb.analysis.meta_analysis.combine_effects — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.analysis.meta_analysis.combine_effects#

+
+
+moabb.analysis.meta_analysis.combine_effects(effects, nsubs)[source]#
+

Combine effects for meta-analysis statistics.

+

Function that takes effects from each experiments and number of subjects to +return meta-analysis effect

+
+
Parameters:
+
    +
  • effects (DataFrame) – effects for 2 pipelines computed on different datasets

  • +
  • nsubs (float) – average number of subject per datasets

  • +
+
+
Returns:
+

effect – Estimatation of the combined effects

+
+
Return type:
+

float

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.analysis.meta_analysis.combine_pvalues.html b/docs/generated/moabb.analysis.meta_analysis.combine_pvalues.html new file mode 100644 index 00000000..54e7f49b --- /dev/null +++ b/docs/generated/moabb.analysis.meta_analysis.combine_pvalues.html @@ -0,0 +1,760 @@ + + + + + + + + + + + + moabb.analysis.meta_analysis.combine_pvalues — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.analysis.meta_analysis.combine_pvalues#

+
+
+moabb.analysis.meta_analysis.combine_pvalues(p, nsubs)[source]#
+

Combine p-values for meta-analysis statistics.

+

Function that takes pvals from each experiments and number of subjects to +return meta-analysis significance using Stouffer’s method

+
+
Parameters:
+
    +
  • p (DataFrame) – p-values for 2 pipelines computed on different datasets

  • +
  • nsubs (float) – average number of subject per datasets

  • +
+
+
Returns:
+

pval – Estimatation of the combined p-value

+
+
Return type:
+

float

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.analysis.meta_analysis.compute_dataset_statistics.html b/docs/generated/moabb.analysis.meta_analysis.compute_dataset_statistics.html new file mode 100644 index 00000000..0d7eec3b --- /dev/null +++ b/docs/generated/moabb.analysis.meta_analysis.compute_dataset_statistics.html @@ -0,0 +1,758 @@ + + + + + + + + + + + + moabb.analysis.meta_analysis.compute_dataset_statistics — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.analysis.meta_analysis.compute_dataset_statistics#

+
+
+moabb.analysis.meta_analysis.compute_dataset_statistics(df, perm_cutoff=20)[source]#
+

Compute meta-analysis statistics from results dataframe.

+
+
Parameters:
+
    +
  • df (DataFrame) – results obtained by an evaluation

  • +
  • perm_cutoff (int, default=20) – threshold value for using permutation or Wilcoxon tests

  • +
+
+
Returns:
+

stats – Table of effect and p-values for each dataset and all pipelines

+
+
Return type:
+

DataFrame

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.analysis.meta_analysis.find_significant_differences.html b/docs/generated/moabb.analysis.meta_analysis.find_significant_differences.html new file mode 100644 index 00000000..33d99891 --- /dev/null +++ b/docs/generated/moabb.analysis.meta_analysis.find_significant_differences.html @@ -0,0 +1,763 @@ + + + + + + + + + + + + moabb.analysis.meta_analysis.find_significant_differences — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.analysis.meta_analysis.find_significant_differences#

+
+
+moabb.analysis.meta_analysis.find_significant_differences(df, perm_cutoff=20)[source]#
+

Compute differences between pipelines across datasets.

+

Compute matrices of p-values and effects for all algorithms over all datasets via +combined p-values and combined effects methods

+
+
Parameters:
+
    +
  • df (DataFrame) – Table of effect and p-values for each dataset and all pipelines, returned by +compute_dataset_statistics

  • +
  • perm_cutoff (int, default=20) – threshold value to stop using permutation tests, which can be very expensive +computationally, using Wilcoxon rank-sum test instead

  • +
+
+
Returns:
+

    +
  • dfP (DataFrame of shape (n_pipelines, n_pipelines)) – p-values per algorithm pairs

  • +
  • dfT (DataFrame of shape (n_pipelines, n_pipelines)) – signed standardized mean differences

  • +
+

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.analysis.plotting.meta_analysis_plot.html b/docs/generated/moabb.analysis.plotting.meta_analysis_plot.html new file mode 100644 index 00000000..a92b1602 --- /dev/null +++ b/docs/generated/moabb.analysis.plotting.meta_analysis_plot.html @@ -0,0 +1,769 @@ + + + + + + + + + + + + moabb.analysis.plotting.meta_analysis_plot — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.analysis.plotting.meta_analysis_plot#

+
+
+moabb.analysis.plotting.meta_analysis_plot(stats_df, alg1, alg2)[source]#
+

Meta-analysis to compare two algorithms across several datasets.

+

A meta-analysis style plot that shows the standardized effect with +confidence intervals over all datasets for two algorithms. +Hypothesis is that alg1 is larger than alg2

+
+
Parameters:
+
    +
  • stats_df (DataFrame) – DataFrame generated by compute_dataset_statistics

  • +
  • alg1 (str) – Name of first pipeline

  • +
  • alg2 (str) – Name of second pipeline

  • +
+
+
Returns:
+

fig – Pyplot handle

+
+
Return type:
+

Figure

+
+
+
+ +
+

Examples using moabb.analysis.plotting.meta_analysis_plot#

+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.analysis.plotting.paired_plot.html b/docs/generated/moabb.analysis.plotting.paired_plot.html new file mode 100644 index 00000000..d9a4bdd8 --- /dev/null +++ b/docs/generated/moabb.analysis.plotting.paired_plot.html @@ -0,0 +1,772 @@ + + + + + + + + + + + + moabb.analysis.plotting.paired_plot — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.analysis.plotting.paired_plot#

+
+
+moabb.analysis.plotting.paired_plot(data, alg1, alg2)[source]#
+

Generate a figure with a paired plot.

+
+
Parameters:
+
    +
  • data (DataFrame) – dataframe obtained from evaluation

  • +
  • alg1 (str) – Name of a member of column data.pipeline

  • +
  • alg2 (str) – Name of a member of column data.pipeline

  • +
+
+
Returns:
+

fig – Pyplot handle

+
+
Return type:
+

Figure

+
+
+
+ +
+

Examples using moabb.analysis.plotting.paired_plot#

+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.analysis.plotting.score_plot.html b/docs/generated/moabb.analysis.plotting.score_plot.html new file mode 100644 index 00000000..b50791fb --- /dev/null +++ b/docs/generated/moabb.analysis.plotting.score_plot.html @@ -0,0 +1,779 @@ + + + + + + + + + + + + moabb.analysis.plotting.score_plot — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.analysis.plotting.score_plot#

+
+
+moabb.analysis.plotting.score_plot(data, pipelines=None, orientation='vertical')[source]#
+

Plot scores for all pipelines and all datasets

+
+
Parameters:
+
    +
  • data (output of Results.to_dataframe()) – results on datasets

  • +
  • pipelines (list of str | None) – pipelines to include in this plot

  • +
  • orientation (str, default="vertical") – plot orientation, could be [“vertical”, “v”, “horizontal”, “h”]

  • +
+
+
Returns:
+

    +
  • fig (Figure) – Pyplot handle

  • +
  • color_dict (dict) – Dictionary with the facecolor

  • +
+

+
+
+
+ +
+

Examples using moabb.analysis.plotting.score_plot#

+
Examples of how to use MOABB to benchmark pipelines. +

Examples of how to use MOABB to benchmark pipelines.

+
Examples of how to use MOABB to benchmark pipelines.
+
Benchmarking on MOABB with Tensorflow deep net architectures +

Benchmarking on MOABB with Tensorflow deep net architectures

+
Benchmarking on MOABB with Tensorflow deep net architectures
+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures +

Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures

+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures
+
Benchmarking with MOABB with Grid Search +

Benchmarking with MOABB with Grid Search

+
Benchmarking with MOABB with Grid Search
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.analysis.plotting.summary_plot.html b/docs/generated/moabb.analysis.plotting.summary_plot.html new file mode 100644 index 00000000..4786df29 --- /dev/null +++ b/docs/generated/moabb.analysis.plotting.summary_plot.html @@ -0,0 +1,770 @@ + + + + + + + + + + + + moabb.analysis.plotting.summary_plot — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.analysis.plotting.summary_plot#

+
+
+moabb.analysis.plotting.summary_plot(sig_df, effect_df, p_threshold=0.05, simplify=True)[source]#
+

Significance matrix to compare pipelines.

+

Visualize significances as a heatmap with green/grey/red for significantly +higher/significantly lower.

+
+
Parameters:
+
    +
  • sig_df (DataFrame) – DataFrame of pipeline x pipeline where each value is a p-value,

  • +
  • effect_df (DataFrame) – DataFrame where each value is an effect size

  • +
+
+
Returns:
+

fig – Pyplot handle

+
+
Return type:
+

Figure

+
+
+
+ +
+

Examples using moabb.analysis.plotting.summary_plot#

+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.benchmark.html b/docs/generated/moabb.benchmark.html new file mode 100644 index 00000000..1af1d841 --- /dev/null +++ b/docs/generated/moabb.benchmark.html @@ -0,0 +1,641 @@ + + + + + + + + + + + + moabb.benchmark — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.benchmark#

+
+
+moabb.benchmark(pipelines='./pipelines/', evaluations=None, paradigms=None, results='./results/', overwrite=False, output='./benchmark/', n_jobs=-1, n_jobs_evaluation=1, plot=False, contexts=None, include_datasets=None, exclude_datasets=None)[source]#
+

Run benchmarks for selected pipelines and datasets.

+

Load from saved pipeline configurations to determine associated paradigms. It is +possible to include or exclude specific datasets and to choose the type of +evaluation.

+

If particular paradigms are mentioned through select_paradigms, only the pipelines corresponding to those paradigms +will be run. If no paradigms are mentioned, all pipelines will be run.

+

Pipelines stored in a file named braindecode_xxx.py will be recognized as Braindecode architectures +and they will receive epochs as input, instead of numpy array.

+

To define the include_datasets or exclude_dataset, you could start from the full dataset list, +using for example the following code: +> # Choose your paradigm +> p = moabb.paradigms.SSVEP() +> # Get the class names +> print(p.datasets) +> # Get the dataset code +> print([d.code for d in p.datasets])

+
+
Parameters:
+
    +
  • pipelines (str) – Folder containing the pipelines to evaluate

  • +
  • evaluations (list of str) – If to restrict the types of evaluations to be run. By default, all 3 base types are run +Can be a list of these elements [“WithinSession”, “CrossSession”, “CrossSubject”]

  • +
  • paradigms (list of str) – To restrict the paradigms on which evaluations should be run. +Can be a list of these elements [‘LeftRightImagery’, ‘MotorImagery’, ‘FilterBankSSVEP’, ‘SSVEP’, +‘FilterBankMotorImagery’]

  • +
  • results (str) – Folder to store the results

  • +
  • overwrite (bool) – Force evaluation of cached pipelines

  • +
  • output (str) – Folder to store the analysis results

  • +
  • n_jobs (int) – Number of threads to use for running parallel jobs

  • +
  • n_jobs_evaluation (int, default=1) – Number of jobs for evaluation, processing in parallel the within session, +cross-session or cross-subject.

  • +
  • plot (bool) – Plot results after computing

  • +
  • contexts (str) – File path to context.yml file that describes context parameters. +If none, assumes all defaults. Must contain an entry for all +paradigms described in the pipelines.

  • +
  • include_datasets (list of str or Dataset object) – Datasets (dataset.code or object) to include in the benchmark run. +By default, all suitable datasets are included. If both include_datasets +and exclude_datasets are specified, raise an error.

  • +
  • exclude_datasets (list of str or Dataset object) – Datasets to exclude from the benchmark run

  • +
+
+
Returns:
+

eval_results – Results of benchmark for all considered paradigms

+
+
Return type:
+

DataFrame

+
+
+

Notes

+
+

New in version 0.5.0.

+
+
+ +
+

Examples using moabb.benchmark#

+
Benchmarking with MOABB showing the CO2 footprint +

Benchmarking with MOABB showing the CO2 footprint

+
Benchmarking with MOABB showing the CO2 footprint
+
Examples of how to use MOABB to benchmark pipelines. +

Examples of how to use MOABB to benchmark pipelines.

+
Examples of how to use MOABB to benchmark pipelines.
+
Benchmarking on MOABB with Tensorflow deep net architectures +

Benchmarking on MOABB with Tensorflow deep net architectures

+
Benchmarking on MOABB with Tensorflow deep net architectures
+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures +

Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures

+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures
+
Benchmarking with MOABB with Grid Search +

Benchmarking with MOABB with Grid Search

+
Benchmarking with MOABB with Grid Search
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.AlexMI.html b/docs/generated/moabb.datasets.AlexMI.html new file mode 100644 index 00000000..e7149f72 --- /dev/null +++ b/docs/generated/moabb.datasets.AlexMI.html @@ -0,0 +1,660 @@ + + + + + + + + + + + + moabb.datasets.AlexMI — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.AlexMI#

+
+
+class moabb.datasets.AlexMI[source]#
+

Alex Motor Imagery dataset.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

AlexMI

8

16

3

20

3s

512Hz

1

+
+

Motor imagery dataset from the PhD dissertation of A. Barachant [1].

+

This Dataset contains EEG recordings from 8 subjects, performing 2 task of +motor imagination (right hand, feet or rest). Data have been recorded at +512Hz with 16 wet electrodes (Fpz, F7, F3, Fz, F4, F8, T7, C3, Cz, C4, T8, +P7, P3, Pz, P4, P8) with a g.tec g.USBamp EEG amplifier.

+

File are provided in MNE raw file format. A stimulation channel encoding +the timing of the motor imagination. The start of a trial is encoded as 1, +then the actual start of the motor imagination is encoded with 2 for +imagination of a right hand movement, 3 for imagination of both feet +movement and 4 with a rest trial.

+

The duration of each trial is 3 second. There is 20 trial of each class.

+

References

+
+
+[1] +

Barachant, A., 2012. Commande robuste d’un effecteur par une +interface cerveau machine EEG asynchrone (Doctoral dissertation, +Université de Grenoble). +https://tel.archives-ouvertes.fr/tel-01196752

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+

Examples using moabb.datasets.AlexMI#

+
Convert a MOABB dataset to BIDS +

Convert a MOABB dataset to BIDS

+
Convert a MOABB dataset to BIDS
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BI2012.html b/docs/generated/moabb.datasets.BI2012.html new file mode 100644 index 00000000..1be66561 --- /dev/null +++ b/docs/generated/moabb.datasets.BI2012.html @@ -0,0 +1,646 @@ + + + + + + + + + + + + moabb.datasets.BI2012 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BI2012#

+
+
+class moabb.datasets.BI2012(Training=True, Online=False)[source]#
+

P300 dataset BI2012 from a “Brain Invaders” experiment.

+

Dataset following the setup from [1] carried-out at University of +Grenoble Alpes.

+

This dataset contains electroencephalographic (EEG) recordings of 25 subjects testing +the Brain Invaders, a visual P300 Brain-Computer Interface inspired by the famous vintage +video game Space Invaders (Taito, Tokyo, Japan). The visual P300 is an event-related +potential elicited by a visual stimulation, peaking 240-600 ms after stimulus onset. EEG +data were recorded by 16 electrodes in an experiment that took place in the GIPSA-lab, +Grenoble, France, in 2012). A full description of the experiment is available in [1].

+
+
Principal Investigator:
+

B.Sc. Gijsbrecht Franciscus Petrus Van Veen

+
+
Technical Supervisors:
+

Ph.D. Alexandre Barachant, Eng. Anton Andreev, Eng. Grégoire Cattan, +Eng. Pedro. L. C. Rodrigues

+
+
Scientific Supervisor:
+

Ph.D. Marco Congedo

+
+
ID of the dataset:
+

BI.EEG.2012-GIPSA

+
+
+

Notes

+
+

Note

+

BI2012 was previously named bi2012. bi2012 will be removed in version 1.1.

+
+
+

New in version 0.4.6.

+
+

References

+
+
+[1] +(1,2) +

Van Veen, G., Barachant, A., Andreev, A., Cattan, G., Rodrigues, P. C., & +Congedo, M. (2019). Building Brain Invaders: EEG data of an experimental validation. +arXiv preprint arXiv:1905.05182.

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BI2013a.html b/docs/generated/moabb.datasets.BI2013a.html new file mode 100644 index 00000000..1a74e0ad --- /dev/null +++ b/docs/generated/moabb.datasets.BI2013a.html @@ -0,0 +1,709 @@ + + + + + + + + + + + + moabb.datasets.BI2013a — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BI2013a#

+
+
+class moabb.datasets.BI2013a(NonAdaptive=True, Adaptive=False, Training=True, Online=False)[source]#
+

P300 dataset BI2013a from a “Brain Invaders” experiment.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Trials / class

Trials length

Sampling rate

#Sessions

BI2013a

24

16

3200 NT / 640 T

1s

512Hz

(1-7)8 s|(8-24)1s

+
+

Dataset following the setup from [1] carried-out at University of +Grenoble Alpes.

+

This dataset concerns an experiment carried out at GIPSA-lab +(University of Grenoble Alpes, CNRS, Grenoble-INP) in 2013. +The recordings concerned 24 subjects in total. Subjects 1 to 7 participated +to eight sessions, run in different days, subject 8 to 24 participated to +one session. Each session consisted in two runs, one in a Non-Adaptive +(classical) and one in an Adaptive (calibration-less) mode of operation. +The order of the runs was randomized for each session. In both runs there +was a Training (calibration) phase and an Online phase, always passed in +this order. In the non-Adaptive run the data from the Training phase was +used for classifying the trials on the Online phase using the training-test +version of the MDM algorithm [2]. In the Adaptive run, the data from the +training phase was not used at all, instead the classifier was initialized +with generic class geometric means and continuously adapted to the incoming +data using the Riemannian method explained in [2]. Subjects were completely +blind to the mode of operation and the two runs appeared to them identical.

+

In the Brain Invaders P300 paradigm, a repetition is composed of 12 +flashes, of which 2 include the Target symbol (Target flashes) and 10 do +not (non-Target flash). Please see [3] for a description of the paradigm. +For this experiment, in the Training phases the number of flashes is fixed +(80 Target flashes and 400 non-Target flashes). In the Online phases the +number of Target and non-Target still are in a ratio 1/5, however their +number is variable because the Brain Invaders works with a fixed number of +game levels, however the number of repetitions needed to destroy the target +(hence to proceed to the next level) depends on the user’s performance +[2]. In any case, since the classes are unbalanced, an appropriate score +must be used for quantifying the performance of classification methods +(e.g., balanced accuracy, AUC methods, etc).

+

Data were acquired with a Nexus (TMSi, The Netherlands) EEG amplifier:

+
    +
  • Sampling Frequency: 512 samples per second

  • +
  • Digital Filter: no

  • +
  • Electrodes: 16 wet Silver/Silver Chloride electrodes positioned at +FP1, FP2, F5, AFz, F6, T7, Cz, T8, P7, P3, Pz, P4, P8, O1, Oz, O2 +according to the 10/20 international system.

  • +
  • Reference: left ear-lobe.

  • +
  • Ground: N/A.

  • +
+
+
Principal Investigators:
+

Erwan Vaineau, Dr. Alexandre Barachant

+
+
Scientific Supervisor:
+

Dr. Marco Congedo

+
+
Technical Supervisor:
+

Anton Andreev

+
+
+

References

+
+
+[1] +

Vaineau, E., Barachant, A., Andreev, A., Rodrigues, P. C., +Cattan, G. & Congedo, M. (2019). Brain invaders adaptive +versus non-adaptive P300 brain-computer interface dataset. +arXiv preprint arXiv:1904.09111.

+
+
+[2] +(1,2,3) +

Barachant A, Congedo M (2014) A Plug & Play P300 BCI using +Information Geometry. +arXiv:1409.0107.

+
+
+[3] +

Congedo M, Goyat M, Tarrin N, Ionescu G, Rivet B,Varnet L, Rivet B, +Phlypo R, Jrad N, Acquadro M, Jutten C (2011) “Brain Invaders”: a +prototype of an open-source P300-based video game working with the +OpenViBE platform. Proc. IBCI Conf., Graz, Austria, 280-283.

+
+
+

Notes

+
+

Note

+

BI2013a was previously named bi2013a. bi2013a will be removed in version 1.1.

+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BI2014a.html b/docs/generated/moabb.datasets.BI2014a.html new file mode 100644 index 00000000..a313454b --- /dev/null +++ b/docs/generated/moabb.datasets.BI2014a.html @@ -0,0 +1,649 @@ + + + + + + + + + + + + moabb.datasets.BI2014a — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BI2014a#

+
+
+class moabb.datasets.BI2014a[source]#
+

P300 dataset BI2014a from a “Brain Invaders” experiment.

+

This dataset contains electroencephalographic (EEG) recordings of 71 subjects +playing to a visual P300 Brain-Computer Interface (BCI) videogame named Brain Invaders. +The interface uses the oddball paradigm on a grid of 36 symbols (1 Target, 35 Non-Target) +that are flashed pseudo-randomly to elicit the P300 response. EEG data were recorded +using 16 active dry electrodes with up to three game sessions. The experiment took place +at GIPSA-lab, Grenoble, France, in 2014. A full description of the experiment is available +at [1]. The ID of this dataset is BI2014a.

+
+
Investigators:
+

Eng. Louis Korczowski, B. Sc. Ekaterina Ostaschenko

+
+
Technical Support:
+

Eng. Anton Andreev, Eng. Grégoire Cattan, Eng. Pedro. L. C. Rodrigues, +M. Sc. Violette Gautheret

+
+
Scientific Supervisor:
+

Ph.D. Marco Congedo

+
+
+

Notes

+
+

Note

+

BI2014a was previously named bi2014a. bi2014a will be removed in version 1.1.

+
+
+

New in version 0.4.6.

+
+

References

+
+
+[1] +

Korczowski, L., Ostaschenko, E., Andreev, A., Cattan, G., Rodrigues, P. L. C., +Gautheret, V., & Congedo, M. (2019). Brain Invaders calibration-less P300-based +BCI using dry EEG electrodes Dataset (BI2014a). +https://hal.archives-ouvertes.fr/hal-02171575

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+

Examples using moabb.datasets.BI2014a#

+
Tutorial 5: Creating a dataset class +

Tutorial 5: Creating a dataset class

+
Tutorial 5: Creating a dataset class
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BI2014b.html b/docs/generated/moabb.datasets.BI2014b.html new file mode 100644 index 00000000..bd830017 --- /dev/null +++ b/docs/generated/moabb.datasets.BI2014b.html @@ -0,0 +1,643 @@ + + + + + + + + + + + + moabb.datasets.BI2014b — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BI2014b#

+
+
+class moabb.datasets.BI2014b[source]#
+

P300 dataset BI2014b from a “Brain Invaders” experiment.

+

This dataset contains electroencephalographic (EEG) recordings of 38 subjects playing in +pair (19 pairs) to the multi-user version of a visual P300-based Brain-Computer Interface (BCI) +named Brain Invaders. The interface uses the oddball paradigm on a grid of 36 symbols (1 Target, +35 Non-Target) that are flashed pseudo-randomly to elicit a P300 response, an evoked-potential +appearing about 300ms after stimulation onset. EEG data were recorded using 32 active wet +electrodes per subjects (total: 64 electrodes) during three randomized conditions +(Solo1, Solo2, Collaboration). The experiment took place at GIPSA-lab, Grenoble, France, in 2014. +A full description of the experiment is available at [1]. The ID of this dataset is BI2014b.

+
+
Investigators:
+

Eng. Louis Korczowski, B. Sc. Ekaterina Ostaschenko

+
+
Technical Support:
+

Eng. Anton Andreev, Eng. Grégoire Cattan, Eng. Pedro. L. C. Rodrigues, +M. Sc. Violette Gautheret

+
+
Scientific Supervisor:
+

Ph.D. Marco Congedo

+
+
+

Notes

+
+

Note

+

BI2014b was previously named bi2014b. bi2014b will be removed in version 1.1.

+
+
+

New in version 0.4.6.

+
+

References

+
+
+[1] +

Korczowski, L., Ostaschenko, E., Andreev, A., Cattan, G., Rodrigues, P. L. C., +Gautheret, V., & Congedo, M. (2019). Brain Invaders Solo versus Collaboration: +Multi-User P300-Based Brain-Computer Interface Dataset (BI2014b). +https://hal.archives-ouvertes.fr/hal-02173958

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BI2015a.html b/docs/generated/moabb.datasets.BI2015a.html new file mode 100644 index 00000000..a3e4497c --- /dev/null +++ b/docs/generated/moabb.datasets.BI2015a.html @@ -0,0 +1,644 @@ + + + + + + + + + + + + moabb.datasets.BI2015a — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BI2015a#

+
+
+class moabb.datasets.BI2015a[source]#
+

P300 dataset BI2015a from a “Brain Invaders” experiment.

+

This dataset contains electroencephalographic (EEG) recordings +of 43 subjects playing to a visual P300 Brain-Computer Interface (BCI) +videogame named Brain Invaders. The interface uses the oddball paradigm +on a grid of 36 symbols (1 Target, 35 Non-Target) that are flashed +pseudo-randomly to elicit the P300 response. EEG data were recorded using +32 active wet electrodes with three conditions: flash duration 50ms, 80ms +or 110ms. The experiment took place at GIPSA-lab, Grenoble, France, in 2015. +A full description of the experiment is available at [1]. The ID of this +dataset is BI2015a.

+
+
Investigators:
+

Eng. Louis Korczowski, B. Sc. Martine Cederhout

+
+
Technical Support:
+

Eng. Anton Andreev, Eng. Grégoire Cattan, Eng. Pedro. L. C. Rodrigues, +M. Sc. Violette Gautheret

+
+
Scientific Supervisor:
+

Ph.D. Marco Congedo

+
+
+

Notes

+
+

Note

+

BI2015a was previously named bi2015a. bi2015a will be removed in version 1.1.

+
+
+

New in version 0.4.6.

+
+

References

+
+
+[1] +

Korczowski, L., Cederhout, M., Andreev, A., Cattan, G., Rodrigues, P. L. C., +Gautheret, V., & Congedo, M. (2019). Brain Invaders calibration-less P300-based +BCI with modulation of flash duration Dataset (BI2015a) +https://hal.archives-ouvertes.fr/hal-02172347

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BI2015b.html b/docs/generated/moabb.datasets.BI2015b.html new file mode 100644 index 00000000..d82e4bf5 --- /dev/null +++ b/docs/generated/moabb.datasets.BI2015b.html @@ -0,0 +1,649 @@ + + + + + + + + + + + + moabb.datasets.BI2015b — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BI2015b#

+
+
+class moabb.datasets.BI2015b[source]#
+

P300 dataset BI2015b from a “Brain Invaders” experiment.

+
+
+

This dataset contains electroencephalographic (EEG) recordings +of 44 subjects playing in pair to the multi-user version of a visual +P300 Brain-Computer Interface (BCI) named Brain Invaders. The interface +uses the oddball paradigm on a grid of 36 symbols (1 or 2 Target, +35 or 34 Non-Target) that are flashed pseudo-randomly to elicit the +P300 response. EEG data were recorded using 32 active wet electrodes +per subjects (total: 64 electrodes) during four randomised conditions +(Cooperation 1-Target, Cooperation 2-Targets, Competition 1-Target, +Competition 2-Targets). The experiment took place at GIPSA-lab, Grenoble, +France, in 2015. A full description of the experiment is available at +A full description of the experiment is available at [1]. The ID of this +dataset is BI2015a.

+
+
Investigators:
+

Eng. Louis Korczowski, B. Sc. Martine Cederhout

+
+
Technical Support:
+

Eng. Anton Andreev, Eng. Grégoire Cattan, Eng. Pedro. L. C. Rodrigues, +M. Sc. Violette Gautheret

+
+
Scientific Supervisor:
+

Ph.D. Marco Congedo

+
+
+

Notes

+
+

Note

+

BI2015b was previously named bi2015b. bi2015b will be removed in version 1.1.

+
+
+

New in version 0.4.6.

+
+

References

+
+
+[1] +

Korczowski, L., Cederhout, M., Andreev, A., Cattan, G., Rodrigues, P. L. C., +Gautheret, V., & Congedo, M. (2019). Brain Invaders Cooperative versus Competitive: +Multi-User P300-based Brain-Computer Interface Dataset (BI2015b) +https://hal.archives-ouvertes.fr/hal-02172347

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BNCI2014_001.html b/docs/generated/moabb.datasets.BNCI2014_001.html new file mode 100644 index 00000000..ec21fe25 --- /dev/null +++ b/docs/generated/moabb.datasets.BNCI2014_001.html @@ -0,0 +1,667 @@ + + + + + + + + + + + + moabb.datasets.BNCI2014_001 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BNCI2014_001#

+
+
+class moabb.datasets.BNCI2014_001[source]#
+

BNCI 2014-001 Motor Imagery dataset.

+
+

Dataset summary

+
+

Dataset IIa from BCI Competition 4 [1].

+

Dataset Description

+

This data set consists of EEG data from 9 subjects. The cue-based BCI +paradigm consisted of four different motor imagery tasks, namely the imag- +ination of movement of the left hand (class 1), right hand (class 2), both +feet (class 3), and tongue (class 4). Two sessions on different days were +recorded for each subject. Each session is comprised of 6 runs separated +by short breaks. One run consists of 48 trials (12 for each of the four +possible classes), yielding a total of 288 trials per session.

+

The subjects were sitting in a comfortable armchair in front of a computer +screen. At the beginning of a trial ( t = 0 s), a fixation cross appeared +on the black screen. In addition, a short acoustic warning tone was +presented. After two seconds ( t = 2 s), a cue in the form of an arrow +pointing either to the left, right, down or up (corresponding to one of the +four classes left hand, right hand, foot or tongue) appeared and stayed on +the screen for 1.25 s. This prompted the subjects to perform the desired +motor imagery task. No feedback was provided. The subjects were ask to +carry out the motor imagery task until the fixation cross disappeared from +the screen at t = 6 s.

+

Twenty-two Ag/AgCl electrodes (with inter-electrode distances of 3.5 cm) +were used to record the EEG; the montage is shown in Figure 3 left. All +signals were recorded monopolarly with the left mastoid serving as +reference and the right mastoid as ground. The signals were sampled with. +250 Hz and bandpass-filtered between 0.5 Hz and 100 Hz. The sensitivity of +the amplifier was set to 100 μV . An additional 50 Hz notch filter was +enabled to suppress line noise

+

References

+
+
+[1] +

Tangermann, M., Müller, K.R., Aertsen, A., Birbaumer, N., Braun, C., +Brunner, C., Leeb, R., Mehring, C., Miller, K.J., Mueller-Putz, G. +and Nolte, G., 2012. Review of the BCI competition IV. +Frontiers in neuroscience, 6, p.55.

+
+
+

Notes

+
+

Note

+

BNCI2014_001 was previously named BNCI2014001. BNCI2014001 will be removed in version 1.1.

+
+
+ +
+

Examples using moabb.datasets.BNCI2014_001#

+
Benchmarking with MOABB showing the CO2 footprint +

Benchmarking with MOABB showing the CO2 footprint

+
Benchmarking with MOABB showing the CO2 footprint
+
Benchmarking on MOABB with Tensorflow deep net architectures +

Benchmarking on MOABB with Tensorflow deep net architectures

+
Benchmarking on MOABB with Tensorflow deep net architectures
+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures +

Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures

+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures
+
Cross-session motor imagery with deep learning EEGNet v4 model +

Cross-session motor imagery with deep learning EEGNet v4 model

+
Cross-session motor imagery with deep learning EEGNet v4 model
+
Cross-Session Motor Imagery +

Cross-Session Motor Imagery

+
Cross-Session Motor Imagery
+
Cross-Session on Multiple Datasets +

Cross-Session on Multiple Datasets

+
Cross-Session on Multiple Datasets
+
Explore Paradigm Object +

Explore Paradigm Object

+
Explore Paradigm Object
+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
GridSearch within a session +

GridSearch within a session

+
GridSearch within a session
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
Within Session Motor Imagery with Learning Curve +

Within Session Motor Imagery with Learning Curve

+
Within Session Motor Imagery with Learning Curve
+
Tutorial 0: Getting Started +

Tutorial 0: Getting Started

+
Tutorial 0: Getting Started
+
Tutorial 1: Simple Motor Imagery +

Tutorial 1: Simple Motor Imagery

+
Tutorial 1: Simple Motor Imagery
+
Tutorial 2: Using multiple datasets +

Tutorial 2: Using multiple datasets

+
Tutorial 2: Using multiple datasets
+
Tutorial 3: Benchmarking multiple pipelines +

Tutorial 3: Benchmarking multiple pipelines

+
Tutorial 3: Benchmarking multiple pipelines
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BNCI2014_002.html b/docs/generated/moabb.datasets.BNCI2014_002.html new file mode 100644 index 00000000..471c0daf --- /dev/null +++ b/docs/generated/moabb.datasets.BNCI2014_002.html @@ -0,0 +1,615 @@ + + + + + + + + + + + + moabb.datasets.BNCI2014_002 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BNCI2014_002#

+
+
+class moabb.datasets.BNCI2014_002[source]#
+

BNCI 2014-002 Motor Imagery dataset.

+
+

Dataset summary

+
+

Motor Imagery Dataset from [1].

+

Dataset description

+

The session consisted of eight runs, five of them for training and three +with feedback for validation. One run was composed of 20 trials. Taken +together, we recorded 50 trials per class for training and 30 trials per +class for validation. Participants had the task of performing sustained (5 +seconds) kinaesthetic motor imagery (MI) of the right hand and of the feet +each as instructed by the cue. At 0 s, a white colored cross appeared on +screen, 2 s later a beep sounded to catch the participant’s attention. The +cue was displayed from 3 s to 4 s. Participants were instructed to start +with MI as soon as they recognized the cue and to perform the indicated MI +until the cross disappeared at 8 s. A rest period with a random length +between 2 s and 3 s was presented between trials. Participants did not +receive feedback during training. Feedback was presented in form of a +white +coloured bar-graph. The length of the bar-graph reflected the amount of +correct classifications over the last second. EEG was measured with a +biosignal amplifier and active Ag/AgCl electrodes (g.USBamp, g.LADYbird, +Guger Technologies OG, Schiedlberg, Austria) at a sampling rate of 512 Hz. +The electrodes placement was designed for obtaining three Laplacian +derivations. Center electrodes at positions C3, Cz, and C4 and four +additional electrodes around each center electrode with a distance of 2.5 +cm, 15 electrodes total. The reference electrode was mounted on the left +mastoid and the ground electrode on the right mastoid. The 13 participants +were aged between 20 and 30 years, 8 naive to the task, and had no known +medical or neurological diseases.

+

References

+
+
+[1] +

Steyrl, D., Scherer, R., Faller, J. and Müller-Putz, G.R., 2016. +Random forests in non-invasive sensorimotor rhythm brain-computer +interfaces: a practical and convenient non-linear classifier. +Biomedical Engineering/Biomedizinische Technique, 61(1), pp.77-86.

+
+
+

Notes

+
+

Note

+

BNCI2014_002 was previously named BNCI2014002. BNCI2014002 will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BNCI2014_004.html b/docs/generated/moabb.datasets.BNCI2014_004.html new file mode 100644 index 00000000..aba885bc --- /dev/null +++ b/docs/generated/moabb.datasets.BNCI2014_004.html @@ -0,0 +1,638 @@ + + + + + + + + + + + + moabb.datasets.BNCI2014_004 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BNCI2014_004#

+
+
+class moabb.datasets.BNCI2014_004[source]#
+

BNCI 2014-004 Motor Imagery dataset.

+
+

Dataset summary

+
+

Dataset B from BCI Competition 2008.

+

Dataset description

+

This data set consists of EEG data from 9 subjects of a study published in +[1]. The subjects were right-handed, had normal or corrected-to-normal +vision and were paid for participating in the experiments. +All volunteers were sitting in an armchair, watching a flat screen monitor +placed approximately 1 m away at eye level. For each subject 5 sessions +are provided, whereby the first two sessions contain training data without +feedback (screening), and the last three sessions were recorded with +feedback.

+

Three bipolar recordings (C3, Cz, and C4) were recorded with a sampling +frequency of 250 Hz.They were bandpass- filtered between 0.5 Hz and 100 Hz, +and a notch filter at 50 Hz was enabled. The placement of the three +bipolar recordings (large or small distances, more anterior or posterior) +were slightly different for each subject (for more details see [1]). +The electrode position Fz served as EEG ground. In addition to the EEG +channels, the electrooculogram (EOG) was recorded with three monopolar +electrodes.

+

The cue-based screening paradigm consisted of two classes, +namely the motor imagery (MI) of left hand (class 1) and right hand +(class 2). +Each subject participated in two screening sessions without feedback +recorded on two different days within two weeks. +Each session consisted of six runs with ten trials each and two classes of +imagery. This resulted in 20 trials per run and 120 trials per session. +Data of 120 repetitions of each MI class were available for each person in +total. Prior to the first motor im- agery training the subject executed +and imagined different movements for each body part and selected the one +which they could imagine best (e. g., squeezing a ball or pulling a brake).

+

Each trial started with a fixation cross and an additional short acoustic +warning tone (1 kHz, 70 ms). Some seconds later a visual cue was presented +for 1.25 seconds. Afterwards the subjects had to imagine the corresponding +hand movement over a period of 4 seconds. Each trial was followed by a +short break of at least 1.5 seconds. A randomized time of up to 1 second +was added to the break to avoid adaptation

+

For the three online feedback sessions four runs with smiley feedback +were recorded, whereby each run consisted of twenty trials for each type of +motor imagery. At the beginning of each trial (second 0) the feedback (a +gray smiley) was centered on the screen. At second 2, a short warning beep +(1 kHz, 70 ms) was given. The cue was presented from second 3 to 7.5. At +second 7.5 the screen went blank and a random interval between 1.0 and 2.0 +seconds was added to the trial.

+

References

+
+
+[1] +

R. Leeb, F. Lee, C. Keinrath, R. Scherer, H. Bischof, +G. Pfurtscheller. Brain-computer communication: motivation, aim, +and impact of exploring a virtual apartment. IEEE Transactions on +Neural Systems and Rehabilitation Engineering 15, 473–482, 2007

+
+
+

Notes

+
+

Note

+

BNCI2014_004 was previously named BNCI2014004. BNCI2014004 will be removed in version 1.1.

+
+
+ +
+

Examples using moabb.datasets.BNCI2014_004#

+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures +

Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures

+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BNCI2014_008.html b/docs/generated/moabb.datasets.BNCI2014_008.html new file mode 100644 index 00000000..8e2cca08 --- /dev/null +++ b/docs/generated/moabb.datasets.BNCI2014_008.html @@ -0,0 +1,624 @@ + + + + + + + + + + + + moabb.datasets.BNCI2014_008 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BNCI2014_008#

+
+
+class moabb.datasets.BNCI2014_008[source]#
+

BNCI 2014-008 P300 dataset.

+
+

Dataset summary

+
+

Dataset from [1].

+

Dataset description

+

This dataset represents a complete record of P300 evoked potentials +using a paradigm originally described by Farwell and Donchin [2]. +In these sessions, 8 users with amyotrophic lateral sclerosis (ALSO) +focused on one out of 36 different characters. The objective in this +contest is to predict the correct character in each of the provided +character selection epochs.

+

We included in the study a total of eight volunteers, all naïve to BCI +training. Scalp EEG signals were recorded (g.MOBILAB, g.tec, Austria) +from eight channels according to 10–10 standard (Fz, Cz, Pz, Oz, P3, P4, +PO7 and PO8) using active electrodes (g.Ladybird, g.tec, Austria). +All channels were referenced to the right earlobe and grounded to the left +mastoid. The EEG signal was digitized at 256 Hz and band-pass filtered +between 0.1 and 30 Hz.

+

Participants were required to copy spell seven predefined words of five +characters each (runs), by controlling a P300 matrix speller. Rows and +columns on the interface were randomly intensified for 125ms, with an +inter stimulus interval (ISI) of 125ms, yielding a 250 ms lag between the +appearance of two stimuli (stimulus onset asynchrony, SOA).

+

In the first three runs (15 trials in total) EEG data was stored to +perform a calibration of the BCI classifier. Thus no feedback was provided +to the participant up to this point. A stepwise linear discriminant +analysis (SWLDA) was applied to the data from the three calibration runs +(i.e., runs 1–3) to determine the classifier weights (i.e., classifier +coefficients). These weights were then applied during the subsequent four +testing runs (i.e., runs 4–7) when participants were provided with +feedback.

+

References

+
+
+[1] +

A. Riccio, L. Simione, F. Schettini, A. Pizzimenti, M. Inghilleri, +M. O. Belardinelli, D. Mattia, and F. Cincotti (2013). Attention +and P300-based BCI performance in people with amyotrophic lateral +sclerosis. Front. Hum. Neurosci., vol. 7:, pag. 732.

+
+
+[2] +

L. A. Farwell and E. Donchin, Talking off the top of your head: +toward a mental prosthesis utilizing eventrelated +brain potentials, Electroencephalogr. Clin. Neurophysiol., +vol. 70, n. 6, pagg. 510–523, 1988.

+
+
+

Notes

+
+

Note

+

BNCI2014_008 was previously named BNCI2014008. BNCI2014008 will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BNCI2014_009.html b/docs/generated/moabb.datasets.BNCI2014_009.html new file mode 100644 index 00000000..f2106303 --- /dev/null +++ b/docs/generated/moabb.datasets.BNCI2014_009.html @@ -0,0 +1,629 @@ + + + + + + + + + + + + moabb.datasets.BNCI2014_009 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BNCI2014_009#

+
+
+class moabb.datasets.BNCI2014_009[source]#
+

BNCI 2014-009 P300 dataset.

+
+

Dataset summary

+
+

Dataset from [1].

+

Dataset description

+

This dataset presents a complete record of P300 evoked potentials +using two different paradigms: a paradigm based on the P300 Speller in +overt attention condition and a paradigm based used in convert attention +condition. In these sessions, 10 healthy subjects focused on one out of 36 +different characters. The objective was to predict the correct character +in each of the provided character selection epochs. +(Note: right now only the overt attention data is available via MOABB)

+

In the first interface, cues are organized in a 6×6 matrix and each +character is always visible on the screen and spatially separated from the +others. By design, no fixation cue is provided, as the subject is expected +to gaze at the target character. Stimulation consists in the +intensification of whole lines (rows or columns) of six characters.

+

Ten healthy subjects (10 female, mean age = 26.8 ± 5.6, table I) with +previous experience with P300-based BCIs attended 3 recording sessions. +Scalp EEG potentials were measured using 16 Ag/AgCl electrodes that +covered the left, right and central scalp (Fz, FCz, Cz, CPz, Pz, Oz, F3, +F4, C3, C4, CP3, CP4, P3, P4, PO7, PO8) per the 10-10 standard. Each +electrode was referenced to the linked earlobes and grounded to the +right mastoid. The EEG was acquired at 256 Hz, high pass- and low +pass-filtered with cutoff frequencies of 0.1 Hz and 20 Hz, respectively. +Each subject attended 4 recording sessions. During each session, +the subject performed three runs with each of the stimulation interfaces.

+

References

+
+
+[1] +

P Aricò, F Aloise, F Schettini, S Salinari, D Mattia and F Cincotti +(2013). Influence of P300 latency jitter on event related potential- +based brain–computer interface performance. Journal of Neural +Engineering, vol. 11, number 3.

+
+
+

Notes

+
+

Note

+

BNCI2014_009 was previously named BNCI2014009. BNCI2014009 will be removed in version 1.1.

+
+
+ +
+

Examples using moabb.datasets.BNCI2014_009#

+
Within Session P300 +

Within Session P300

+
Within Session P300
+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BNCI2015_001.html b/docs/generated/moabb.datasets.BNCI2015_001.html new file mode 100644 index 00000000..5ee85b8b --- /dev/null +++ b/docs/generated/moabb.datasets.BNCI2015_001.html @@ -0,0 +1,607 @@ + + + + + + + + + + + + moabb.datasets.BNCI2015_001 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BNCI2015_001#

+
+
+class moabb.datasets.BNCI2015_001[source]#
+

BNCI 2015-001 Motor Imagery dataset.

+
+

Dataset summary

+
+

Dataset from [1].

+

Dataset description

+

We acquired the EEG from three Laplacian derivations, 3.5 cm (center-to- +center) around the electrode positions (according to International 10-20 +System of Electrode Placement) C3 (FC3, C5, CP3 and C1), Cz (FCz, C1, CPz +and C2) and C4 (FC4, C2, CP4 and C6). The acquisition hardware was a +g.GAMMAsys active electrode system along with a g.USBamp amplifier (g.tec, +Guger Tech- nologies OEG, Graz, Austria). The system sampled at 512 Hz, +with a bandpass filter between 0.5 and 100 Hz and a notch filter at 50 Hz. +The order of the channels in the data is FC3, FCz, FC4, C5, C3, C1, Cz, C2, +C4, C6, CP3, CPz, CP4.

+

The task for the user was to perform sustained right hand versus both feet +movement imagery starting from the cue (second 3) to the end of the cross +period (sec- and 8). A trial started with 3 s of reference period, +followed by a brisk audible cue and a visual cue (arrow right for right +hand, arrow down for both feet) from second 3 to 4.25. +The activity period, where the users received feedback, lasted from +second 4 to 8. There was a random 2 to 3 s pause between the trials.

+

References

+
+
+[1] +

J. Faller, C. Vidaurre, T. Solis-Escalante, C. Neuper and R. +Scherer (2012). Autocalibration and recurrent adaptation: Towards a +plug and play online ERD- BCI. IEEE Transactions on Neural Systems +and Rehabilitation Engineering, 20(3), 313-319.

+
+
+

Notes

+
+

Note

+

BNCI2015_001 was previously named BNCI2015001. BNCI2015001 will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BNCI2015_003.html b/docs/generated/moabb.datasets.BNCI2015_003.html new file mode 100644 index 00000000..effc080a --- /dev/null +++ b/docs/generated/moabb.datasets.BNCI2015_003.html @@ -0,0 +1,597 @@ + + + + + + + + + + + + moabb.datasets.BNCI2015_003 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BNCI2015_003#

+
+
+class moabb.datasets.BNCI2015_003[source]#
+

BNCI 2015-003 P300 dataset.

+
+

Dataset summary

+
+

Dataset from [1].

+

Dataset description

+

This dataset contains recordings from 10 subjects performing a visual P300 +task for spelling. Results were published in [1]. Sampling frequency was +256 Hz and there were 8 electrodes (‘Fz’, ‘Cz’, ‘P3’, ‘Pz’, ‘P4’, ‘PO7’, +‘Oz’, ‘PO8’) which were referenced to the right earlobe. Each subject +participated in only one session. For more information, see [1].

+

References

+
+
+[1] +(1,2,3) +

C. Guger, S. Daban, E. Sellers, C. Holzner, G. Krausz, +R. Carabalona, F. Gramatica, and G. Edlinger (2009). How many +people are able to control a P300-based brain-computer interface +(BCI)?. Neuroscience Letters, vol. 462, pp. 94–98.

+
+
+

Notes

+
+

Note

+

BNCI2015_003 was previously named BNCI2015003. BNCI2015003 will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.BNCI2015_004.html b/docs/generated/moabb.datasets.BNCI2015_004.html new file mode 100644 index 00000000..0bdc168d --- /dev/null +++ b/docs/generated/moabb.datasets.BNCI2015_004.html @@ -0,0 +1,625 @@ + + + + + + + + + + + + moabb.datasets.BNCI2015_004 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.BNCI2015_004#

+
+
+class moabb.datasets.BNCI2015_004[source]#
+

BNCI 2015-004 Motor Imagery dataset.

+
+

Dataset summary

+
+

Dataset from [1].

+

Dataset description

+

We provide EEG data recorded from nine users with disability (spinal cord +injury and stroke) on two different days (sessions). Users performed, +follow- ing a cue-guided experimental paradigm, five distinct mental tasks +(MT). MTs include mental word association (condition WORD), mental +subtraction (SUB), spatial navigation (NAV), right hand motor imagery +(HAND) and +feet motor imagery (FEET). Details on the experimental paradigm are +summarized in Figure 1. The session for a single subject consisted of 8 +runs resulting in 40 trials of each class for each day. One single +experimental run consisted of 25 cues, with 5 of each mental task. Cues +were presented in random order.

+

EEG was recorded from 30 electrode channels placed on the scalp according +to the international 10-20 system. Electrode positions included channels +AFz, F7, F3, Fz, F4, F8, FC3, FCz, FC4, T3, C3, Cz, C4, T4, CP3, CPz,CP4, +P7, P5, P3, P1, Pz, P2, P4, P6, P8, PO3, PO4, O1, and O2. Reference and +ground were placed at the left and right mastoid, respectively. The g.tec +GAMMAsys system with g.LADYbird active electrodes and two g.USBamp +biosignal +amplifiers (Guger Technologies, Graz, Austria) was used for recording. EEG +was band pass filtered 0.5-100 Hz (notch filter at 50 Hz) and sampled at a +rate of 256 Hz.

+

The duration of a single imagery trials is 10 s. At t = 0 s, a cross was +presented in the middle of the screen. Participants were asked to relax +and +fixate the cross to avoid eye movements. At t = 3 s, a beep was sounded to +get the participant’s attention. The cue indicating the requested imagery +task, one out of five graphical symbols, was presented from t = 3 s to t = +4.25 s. At t = 10 s, a second beep was sounded and the fixation-cross +disappeared, which indicated the end of the trial. A variable break +(inter-trial-interval, ITI) lasting between 2.5 s and 3.5 s occurred +before +the start of the next trial. Participants were asked to avoid movements +during the imagery period, and to move and blink during the +ITI. Experimental runs began and ended with a blank screen (duration 4 s)

+

References

+
+
+[1] +

Scherer R, Faller J, Friedrich EVC, Opisso E, Costa U, Kübler A, et +al. (2015) Individually Adapted Imagery Improves Brain-Computer +Interface Performance in End-Users with Disability. PLoS ONE 10(5). +https://doi.org/10.1371/journal.pone.0123727

+
+
+

Notes

+
+

Note

+

BNCI2015_004 was previously named BNCI2015004. BNCI2015004 will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.CastillosBurstVEP100.html b/docs/generated/moabb.datasets.CastillosBurstVEP100.html new file mode 100644 index 00000000..80aae808 --- /dev/null +++ b/docs/generated/moabb.datasets.CastillosBurstVEP100.html @@ -0,0 +1,645 @@ + + + + + + + + + + + + moabb.datasets.CastillosBurstVEP100 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.CastillosBurstVEP100#

+
+
+class moabb.datasets.CastillosBurstVEP100[source]#
+

c-VEP and Burst-VEP dataset from Castillos et al. (2023)

+

Dataset [1] from the study on burst-VEP [2].

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Sessions

Sampling rate

#Chan

Trials length

#Trial classes

#Trials / class

#Epoch classes

#Epochs / class

Codes

Presentation rate

CastillosBurstVEP100

12

1

500Hz

32

2.2s

4

15/15/15/15

2

5820NT/1200T

Burst-CVEP

60Hz

+
+

Dataset description

+

Participants were comfortably seated and instructed to read and sign the informed consent. EEG data were recorded +using a BrainProduct LiveAmp 32 active electrodes wet-EEG setup with a sample rate of 500 Hz to record the surface +brain activity. The 32 electrodes were placed following the 10–20 international system on a BrainProduct Acticap. The +ground electrode was placed at the FPz electrode location and all electrodes were referenced to the FCz electrode. The +impedance of all electrodes was brought below 25kOhm prior to recording onset. Once equipped with the EEG system, +volunteers were asked to focus on four targets that were cued sequentially in a random order for 0.5 s, followed by a +2.2 s stimulation phase, before a 0.7 s inter-trial period. The cue sequence for each trial was pseudo-random and +different for each block. After each block, a pause was observed and subjects had to press the space bar to continue. +The participants were presented with fifteen blocks of four trials for each of the four conditions (burst or msequence x +40% or 100%). The task was implemented in Python using the Psychopy toolbox. The four discs were all +150 pixels, without borders, and were presented on the following LCD monitor: Dell P2419HC, 1920 x 1080 pixels, 265 +cd/m2, and 60 Hz refresh rate. After completing the experiment and removing the EEG equipment, the participants were +asked to provide subjective ratings for the different stimuli conditions. These stimuli included burst c-VEP with 100% +amplitude, burst c-VEP with 40% amplitude, m-sequences with 100% amplitude, and m-sequences with 40% amplitude. Each +stimulus was presented three times in a pseudo-random order. Following the presentation of each stimulus, participants +were presented with three 11-points scales and were asked to rate the visual comfort, visual tiredness, and +intrusiveness using a mouse. In total, participants completed 12 ratings (3 repetitions x 4 types of stimuli) for +each of the three scales.

+

References

+
+
+[1] +

Kalou Cabrera Castillos. (2023). 4-class code-VEP EEG data [Data set]. Zenodo.(dataset). +DOI: https://doi.org/10.5281/zenodo.8255618

+
+
+[2] +

Kalou Cabrera Castillos, Simon Ladouce, Ludovic Darmet, Frédéric Dehais. Burst c-VEP Based BCI: Optimizing stimulus +design for enhanced classification with minimal calibration data and improved user experience,NeuroImage,Volume 284, +2023,120446,ISSN 1053-8119 +DOI: https://doi.org/10.1016/j.neuroimage.2023.120446

+
+
+

Notes

+
+

New in version 1.1.0.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.CastillosBurstVEP40.html b/docs/generated/moabb.datasets.CastillosBurstVEP40.html new file mode 100644 index 00000000..5c23e15c --- /dev/null +++ b/docs/generated/moabb.datasets.CastillosBurstVEP40.html @@ -0,0 +1,645 @@ + + + + + + + + + + + + moabb.datasets.CastillosBurstVEP40 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.CastillosBurstVEP40#

+
+
+class moabb.datasets.CastillosBurstVEP40[source]#
+

c-VEP and Burst-VEP dataset from Castillos et al. (2023)

+

Dataset [1] from the study on burst-VEP [2].

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Sessions

Sampling rate

#Chan

Trials length

#Trial classes

#Trials / class

#Epoch classes

#Epochs / class

Codes

Presentation rate

CastillosBurstVEP40

12

1

500Hz

32

2.2s

4

15/15/15/15

2

5820NT/1200T

Burst-CVEP

60Hz

+
+

Dataset description

+

Participants were comfortably seated and instructed to read and sign the informed consent. EEG data were recorded +using a BrainProduct LiveAmp 32 active electrodes wet-EEG setup with a sample rate of 500 Hz to record the surface +brain activity. The 32 electrodes were placed following the 10–20 international system on a BrainProduct Acticap. The +ground electrode was placed at the FPz electrode location and all electrodes were referenced to the FCz electrode. The +impedance of all electrodes was brought below 25kOhm prior to recording onset. Once equipped with the EEG system, +volunteers were asked to focus on four targets that were cued sequentially in a random order for 0.5 s, followed by a +2.2 s stimulation phase, before a 0.7 s inter-trial period. The cue sequence for each trial was pseudo-random and +different for each block. After each block, a pause was observed and subjects had to press the space bar to continue. +The participants were presented with fifteen blocks of four trials for each of the four conditions (burst or msequence x +40% or 100%). The task was implemented in Python using the Psychopy toolbox. The four discs were all +150 pixels, without borders, and were presented on the following LCD monitor: Dell P2419HC, 1920 x 1080 pixels, 265 +cd/m2, and 60 Hz refresh rate. After completing the experiment and removing the EEG equipment, the participants were +asked to provide subjective ratings for the different stimuli conditions. These stimuli included burst c-VEP with 100% +amplitude, burst c-VEP with 40% amplitude, m-sequences with 100% amplitude, and m-sequences with 40% amplitude. Each +stimulus was presented three times in a pseudo-random order. Following the presentation of each stimulus, participants +were presented with three 11-points scales and were asked to rate the visual comfort, visual tiredness, and +intrusiveness using a mouse. In total, participants completed 12 ratings (3 repetitions x 4 types of stimuli) for +each of the three scales.

+

References

+
+
+[1] +

Kalou Cabrera Castillos. (2023). 4-class code-VEP EEG data [Data set]. Zenodo.(dataset). +DOI: https://doi.org/10.5281/zenodo.8255618

+
+
+[2] +

Kalou Cabrera Castillos, Simon Ladouce, Ludovic Darmet, Frédéric Dehais. Burst c-VEP Based BCI: Optimizing stimulus +design for enhanced classification with minimal calibration data and improved user experience,NeuroImage,Volume 284, +2023,120446,ISSN 1053-8119 +DOI: https://doi.org/10.1016/j.neuroimage.2023.120446

+
+
+

Notes

+
+

New in version 1.1.0.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.CastillosCVEP100.html b/docs/generated/moabb.datasets.CastillosCVEP100.html new file mode 100644 index 00000000..dddbe14d --- /dev/null +++ b/docs/generated/moabb.datasets.CastillosCVEP100.html @@ -0,0 +1,645 @@ + + + + + + + + + + + + moabb.datasets.CastillosCVEP100 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.CastillosCVEP100#

+
+
+class moabb.datasets.CastillosCVEP100[source]#
+

c-VEP and Burst-VEP dataset from Castillos et al. (2023)

+

Dataset [1] from the study on burst-VEP [2].

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Sessions

Sampling rate

#Chan

Trials length

#Trial classes

#Trials / class

#Epoch classes

#Epochs / class

Codes

Presentation rate

CastillosCVEP100

12

1

500Hz

32

2.2s

4

15/15/15/15

2

3525NT/3495T

m-sequence

60Hz

+
+

Dataset description

+

Participants were comfortably seated and instructed to read and sign the informed consent. EEG data were recorded +using a BrainProduct LiveAmp 32 active electrodes wet-EEG setup with a sample rate of 500 Hz to record the surface +brain activity. The 32 electrodes were placed following the 10–20 international system on a BrainProduct Acticap. The +ground electrode was placed at the FPz electrode location and all electrodes were referenced to the FCz electrode. The +impedance of all electrodes was brought below 25kOhm prior to recording onset. Once equipped with the EEG system, +volunteers were asked to focus on four targets that were cued sequentially in a random order for 0.5 s, followed by a +2.2 s stimulation phase, before a 0.7 s inter-trial period. The cue sequence for each trial was pseudo-random and +different for each block. After each block, a pause was observed and subjects had to press the space bar to continue. +The participants were presented with fifteen blocks of four trials for each of the four conditions (burst or msequence x +40% or 100%). The task was implemented in Python using the Psychopy toolbox. The four discs were all +150 pixels, without borders, and were presented on the following LCD monitor: Dell P2419HC, 1920 x 1080 pixels, 265 +cd/m2, and 60 Hz refresh rate. After completing the experiment and removing the EEG equipment, the participants were +asked to provide subjective ratings for the different stimuli conditions. These stimuli included burst c-VEP with 100% +amplitude, burst c-VEP with 40% amplitude, m-sequences with 100% amplitude, and m-sequences with 40% amplitude. Each +stimulus was presented three times in a pseudo-random order. Following the presentation of each stimulus, participants +were presented with three 11-points scales and were asked to rate the visual comfort, visual tiredness, and +intrusiveness using a mouse. In total, participants completed 12 ratings (3 repetitions x 4 types of stimuli) for +each of the three scales.

+

References

+
+
+[1] +

Kalou Cabrera Castillos. (2023). 4-class code-VEP EEG data [Data set]. Zenodo.(dataset). +DOI: https://doi.org/10.5281/zenodo.8255618

+
+
+[2] +

Kalou Cabrera Castillos, Simon Ladouce, Ludovic Darmet, Frédéric Dehais. Burst c-VEP Based BCI: Optimizing stimulus +design for enhanced classification with minimal calibration data and improved user experience,NeuroImage,Volume 284, +2023,120446,ISSN 1053-8119 +DOI: https://doi.org/10.1016/j.neuroimage.2023.120446

+
+
+

Notes

+
+

New in version 1.1.0.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.CastillosCVEP40.html b/docs/generated/moabb.datasets.CastillosCVEP40.html new file mode 100644 index 00000000..6baf8b14 --- /dev/null +++ b/docs/generated/moabb.datasets.CastillosCVEP40.html @@ -0,0 +1,610 @@ + + + + + + + + + + + + moabb.datasets.CastillosCVEP40 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.CastillosCVEP40#

+
+
+class moabb.datasets.CastillosCVEP40[source]#
+

c-VEP and Burst-VEP dataset from Castillos et al. (2023)

+

Dataset [1] from the study on burst-VEP [2].

+

Dataset description

+

Participants were comfortably seated and instructed to read and sign the informed consent. EEG data were recorded +using a BrainProduct LiveAmp 32 active electrodes wet-EEG setup with a sample rate of 500 Hz to record the surface +brain activity. The 32 electrodes were placed following the 10–20 international system on a BrainProduct Acticap. The +ground electrode was placed at the FPz electrode location and all electrodes were referenced to the FCz electrode. The +impedance of all electrodes was brought below 25kOhm prior to recording onset. Once equipped with the EEG system, +volunteers were asked to focus on four targets that were cued sequentially in a random order for 0.5 s, followed by a +2.2 s stimulation phase, before a 0.7 s inter-trial period. The cue sequence for each trial was pseudo-random and +different for each block. After each block, a pause was observed and subjects had to press the space bar to continue. +The participants were presented with fifteen blocks of four trials for each of the four conditions (burst or msequence x +40% or 100%). The task was implemented in Python using the Psychopy toolbox. The four discs were all +150 pixels, without borders, and were presented on the following LCD monitor: Dell P2419HC, 1920 x 1080 pixels, 265 +cd/m2, and 60 Hz refresh rate. After completing the experiment and removing the EEG equipment, the participants were +asked to provide subjective ratings for the different stimuli conditions. These stimuli included burst c-VEP with 100% +amplitude, burst c-VEP with 40% amplitude, m-sequences with 100% amplitude, and m-sequences with 40% amplitude. Each +stimulus was presented three times in a pseudo-random order. Following the presentation of each stimulus, participants +were presented with three 11-points scales and were asked to rate the visual comfort, visual tiredness, and +intrusiveness using a mouse. In total, participants completed 12 ratings (3 repetitions x 4 types of stimuli) for +each of the three scales.

+

References

+
+
+[1] +

Kalou Cabrera Castillos. (2023). 4-class code-VEP EEG data [Data set]. Zenodo.(dataset). +DOI: https://doi.org/10.5281/zenodo.8255618

+
+
+[2] +

Kalou Cabrera Castillos, Simon Ladouce, Ludovic Darmet, Frédéric Dehais. Burst c-VEP Based BCI: Optimizing stimulus +design for enhanced classification with minimal calibration data and improved user experience,NeuroImage,Volume 284, +2023,120446,ISSN 1053-8119 +DOI: https://doi.org/10.1016/j.neuroimage.2023.120446

+
+
+

Notes

+
+

New in version 1.1.0.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Cattan2019_PHMD.html b/docs/generated/moabb.datasets.Cattan2019_PHMD.html new file mode 100644 index 00000000..53d7918d --- /dev/null +++ b/docs/generated/moabb.datasets.Cattan2019_PHMD.html @@ -0,0 +1,650 @@ + + + + + + + + + + + + moabb.datasets.Cattan2019_PHMD — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Cattan2019_PHMD#

+
+
+class moabb.datasets.Cattan2019_PHMD[source]#
+

Passive Head Mounted Display with Music Listening dataset.

+
+

Dataset summary

+
+

We describe the experimental procedures for a dataset that we have made publicly available +at https://doi.org/10.5281/zenodo.2617084 in mat (Mathworks, Natick, USA) and csv formats. +This dataset contains electroencephalographic recordings of 12 subjects listening to music +with and without a passive head-mounted display, that is, a head-mounted display which does +not include any electronics at the exception of a smartphone. The electroencephalographic +headset consisted of 16 electrodes. Data were recorded during a pilot experiment taking +place in the GIPSA-lab, Grenoble, France, in 2017 (Cattan and al, 2018). +The ID of this dataset is PHMDML.EEG.2017-GIPSA.

+

full description of the experiment +https://hal.archives-ouvertes.fr/hal-02085118

+

Link to the data +https://doi.org/10.5281/zenodo.2617084

+

Authors +Principal Investigator: Eng. Grégoire Cattan +Technical Supervisors: Eng. Pedro L. C. Rodrigues +Scientific Supervisor: Dr. Marco Congedo

+

ID of the dataset +PHMDML.EEG.2017-GIPSA

+

Notes

+
+

Note

+

Cattan2019_PHMD was previously named HeadMountedDisplay. HeadMountedDisplay will be removed in version 1.1.

+
+
+

New in version 1.0.0.

+
+

References

+
+
+[1] +

G. Cattan, P. L. Coelho Rodrigues, and M. Congedo, +‘Passive Head-Mounted Display Music-Listening EEG dataset’, +Gipsa-Lab ; IHMTEK, Research Report 2, Mar. 2019. doi: 10.5281/zenodo.2617084.

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+

Examples using moabb.datasets.Cattan2019_PHMD#

+
Spectral analysis of the trials +

Spectral analysis of the trials

+
Spectral analysis of the trials
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Cattan2019_VR.html b/docs/generated/moabb.datasets.Cattan2019_VR.html new file mode 100644 index 00000000..b0259ea2 --- /dev/null +++ b/docs/generated/moabb.datasets.Cattan2019_VR.html @@ -0,0 +1,694 @@ + + + + + + + + + + + + moabb.datasets.Cattan2019_VR — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Cattan2019_VR#

+
+
+class moabb.datasets.Cattan2019_VR(virtual_reality=False, screen_display=True)[source]#
+

Dataset of an EEG-based BCI experiment in Virtual Reality using P300.

+

We describe the experimental procedures for a dataset that we have made publicly +available at https://doi.org/10.5281/zenodo.2605204 in mat (Mathworks, Natick, USA) +and csv formats [1]. This dataset contains electroencephalographic recordings on 21 +subjects doing a visual P300 experiment on non-VR (PC display) and VR (virtual +reality). The visual P300 is an event-related potential elicited by a visual +stimulation, peaking 240-600 ms after stimulus onset. The experiment was designed +in order to compare the use of a P300-based brain-computer interface on a PC and +with a virtual reality headset, concerning the physiological, subjective and +performance aspects. The brain-computer interface is based on electroencephalography +(EEG). EEG data were recorded thanks to 16 electrodes. The virtual reality headset +consisted of a passive head-mounted display, that is, a head-mounted display which +does not include any electronics at the exception of a smartphone. A full description +of the experiment is available at https://hal.archives-ouvertes.fr/hal-02078533.

+

See the example plot_vr_pc_p300_different_epoch_size to compare the performance +between PC and VR.

+
+
Parameters:
+
    +
  • virtual_reality (bool (default False)) – if True, return runs corresponding to P300 experiment on virtual reality.

  • +
  • screen_display (bool (default True)) – if True, return runs corresponding to P300 experiment on personal computer.

  • +
+
+
+

Notes

+
+

Note

+

Cattan2019_VR was previously named VirtualReality. VirtualReality will be removed in version 1.1.

+
+
+

New in version 0.5.0.

+
+

References

+
+
+[1] +

G. Cattan, A. Andreev, P. L. C. Rodrigues, and M. Congedo (2019). +Dataset of an EEG-based BCI experiment in Virtual Reality and +on a Personal Computer. Research Report, GIPSA-lab; IHMTEK. +https://doi.org/10.5281/zenodo.2605204

+
+
+
+

New in version 0.5.0.

+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+
+get_block_repetition(paradigm, subjects, block_list, repetition_list)[source]#
+

Select data for all provided subjects, blocks and repetitions. Each +subject has 12 blocks of 5 repetitions.

+

The returned data is a dictionary with the following structure:

+
data = {'subject_id' :
+            {'session_id':
+                {'run_id': raw}
+            }
+        }
+
+
+
+

See also

+

BaseDataset.get_data

+
+
+
Parameters:
+
    +
  • subjects (List of int) – List of subject number

  • +
  • block_list (List of int) – List of block number (from 0 to 11)

  • +
  • repetition_list (List of int) – List of repetition number inside a block (from 0 to 4)

  • +
+
+
Returns:
+

data – dict containing the raw data

+
+
Return type:
+

Dict

+
+
+
+ +
+ +
+

Examples using moabb.datasets.Cattan2019_VR#

+
Example of P300 classification with different epoch size. +

sphx_glr_auto_examples_noplot_vr_pc_p300_different_epoch_size.py

+
Example of P300 classification with different epoch size.
+
Tutorial 5: Creating a dataset class +

Tutorial 5: Creating a dataset class

+
Tutorial 5: Creating a dataset class
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Cho2017.html b/docs/generated/moabb.datasets.Cho2017.html new file mode 100644 index 00000000..e1234fd4 --- /dev/null +++ b/docs/generated/moabb.datasets.Cho2017.html @@ -0,0 +1,664 @@ + + + + + + + + + + + + moabb.datasets.Cho2017 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Cho2017#

+
+
+class moabb.datasets.Cho2017[source]#
+

Motor Imagery dataset from Cho et al 2017.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

Cho2017

52

64

2

100

3s

512Hz

1

+
+

Dataset from the paper [1].

+

Dataset Description

+

We conducted a BCI experiment for motor imagery movement (MI movement) +of the left and right hands with 52 subjects (19 females, mean age ± SD +age = 24.8 ± 3.86 years); Each subject took part in the same experiment, +and subject ID was denoted and indexed as s1, s2, …, s52. +Subjects s20 and s33 were both-handed, and the other 50 subjects +were right-handed.

+

EEG data were collected using 64 Ag/AgCl active electrodes. +A 64-channel montage based on the international 10-10 system was used to +record the EEG signals with 512 Hz sampling rates. +The EEG device used in this experiment was the Biosemi ActiveTwo system. +The BCI2000 system 3.0.2 was used to collect EEG data and present +instructions (left hand or right hand MI). Furthermore, we recorded +EMG as well as EEG simultaneously with the same system and sampling rate +to check actual hand movements. Two EMG electrodes were attached to the +flexor digitorum profundus and extensor digitorum on each arm.

+

Subjects were asked to imagine the hand movement depending on the +instruction given. Five or six runs were performed during the MI +experiment. After each run, we calculated the classification +accuracy over one run and gave the subject feedback to increase motivation. +Between each run, a maximum 4-minute break was given depending on +the subject’s demands.

+

References

+
+
+[1] +

Cho, H., Ahn, M., Ahn, S., Kwon, M. and Jun, S.C., 2017. +EEG datasets for motor imagery brain computer interface. +GigaScience. https://doi.org/10.1093/gigascience/gix034

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.DemonsP300.html b/docs/generated/moabb.datasets.DemonsP300.html new file mode 100644 index 00000000..2fdc98c4 --- /dev/null +++ b/docs/generated/moabb.datasets.DemonsP300.html @@ -0,0 +1,697 @@ + + + + + + + + + + + + moabb.datasets.DemonsP300 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.DemonsP300#

+
+
+class moabb.datasets.DemonsP300[source]#
+

Visual P300 dataset recorded in Virtual Reality (VR) game Raccoons +versus Demons.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Trials / class

Trials length

Sampling rate

#Sessions

DemonsP300

60

8

935 NT / 50 T

1s

500Hz

1

+
+
+

Danger

+

This dataset contains major unresolved issues and could removed in the near futur. Use it in a benchmark +at your own risk. See NeuroTechX/moabb#216

+
+

Dataset Description

+

We publish dataset of visual P300 BCI performed in Virtual Reality (VR) game Raccoons versus +Demons (RvD). Data contains reach labels incorporating information about stimulus chosen enabling us +to estimate model’s confidence at each stimulus prediction stage. +target channel contains standard P300 target/non-target labels, +while mult_target channel contains multiclass labels (numbers of activated stimuli).

+

Participants

+

60 healthy participants (23 males) naive to BCI with mean age 28 years from 19 to 45 y.o. took part in the study. +All subject signed informed consent and passed primary prerequisites on their health and condition.

+

Stimulation and EEG recording

+

The EEG was recorded with NVX-52 encephalograph (MCS, Zelenograd, Russia) at 500 Hz. We used 8 sponge +electrodes (Cz, P3, P4, PO3, POz, PO4, O1, O2). Stimuli were presented with HTC Vive Pro VR headset with +TTL hardware sync

+

Experimental procedure

+

Participants were asked to play the P300 BCI game in virtual reality. +BCI was embedded into a game plot with the player posing as a forest warden. +The player was supposed to feed animals and protect them from demons. +Game mechanics consisted in demons jumping (visually activating), +so player have to concentrate on one demon (chosen freely). That produced +P300 response in time of the daemon jump. That was the way to trigger fireball +towards a daemon predicted by classifier from EEG data.

+

More info can be found in [1] [2] [3].

+

References

+
+
+[1] +

Goncharenko V., Grigoryan R., and Samokhina A. (May 12, 2020), +Raccoons vs Demons: multiclass labeled P300 dataset, +https://arxiv.org/abs/2005.02251

+
+
+[2] +

Goncharenko V., Grigoryan R., and Samokhina A., +Approaches to multiclass classification of P300 potential datasets, +Intelligent Data Processing: Theory and Applications:Book of abstract of +the 13th International Conference, Moscow, 2020. — Moscow: Russian +Academy of Sciences, 2020. — 472 p.ISBN 978-5-907366-16-9 +http://www.machinelearning.ru/wiki/images/3/31/Idp20.pdf

+
+
+[3] +

Goncharenko V., Grigoryan R., and Samokhina A., +P300 potentials dataset and approaches to its processing, +Труды 63-й Всероссийской научной конференции МФТИ. 23–29 ноября 2020 +года. Прикладные математика и информатика. — Москва : МФТИ, 2020. – 334 с. +ISBN 978-5-7417-0757-9 +https://mipt.ru/science/5top100/education/courseproposal/%D0%A4%D0%9F%D0%9C%D0%98%20%D1%84%D0%B8%D0%BD%D0%B0%D0%BB-compressed2.pdf

+
+
+
+
+data_path(subject: int, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+
+classmethod read_hdf(filename) ndarray[source]#
+

Reads data from HDF file.

+
+
Returns:
+

array of _act_dtype

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.EPFLP300.html b/docs/generated/moabb.datasets.EPFLP300.html new file mode 100644 index 00000000..918f468b --- /dev/null +++ b/docs/generated/moabb.datasets.EPFLP300.html @@ -0,0 +1,669 @@ + + + + + + + + + + + + moabb.datasets.EPFLP300 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.EPFLP300#

+
+
+class moabb.datasets.EPFLP300[source]#
+

P300 dataset from Hoffmann et al 2008.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Trials / class

Trials length

Sampling rate

#Sessions

EPFLP300

8

32

2753 NT / 551 T

1s

2048Hz

4

+
+

Dataset from the paper [1].

+

Dataset Description

+

In the present work a six-choice P300 paradigm is tested using a population +of five disabled and four able-bodied subjects. Six different images were +flashed in random order with a stimulus interval of 400 ms. Users were +facing a laptop screen on which six im- ages were displayed. The images +showed a television, a telephone, a lamp, a door, a window, and a radio.

+

The images were flashed in random sequences, one image at a time. Each +flash of an image lasted for 100 ms and during the following 300 ms none of +the images was flashed, i.e. the interstimulus interval was 400 ms. The EEG +was recorded at 2048 Hz sampling rate from 32 electrodes placed at the +standard positions of the 10-20 international system. The system was tested +with five disabled and four healthy subjects. The disabled subjects were +all wheelchair-bound but had varying communication and limb muscle control +abilities (Subjects 1 to 5). In particular, Subject 5 was only able +to perform extremely slow and relatively uncontrolled movements with hands +and arms. Due to a severe hypophony and large fluctuations in the level of +alertness, communication with subject 5 was very difficult, which is why +its data is not available in this dataset. Subjects 6 to 9 were PhD +students recruited from our laboratory (all male, age 30 ± 2.3).

+

Each subject completed four recording sessions. The first two sessions were +performed on one day and the last two sessions on another day. For all +subjects the time between the first and the last session was less than two +weeks. Each of the sessions consisted of six runs, one run for each of the +six images. The duration of one run was approximately one minute and the +duration of one session including setup of electrodes and short breaks +between runs was approximately 30 minutes. One session comprised on average +810 trials, and the whole data for one subject consisted on average of 3240 +trials.

+

References

+
+
+[1] +

Hoffmann, U., Vesin, J-M., Ebrahimi, T., Diserens, K., 2008. +An efficient P300-based brain-computer interfacefor disabled +subjects. Journal of Neuroscience Methods . +https://doi.org/10.1016/j.jneumeth.2007.03.005

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.GrosseWentrup2009.html b/docs/generated/moabb.datasets.GrosseWentrup2009.html new file mode 100644 index 00000000..1d97f5a8 --- /dev/null +++ b/docs/generated/moabb.datasets.GrosseWentrup2009.html @@ -0,0 +1,675 @@ + + + + + + + + + + + + moabb.datasets.GrosseWentrup2009 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.GrosseWentrup2009#

+
+
+class moabb.datasets.GrosseWentrup2009[source]#
+

Munich Motor Imagery dataset.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

GrosseWentrup2009

10

128

2

150

7s

500Hz

1

+
+

Motor imagery dataset from Grosse-Wentrup et al. 2009 [1].

+

A trial started with the central display of a white fixation cross. After 3 +s, a white arrow was superimposed on the fixation cross, either pointing to +the left or the right. +Subjects were instructed to perform haptic motor imagery of the +left or the right hand during display of the arrow, as indicated by the +direction of the arrow. After another 7 s, the arrow was removed, +indicating the end of the trial and start of the next trial. While subjects +were explicitly instructed to perform haptic motor imagery with the +specified hand, i.e., to imagine feeling instead of visualizing how their +hands moved, the exact choice of which type of imaginary movement, i.e., +moving the fingers up and down, gripping an object, etc., was left +unspecified. +A total of 150 trials per condition were carried out by each subject, +with trials presented in pseudorandomized order.

+

Ten healthy subjects (S1–S10) participated in the experimental +evaluation. Of these, two were females, eight were right handed, and their +average age was 25.6 years with a standard deviation of 2.5 years. Subject +S3 had already participated twice in a BCI experiment, while all other +subjects were naive to BCIs. EEG was recorded at M=128 electrodes placed +according to the extended 10–20 system. Data were recorded at 500 Hz with +electrode Cz as reference. Four BrainAmp amplifiers were used for this +purpose, using a temporal analog high-pass filter with a time constant of +10 s. The data were re-referenced to common average reference +offline. Electrode impedances were below 10 kΩ for all electrodes and +subjects at the beginning of each recording session. No trials were +rejected and no artifact correction was performed. For each subject, the +locations of the 128 electrodes were measured in three dimensions using a +Zebris ultrasound tracking system and stored for further offline analysis.

+

References

+
+
+[1] +

Grosse-Wentrup, Moritz, et al. “Beamforming in noninvasive +brain–computer interfaces.” IEEE Transactions on Biomedical +Engineering 56.4 (2009): 1209-1219.

+
+
+

Notes

+
+

Note

+

GrosseWentrup2009 was previously named MunichMI. MunichMI will be removed in version 1.1.

+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Huebner2017.html b/docs/generated/moabb.datasets.Huebner2017.html new file mode 100644 index 00000000..48f64cfc --- /dev/null +++ b/docs/generated/moabb.datasets.Huebner2017.html @@ -0,0 +1,638 @@ + + + + + + + + + + + + moabb.datasets.Huebner2017 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Huebner2017#

+
+
+class moabb.datasets.Huebner2017(interval=None, raw_slice_offset=None, use_blocks_as_sessions=True)[source]#
+

Learning from label proportions for a visual matrix speller (ERP) +dataset from Hübner et al 2017 [1].

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Trials / class

Trials length

Sampling rate

#Sessions

Huebner2017

13

31

364 NT / 112 T

0.9s

1000Hz

3

+
+

Dataset description

+

The subjects were asked to spell the sentence: “Franzy jagt im komplett verwahrlosten Taxi quer durch Freiburg”. +The sentence was chosen because it contains each letter used in German at least once. Each subject spelled this +sentence three times. The stimulus onset asynchrony (SOA) was 250 ms (corresponding to 15 frames on the LCD screen +utilized) while the stimulus duration was 100 ms (corresponding to 6 frames on the LCD screen utilized). For each +character, 68 highlighting events occurred and a total of 63 characters were spelled three times. This resulted in +a total of 68 ⋅ 63 ⋅ 3 = 12852 EEG epochs per subject. Spelling one character took around 25 s including 4 s for +cueing the current symbol, 17 s for highlighting and 4 s to provide feedback to the user. Assuming a perfect +decoding, these timing constraints would allow for a maximum spelling speed of 2.4 characters per minute. Fig 1 +shows the complete experimental structure and how LLP is used to reconstruct average target and non-target ERP +responses.

+

Subjects were placed in a chair at 80 cm distance from a 24-inch flat screen. EEG signals from 31 passive Ag/AgCl +electrodes (EasyCap) were recorded, which were placed approximately equidistantly according to the extended +10–20 system, and whose impedances were kept below 20 kΩ. All channels were referenced against the nose and the +ground was at FCz. The signals were registered by multichannel EEG amplifiers (BrainAmp DC, Brain Products) at a +sampling rate of 1 kHz. To control for vertical ocular movements and eye blinks, we recorded with an EOG electrode +placed below the right eye and referenced against the EEG channel Fp2 above the eye. In addition, pulse and +breathing activity were recorded.

+
+
Parameters:
+
    +
  • interval (array_like) – range/interval in milliseconds in which the brain response/activity relative to an event/stimulus onset lies in. +Default is set to [-.2, .7].

  • +
  • raw_slice_offset (int, None) – defines the crop offset in milliseconds before the first and after the last event (target or non-targeet) onset. +Default None which crops with an offset 2,000 ms.

  • +
+
+
+

References

+
+
+[1] +

Hübner, D., Verhoeven, T., Schmid, K., Müller, K. R., Tangermann, M., & Kindermans, P. J. (2017) +Learning from label proportions in brain-computer interfaces: Online unsupervised learning with guarantees. +PLOS ONE 12(4): e0175856. +https://doi.org/10.1371/journal.pone.0175856

+
+
+
+

New in version 0.4.5.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Huebner2018.html b/docs/generated/moabb.datasets.Huebner2018.html new file mode 100644 index 00000000..8270c175 --- /dev/null +++ b/docs/generated/moabb.datasets.Huebner2018.html @@ -0,0 +1,630 @@ + + + + + + + + + + + + moabb.datasets.Huebner2018 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Huebner2018#

+
+
+class moabb.datasets.Huebner2018(interval=None, raw_slice_offset=None, use_blocks_as_sessions=True)[source]#
+

Mixture of LLP and EM for a visual matrix speller (ERP) dataset from +Hübner et al 2018 [1].

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Trials / class

Trials length

Sampling rate

#Sessions

Huebner2018

12

31

364 NT / 112 T

0.9s

1000Hz

3

+
+

Dataset description

+

Within a single session, a subject was asked to spell the beginning of a sentence in each of three blocks.The text +consists of the 35 symbols “Franzy jagt im Taxi quer durch das ”. Each block, one of the three decoding +algorithms (EM, LLP, MIX) was used in order to guess the attended symbol. The order of the blocks was +pseudo-randomized over subjects, such that each possible order of the three decoding algorithms was used twice. +This randomization should reduce systematic biases by order effects or temporal effects, e.g., due to fatigue or +task-learning.

+

A trial describes the process of spelling one character. Each of the 35 trials per block contained 68 highlighting +events. The stimulus onset asynchrony (SOA) was 250 ms and the stimulus duration was 100 ms leading to an +interstimulus interval (ISI) of 150 ms.

+
+
Parameters:
+
    +
  • interval (array_like) – range/interval in milliseconds in which the brain response/activity relative to an event/stimulus onset lies in. +Default is set to [-.2, .7].

  • +
  • raw_slice_offset (int, None) – defines the crop offset in milliseconds before the first and after the last event (target or non-targeet) onset. +Default None which crops with an offset 2,000 ms.

  • +
+
+
+

References

+
+
+[1] +

Huebner, D., Verhoeven, T., Mueller, K. R., Kindermans, P. J., & Tangermann, M. (2018). +Unsupervised learning for brain-computer interfaces based on event-related potentials: Review and online comparison [research frontier]. +IEEE Computational Intelligence Magazine, 13(2), 66-77. +https://doi.org/10.1109/MCI.2018.2807039

+
+
+
+

New in version 0.4.5.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Kalunga2016.html b/docs/generated/moabb.datasets.Kalunga2016.html new file mode 100644 index 00000000..a53ab415 --- /dev/null +++ b/docs/generated/moabb.datasets.Kalunga2016.html @@ -0,0 +1,675 @@ + + + + + + + + + + + + moabb.datasets.Kalunga2016 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Kalunga2016#

+
+
+class moabb.datasets.Kalunga2016[source]#
+

SSVEP Exo dataset.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials length

Sampling rate

#Sessions

Kalunga2016

12

8

4

16

2s

256Hz

1

+
+

SSVEP dataset from E. Kalunga PhD in University of Versailles [1].

+

The datasets contains recording from 12 male and female subjects aged +between 20 and 28 years. Informed consent was obtained from all subjects, +each one has signed a form attesting her or his consent. The subject sits +in an electric wheelchair, his right upper limb is resting on the +exoskeleton. The exoskeleton is functional but is not used during the +recording of this experiment.

+

A panel of size 20x30 cm is attached on the left side of the chair, with +3 groups of 4 LEDs blinking at different frequencies. Even if the panel +is on the left side, the user could see it without moving its head. The +subjects were asked to sit comfortably in the wheelchair and to follow the +auditory instructions, they could move and blink freely.

+

A sequence of trials is proposed to the user. A trial begin by an audio cue +indicating which LED to focus on, or to focus on a fixation point set at an +equal distance from all LEDs for the reject class. A trial lasts 5 seconds +and there is a 3 second pause between each trial. The evaluation is +conducted during a session consisting of 32 trials, with 8 trials for each +frequency (13Hz, 17Hz and 21Hz) and 8 trials for the reject class, i.e. +when the subject is not focusing on any specific blinking LED.

+

There is between 2 and 5 sessions for each user, recorded on different +days, by the same operators, on the same hardware and in the same +conditions.

+

References

+
+
+[1] +

Emmanuel K. Kalunga, Sylvain Chevallier, Quentin Barthelemy. “Online +SSVEP-based BCI using Riemannian Geometry”. Neurocomputing, 2016. +arXiv report: https://arxiv.org/abs/1501.03227

+
+
+

Notes

+
+

Note

+

Kalunga2016 was previously named SSVEPExo. SSVEPExo will be removed in version 1.1.

+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+

Examples using moabb.datasets.Kalunga2016#

+
Cross-Subject SSVEP +

Cross-Subject SSVEP

+
Cross-Subject SSVEP
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Lee2019_ERP.html b/docs/generated/moabb.datasets.Lee2019_ERP.html new file mode 100644 index 00000000..c16d6885 --- /dev/null +++ b/docs/generated/moabb.datasets.Lee2019_ERP.html @@ -0,0 +1,665 @@ + + + + + + + + + + + + moabb.datasets.Lee2019_ERP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Lee2019_ERP#

+
+
+class moabb.datasets.Lee2019_ERP(train_run=True, test_run=None, resting_state=False, sessions=(1, 2))[source]#
+

BMI/OpenBMI dataset for P300.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Trials / class

Trials length

Sampling rate

#Sessions

Lee2019_ERP

54

62

6900 NT / 1380 T

1s

1000Hz

2

+
+

Dataset from Lee et al 2019 [1].

+

Dataset Description

+

EEG signals were recorded with a sampling rate of 1,000 Hz and +collected with 62 Ag/AgCl electrodes. The EEG amplifier used +in the experiment was a BrainAmp (Brain Products; Munich, +Germany). The channels were nasion-referenced and grounded +to electrode AFz. Additionally, an EMG electrode recorded from +each flexor digitorum profundus muscle with the olecranon +used as reference. The EEG/EMG channel configuration and +indexing numbers are described in Fig. 1. The impedances of the +EEG electrodes were maintained below 10 k during the entire +experiment.

+

ERP paradigm +The interface layout of the speller followed the typical design +of a row-column speller. The six rows and six columns were +configured with 36 symbols (A to Z, 1 to 9, and _). Each symbol +was presented equally spaced. To enhance the +signal quality, two additional settings were incorporated into +the original row-column speller design, namely, random-set +presentation and face stimuli. These additional settings +help to elicit stronger ERP responses by minimizing adjacency +distraction errors and by presenting a familiar face image. The +stimulus-time interval was set to 80 ms, and the inter-stimulus +interval (ISI) to 135 ms. A single iteration of stimulus presentation +in all rows and columns was considered a sequence. Therefore, +one sequence consisted of 12 stimulus flashes. A maximum +of five sequences (i.e., 60 flashes) was allotted without prolonged +inter-sequence intervals for each target character. After the end +of five sequences, 4.5 s were given to the user for identifying, locating, +and gazing at the next target character. The participant +was instructed to attend to the target symbol by counting the +number of times each target character had been flashed. +In the training session, subjects were asked to copy-spell +a given sentence, “NEURAL NETWORKS AND DEEP LEARNING” +(33 characters including spaces) by gazing at the target character +on the screen. The training session was performed in the offline +condition, and no feedback was provided to the subject during +the EEG recording. In the test session, subjects were instructed to +copy-spell “PATTERN RECOGNITION MACHINE LEARNING” +(36 characters including spaces), and the real-time EEG data were +analyzed based on the classifier that was calculated from the +training session data. The selected character from the subject’s +current EEG data was displayed in the top left area of the screen +at the end of the presentation (i.e., after five sequences). +Per participant, the collected EEG data for the ERP experiment consisted +of 1,980 and 2,160 trials (samples) for training and test phase, respectively.

+
+
Parameters:
+
    +
  • train_run (bool (default True)) – if True, return runs corresponding to the training/offline phase (see paper).

  • +
  • test_run (bool (default: False for MI and SSVEP paradigms, True for ERP)) – if True, return runs corresponding to the test/online phase (see paper). Beware that test_run +for MI and SSVEP do not have labels associated with trials: these runs could not be used in +classification tasks.

  • +
  • resting_state (bool (default False)) – if True, return runs corresponding to the resting phases before and after recordings (see paper).

  • +
  • sessions (list of int (default [1,2])) – the list of the sessions to load (2 available).

  • +
+
+
+

References

+
+
+[1] +

Lee, M. H., Kwon, O. Y., Kim, Y. J., Kim, H. K., Lee, Y. E., +Williamson, J., … Lee, S. W. (2019). EEG dataset and OpenBMI +toolbox for three BCI paradigms: An investigation into BCI +illiteracy. GigaScience, 8(5), 1–16. +https://doi.org/10.1093/gigascience/giz002

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Lee2019_MI.html b/docs/generated/moabb.datasets.Lee2019_MI.html new file mode 100644 index 00000000..9119bc65 --- /dev/null +++ b/docs/generated/moabb.datasets.Lee2019_MI.html @@ -0,0 +1,646 @@ + + + + + + + + + + + + moabb.datasets.Lee2019_MI — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Lee2019_MI#

+
+
+class moabb.datasets.Lee2019_MI(train_run=True, test_run=None, resting_state=False, sessions=(1, 2))[source]#
+

BMI/OpenBMI dataset for MI.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

Lee2019_MI

54

62

2

100

4s

1000Hz

2

+
+

Dataset from Lee et al 2019 [1].

+

Dataset Description

+

EEG signals were recorded with a sampling rate of 1,000 Hz and +collected with 62 Ag/AgCl electrodes. The EEG amplifier used +in the experiment was a BrainAmp (Brain Products; Munich, +Germany). The channels were nasion-referenced and grounded +to electrode AFz. Additionally, an EMG electrode recorded from +each flexor digitorum profundus muscle with the olecranon +used as reference. The EEG/EMG channel configuration and +indexing numbers are described in Fig. 1. The impedances of the +EEG electrodes were maintained below 10 k during the entire +experiment.

+

MI paradigm +The MI paradigm was designed following a well-established system protocol. +For all blocks, the first 3 s of each trial began +with a black fixation cross that appeared at the center of the +monitor to prepare subjects for the MI task. Afterwards, the subject +performed the imagery task of grasping with the appropriate +hand for 4 s when the right or left arrow appeared as a visual cue. +After each task, the screen remained blank for 6 s (± 1.5 s). The +experiment consisted of training and test phases; each phase +had 100 trials with balanced right and left hand imagery tasks. +During the online test phase, the fixation cross appeared at the +center of the monitor and moved right or left, according to the +real-time classifier output of the EEG signal.

+
+
Parameters:
+
    +
  • train_run (bool (default True)) – if True, return runs corresponding to the training/offline phase (see paper).

  • +
  • test_run (bool (default: False for MI and SSVEP paradigms, True for ERP)) – if True, return runs corresponding to the test/online phase (see paper). Beware that test_run +for MI and SSVEP do not have labels associated with trials: these runs could not be used in +classification tasks.

  • +
  • resting_state (bool (default False)) – if True, return runs corresponding to the resting phases before and after recordings (see paper).

  • +
  • sessions (list of int (default [1,2])) – the list of the sessions to load (2 available).

  • +
+
+
+

References

+
+
+[1] +

Lee, M. H., Kwon, O. Y., Kim, Y. J., Kim, H. K., Lee, Y. E., +Williamson, J., … Lee, S. W. (2019). EEG dataset and OpenBMI +toolbox for three BCI paradigms: An investigation into BCI +illiteracy. GigaScience, 8(5), 1–16. +https://doi.org/10.1093/gigascience/giz002

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Lee2019_SSVEP.html b/docs/generated/moabb.datasets.Lee2019_SSVEP.html new file mode 100644 index 00000000..ee6640a7 --- /dev/null +++ b/docs/generated/moabb.datasets.Lee2019_SSVEP.html @@ -0,0 +1,648 @@ + + + + + + + + + + + + moabb.datasets.Lee2019_SSVEP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Lee2019_SSVEP#

+
+
+class moabb.datasets.Lee2019_SSVEP(train_run=True, test_run=None, resting_state=False, sessions=(1, 2))[source]#
+

BMI/OpenBMI dataset for SSVEP.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials length

Sampling rate

#Sessions

Lee2019_SSVEP

54

62

4

50

4s

1000Hz

2

+
+

Dataset from Lee et al 2019 [1].

+

Dataset Description

+

EEG signals were recorded with a sampling rate of 1,000 Hz and +collected with 62 Ag/AgCl electrodes. The EEG amplifier used +in the experiment was a BrainAmp (Brain Products; Munich, +Germany). The channels were nasion-referenced and grounded +to electrode AFz. Additionally, an EMG electrode recorded from +each flexor digitorum profundus muscle with the olecranon +used as reference. The EEG/EMG channel configuration and +indexing numbers are described in Fig. 1. The impedances of the +EEG electrodes were maintained below 10 k during the entire +experiment.

+

SSVEP paradigm +Four target SSVEP stimuli were designed to flicker at 5.45, 6.67, +8.57, and 12 Hz and were presented in four positions (down, +right, left, and up, respectively) on a monitor. The designed +paradigm followed the conventional types of SSVEP-based BCI +systems that require four-direction movements. Partici- +pants were asked to fixate the center of a black screen and then +to gaze in the direction where the target stimulus was high- +lighted in a different color. Each SSVEP stimulus +was presented for 4 s with an ISI of 6 s. Each target frequency +was presented 25 times. Therefore, the corrected EEG data had +100 trials (4 classes x 25 trials) in the offline training phase and +another 100 trials in the online test phase. Visual feedback was +presented in the test phase; the estimated target frequency was +highlighted for 1 s with a red border at the end of each trial.

+
+
Parameters:
+
    +
  • train_run (bool (default True)) – if True, return runs corresponding to the training/offline phase (see paper).

  • +
  • test_run (bool (default: False for MI and SSVEP paradigms, True for ERP)) – if True, return runs corresponding to the test/online phase (see paper). Beware that test_run +for MI and SSVEP do not have labels associated with trials: these runs could not be used in +classification tasks.

  • +
  • resting_state (bool (default False)) – if True, return runs corresponding to the resting phases before and after recordings (see paper).

  • +
  • sessions (list of int (default [1,2])) – the list of the sessions to load (2 available).

  • +
+
+
+

References

+
+
+[1] +

Lee, M. H., Kwon, O. Y., Kim, Y. J., Kim, H. K., Lee, Y. E., +Williamson, J., … Lee, S. W. (2019). EEG dataset and OpenBMI +toolbox for three BCI paradigms: An investigation into BCI +illiteracy. GigaScience, 8(5), 1–16. +https://doi.org/10.1093/gigascience/giz002

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.MAMEM1.html b/docs/generated/moabb.datasets.MAMEM1.html new file mode 100644 index 00000000..de7e4bd4 --- /dev/null +++ b/docs/generated/moabb.datasets.MAMEM1.html @@ -0,0 +1,698 @@ + + + + + + + + + + + + moabb.datasets.MAMEM1 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.MAMEM1#

+
+
+class moabb.datasets.MAMEM1[source]#
+

SSVEP MAMEM 1 dataset.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials length

Sampling rate

#Sessions

MAMEM1

10

256

5

12-15

3s

250Hz

1

+
+

Dataset from [1].

+

EEG signals with 256 channels captured from 11 subjects executing a +SSVEP-based experimental protocol. Five different frequencies +(6.66, 7.50, 8.57, 10.00 and 12.00 Hz) have been used for the visual +stimulation,and the EGI 300 Geodesic EEG System, using a +stimulation, HydroCel Geodesic Sensor Net (HCGSN) and a sampling rate of +250 Hz has been used for capturing the signals.

+

Check the technical report [2] for more detail. +From [1], subjects were exposed to non-overlapping flickering lights from five +magenta boxes with frequencies [6.66Hz, 7.5Hz, 8.57Hz 10Hz and 12Hz]. +256 channel EEG recordings were captured.

+

Each session of the experimental procedure consisted of the following:

+
    +
  1. 100 seconds of rest.

  2. +
  3. An adaptation period in which the subject is exposed to eight +5 second windows of flickering from a magenta box. Each flickering +window is of a single isolated frequency, randomly chosen from the +above set, specified in the FREQUENCIES1.txt file under +‘adaptation’. The individual flickering windows are separated by 5 +seconds of rest.

  4. +
  5. 30 seconds of rest.

  6. +
  7. For each of the frequencies from the above set in ascending order, +also specified in FREQUENCIES1.txt under ‘main trials’:

    +
      +
    1. +
      Three 5 second windows of flickering at the chosen frequency,

      separated by 5 seconds of rest.

      +
      +
      +
    2. +
    3. 30 seconds of rest.

    4. +
    +
  8. +
+

This gives a total of 15 flickering windows, or 23 including the +adaptation period.

+

The order of chosen frequencies is the same for each session, although +there are small-moderate variations in the actual frequencies of each +individual window. The .freq annotations list the different frequencies at +a higher level of precision.

+

Note: Each ‘session’ in experiment 1 includes an adaptation period, unlike +experiment 2 and 3 where each subject undergoes only one adaptation period +before their first ‘session’.

+

From [3]:

+

Eligible signals: The EEG signal is sensitive to external factors that have +to do with the environment or the configuration of the acquisition setup +The research stuff was responsible for the elimination of trials that were +considered faulty. As a result the following sessions were noted and +excluded from further analysis: +1. S003, during session 4 the stimulation program crashed +2. S004, during session 2 the stimulation program crashed, and +3. S008, during session 4 the Stim Tracker was detuned. +Furthermore, we must also note that subject S001 participated in 3 sessions +and subjects S003 and S004 participated in 4 sessions, compared to all +other subjects that participated in 5 sessions (NB: in fact, there is only +3 sessions for subjects 1, 3 and 8, and 4 sessions for subject 4 available +to download). As a result, the utilized dataset consists of 1104 trials of +5 seconds each.

+

Flickering frequencies: Usually the refresh rate for an LCD Screen is 60 Hz +creating a restriction to the number of frequencies that can be selected. +Specifically, only the frequencies that when divided with the refresh rate +of the screen result in an integer quotient could be selected. As a result, +the frequendies that could be obtained were the following: 30.00. 20.00, +15.00, 1200, 10.00, 857. 7.50 and 6.66 Hz. In addition, it is also +important to avoid using frequencies that are multiples of another +frequency, for example making the choice to use 10.00Hz prohibits the use +of 20.00 and 30.00 Mhz. With the previously described limitations in mind, +the selected frequencies for the experiment were: 12.00, 10.00, 8.57, 7.50 +and 6.66 Hz.

+

Stimuli Layout: In an effort to keep the experimental process as simple as +possible, we used only one flickering box instead of more common choices, +such as 4 or 5 boxes flickering simultaneously The fact that the subject +could focus on one stimulus without having the distraction of other +flickering sources allowed us to minimize the noise of our signals and +verify the appropriateness of our acquisition setup Nevertheless, having +concluded the optimal configuration for analyzing the EEG signals, the +experiment will be repeated with more concurrent visual stimulus.

+

Trial duration: The duration of each trial was set to 5 seconds, as this +time was considered adequate to allow the occipital part of the bran to +mimic the stimulation frequency and still be small enough for making a +selection in the context

+

References

+
+
+[1] +(1,2) +

MAMEM Steady State Visually Evoked Potential EEG Database +https://archive.physionet.org/physiobank/database/mssvepdb/

+
+
+[2] +

V.P. Oikonomou et al, 2016, Comparative evaluation of state-of-the-art +algorithms for SSVEP-based BCIs. arXiv. +<http://arxiv.org/abs/1602.00904>-

+
+ +
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.MAMEM2.html b/docs/generated/moabb.datasets.MAMEM2.html new file mode 100644 index 00000000..0d5912b8 --- /dev/null +++ b/docs/generated/moabb.datasets.MAMEM2.html @@ -0,0 +1,665 @@ + + + + + + + + + + + + moabb.datasets.MAMEM2 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.MAMEM2#

+
+
+class moabb.datasets.MAMEM2[source]#
+

SSVEP MAMEM 2 dataset.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials length

Sampling rate

#Sessions

MAMEM2

10

256

5

20-30

3s

250Hz

1

+
+

Dataset from [1].

+

EEG signals with 256 channels captured from 11 subjects executing a +SSVEP-based experimental protocol. Five different frequencies +(6.66, 7.50, 8.57, 10.00 and 12.00 Hz) have been used for the visual +stimulation,and the EGI 300 Geodesic EEG System, using a +stimulation, HydroCel Geodesic Sensor Net (HCGSN) and a sampling rate of +250 Hz has been used for capturing the signals.

+

Subjects were exposed to flickering lights from five violet boxes with +frequencies [6.66Hz, 7.5Hz, 8.57Hz, 10Hz, and 12Hz] simultaneously. Prior +to and during each flicking window, one of the boxes is marked by a yellow +arrow indicating the box to be focused on by the subject. 256 channel EEG +recordings were captured.

+

From [2], each subject underwent a single adaptation period before the first of +their 5 sessions (unlike experiment 1 in which each session began with its own +adaptation period). In the adaptation period, the subject is exposed to ten +5-second flickering windows from the five boxes simultaneously, with the +target frequencies specified in the FREQUENCIES2.txt file under +‘adaptation’. The flickering windows are separated by 5 seconds of rest, +and the 100s adaptation period precedes the first session by 30 seconds.

+

Each session consisted of the following: +For the series of frequencies specified in the FREQUENCIES2.txt file under +‘sessions’: +A 5 second window with all boxes flickering and the subject focusing +on the specified frequency’s marked box, followed by 5 seconds of rest. +This gives a total of 25 flickering windows for each session (not +including the first adaptation period). Five minutes of rest before +the next session (not including the 5th session).

+

The order of chosen frequencies is the same for each session, although +there are small-moderate variations in the actual frequencies of each +individual window. +Note: Each ‘session’ in experiment 1 includes an adaptation period, +unlike experiment 2 and 3 where each subject undergoes only one adaptation +period before their first ‘session’.

+

Waveforms and Annotations +File names are in the form T0NNn, where NN is the subject number and n is +a - e for the session letter or x for the adaptation period. Each session +lasts in the order of several minutes and is sampled at 250Hz. Each session +and adaptation period has the following files: +A waveform file of the EEG signals (.dat) along with its header file +(.hea). If the channel corresponds to an international 10-20 channel then +it is labeled as such. Otherwise, it is just labeled ‘EEG’. An annotation +file (.flash) containing the locations of each individual flash. An +annotation file (.win) containing the locations of the beginning and end +of each 5 second flickering window. The annotations are labeled as ‘(’ for +start and ‘)’ for stop, along with auxiliary strings indicating the focal +frequency of the flashing windows.

+

The FREQUENCIES2.txt file indicates the approximate marked frequencies of +the flickering windows, equal for each session, adaptation, and subject. +These values are equal to those contained in the .win annotations.

+

Observed artifacts: +During the stimulus presentation to subject S007 the research stuff +noted that the subject had a tendency to eye blink. As a result the +interference, in matters of artifacts, on the recorded signal is expected +to be high.

+

References

+
+
+[1] +

MAMEM Steady State Visually Evoked Potential EEG Database +https://archive.physionet.org/physiobank/database/mssvepdb/

+
+ +
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.MAMEM3.html b/docs/generated/moabb.datasets.MAMEM3.html new file mode 100644 index 00000000..5cc26040 --- /dev/null +++ b/docs/generated/moabb.datasets.MAMEM3.html @@ -0,0 +1,679 @@ + + + + + + + + + + + + moabb.datasets.MAMEM3 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.MAMEM3#

+
+
+class moabb.datasets.MAMEM3[source]#
+

SSVEP MAMEM 3 dataset.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials length

Sampling rate

#Sessions

MAMEM3

10

14

4

20-30

3s

128Hz

1

+
+

Dataset from [1].

+

EEG signals with 14 channels captured from 11 subjects executing a +SSVEP-based experimental protocol. Five different frequencies +(6.66, 7.50, 8.57, 10.00 and 12.00 Hz) have been used for the visual +stimulation, and the Emotiv EPOC, using 14 wireless channels has been used +for capturing the signals.

+

Subjects were exposed to flickering lights from five magenta boxes with +frequencies [6.66Hz, 7.5Hz, 8.57Hz, 10Hz and 12Hz] simultaneously. Prior +to and during each flicking window, one of the boxes is marked by a yellow +arrow indicating the box to be focused on by the subject. The Emotiv EPOC +14 channel wireless EEG headset was used to capture the subjects’ signals.

+

Each subject underwent a single adaptation period before the first of their +5 sessions (unlike experiment 1 in which each session began with its own +adaptation period). In the adaptation period, the subject is exposed to ten +5-second flickering windows from the five boxes simultaneously, with the +target frequencies specified in the FREQUENCIES3.txt file under +‘adaptation’. The flickering windows are separated by 5 seconds of rest, +and the 100s adaptation period precedes the first session by 30 seconds.

+

Each session consisted of the following: +For the series of frequencies specified in the FREQUENCIES3.txt file under +‘sessions’: +A 5 second window with all boxes flickering and the subject focusing on +the specified frequency’s marked box, followed by 5 seconds of rest. +Between the 12th and 13th flickering window, there is a 30s resting +period. This gives a total of 25 flickering windows for each session +(not including the first adaptation period). Five minutes of rest +before the next session (not including the 5th session).

+

The order of chosen frequencies is the same for each session, although +there are small-moderate variations in the actual frequencies of each +individual window.

+

Note: Each ‘session’ in experiment 1 includes an adaptation period, unlike +experiment 2 and 3 where each subject undergoes only one adaptation period +before their first ‘session’ [2].

+

Waveforms and Annotations +File names are in the form U0NNn, where NN is the subject number and n is +a - e for the session letter or x for the adaptation period. In addition, +session file names end with either i or ii, corresponding to the first 12 +or second 13 windows of the session respectively. Each session lasts in the +order of several minutes and is sampled at 128Hz. +Each session half and adaptation period has the following files: +A waveform file of the EEG signals (.dat) along with its header file +(.hea). An annotation file (.win) containing the locations of the beginning +and end of each 5 second flickering window. The annotations are labeled as +‘(’ for start and ‘)’ for stop, along with auxiliary strings indicating the +focal frequency of the flashing windows.

+

The FREQUENCIES3.txt file indicates the approximate marked frequencies of +the flickering windows, equal for each session, adaptation, and subject. +These values are equal to those contained in the .win annotations.

+

Trial manipulation: +The trial initiation is defined by an event code (32779) and the +end by another (32780). There are five different labels that indicate the +box subjects were instructed to focus on (1, 2, 3, 4 and 5) and +correspond to frequencies 12.00, 10.00, 8.57, 7.50 and 6.66 Hz respectively. +5 3 2 1 4 5 2 1 4 3 is the trial sequence for the adaptation and +4 2 3 5 1 2 5 4 2 3 1 5 4 3 2 4 1 2 5 3 4 1 3 1 3 is the sequence for each +session.

+

Observed artifacts: +During the stimulus presentation to subject S007 the research staff +noted that the subject had a tendency to eye blink. As a result the +interference, in matters of artifacts, on the recorded signal is expected +to be high.

+

References

+
+
+[1] +

MAMEM Steady State Visually Evoked Potential EEG Database +https://archive.physionet.org/physiobank/database/mssvepdb/

+
+ +
+
+ +
+

Examples using moabb.datasets.MAMEM3#

+
Within Session SSVEP +

Within Session SSVEP

+
Within Session SSVEP
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Nakanishi2015.html b/docs/generated/moabb.datasets.Nakanishi2015.html new file mode 100644 index 00000000..013c4e5a --- /dev/null +++ b/docs/generated/moabb.datasets.Nakanishi2015.html @@ -0,0 +1,647 @@ + + + + + + + + + + + + moabb.datasets.Nakanishi2015 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Nakanishi2015#

+
+
+class moabb.datasets.Nakanishi2015[source]#
+

SSVEP Nakanishi 2015 dataset.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials length

Sampling rate

#Sessions

Nakanishi2015

9

8

12

15

4.15s

256Hz

1

+
+

This dataset contains 12-class joint frequency-phase modulated steady-state +visual evoked potentials (SSVEPs) acquired from 10 subjects used to +estimate an online performance of brain-computer interface (BCI) in the +reference study [1].

+

References

+
+
+[1] +

Masaki Nakanishi, Yijun Wang, Yu-Te Wang and Tzyy-Ping Jung, +“A Comparison Study of Canonical Correlation Analysis Based Methods for +Detecting Steady-State Visual Evoked Potentials,” PLoS One, vol.10, no.10, +e140703, 2015. +http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0140703

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Ofner2017.html b/docs/generated/moabb.datasets.Ofner2017.html new file mode 100644 index 00000000..3fd36067 --- /dev/null +++ b/docs/generated/moabb.datasets.Ofner2017.html @@ -0,0 +1,671 @@ + + + + + + + + + + + + moabb.datasets.Ofner2017 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Ofner2017#

+
+
+class moabb.datasets.Ofner2017(imagined=True, executed=False)[source]#
+

Motor Imagery ataset from Ofner et al 2017.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

Ofner2017

15

61

7

60

3s

512Hz

1

+
+

Upper limb Motor imagery dataset from the paper [1].

+

Dataset description

+

We recruited 15 healthy subjects aged between 22 and 40 years with a mean +age of 27 years (standard deviation 5 years). Nine subjects were female, +and all the subjects except s1 were right-handed.

+

We measured each subject in two sessions on two different days, which were +not separated by more than one week. In the first session the subjects +performed ME, and MI in the second session. The subjects performed six +movement types which were the same in both sessions and comprised of +elbow flexion/extension, forearm supination/pronation and hand open/close; +all with the right upper limb. All movements started at a +neutral position: the hand half open, the lower arm extended to 120 +degree and in a neutral rotation, i.e. thumb on the inner side. +Additionally to the movement classes, a rest class was recorded in which +subjects were instructed to avoid any movement and to stay in the starting +position. In the ME session, we instructed subjects to execute sustained +movements. In the MI session, we asked subjects to perform kinesthetic MI +of the movements done in the ME session (subjects performed one ME run +immediately before the MI session to support kinesthetic MI).

+

The paradigm was trial-based and cues were displayed on a computer screen +in front of the subjects, Fig 2 shows the sequence of the paradigm. +At second 0, a beep sounded and a cross popped up on the computer screen +(subjects were instructed to fixate their gaze on the cross). Afterwards, +at second 2, a cue was presented on the computer screen, indicating the +required task (one out of six movements or rest) to the subjects. At the +end of the trial, subjects moved back to the starting position. In every +session, we recorded 10 runs with 42 trials per run. We presented 6 +movement classes and a rest class and recorded 60 trials per class in a +session.

+

References

+
+
+[1] +

Ofner, P., Schwarz, A., Pereira, J. and Müller-Putz, G.R., 2017. +Upper limb movements can be decoded from the time-domain of +low-frequency EEG. PloS one, 12(8), p.e0182578. +https://doi.org/10.1371/journal.pone.0182578

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None, session=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.PhysionetMI.html b/docs/generated/moabb.datasets.PhysionetMI.html new file mode 100644 index 00000000..ab89c2d2 --- /dev/null +++ b/docs/generated/moabb.datasets.PhysionetMI.html @@ -0,0 +1,682 @@ + + + + + + + + + + + + moabb.datasets.PhysionetMI — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.PhysionetMI#

+
+
+class moabb.datasets.PhysionetMI(imagined=True, executed=False)[source]#
+

Physionet Motor Imagery dataset.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

PhysionetMI

109

64

4

23

3s

160Hz

1

+
+

Physionet MI dataset: https://physionet.org/pn4/eegmmidb/

+

This data set consists of over 1500 one- and two-minute EEG recordings, +obtained from 109 volunteers [2].

+

Subjects performed different motor/imagery tasks while 64-channel EEG were +recorded using the BCI2000 system (http://www.bci2000.org) [1]. +Each subject performed 14 experimental runs: two one-minute baseline runs +(one with eyes open, one with eyes closed), and three two-minute runs of +each of the four following tasks:

+
    +
  1. A target appears on either the left or the right side of the screen. +The subject opens and closes the corresponding fist until the target +disappears. Then the subject relaxes.

  2. +
  3. A target appears on either the left or the right side of the screen. +The subject imagines opening and closing the corresponding fist until +the target disappears. Then the subject relaxes.

  4. +
  5. A target appears on either the top or the bottom of the screen. +The subject opens and closes either both fists (if the target is on top) +or both feet (if the target is on the bottom) until the target +disappears. Then the subject relaxes.

  6. +
  7. A target appears on either the top or the bottom of the screen. +The subject imagines opening and closing either both fists +(if the target is on top) or both feet (if the target is on the bottom) +until the target disappears. Then the subject relaxes.

  8. +
+
+
Parameters:
+
    +
  • imagined (bool (default True)) – if True, return runs corresponding to motor imagination.

  • +
  • executed (bool (default False)) – if True, return runs corresponding to motor execution.

  • +
+
+
+

References

+
+
+[1] +

Schalk, G., McFarland, D.J., Hinterberger, T., Birbaumer, N. and +Wolpaw, J.R., 2004. BCI2000: a general-purpose brain-computer +interface (BCI) system. IEEE Transactions on biomedical engineering, +51(6), pp.1034-1043.

+
+
+[2] +

Goldberger, A.L., Amaral, L.A., Glass, L., Hausdorff, J.M., Ivanov, +P.C., Mark, R.G., Mietus, J.E., Moody, G.B., Peng, C.K., Stanley, +H.E. and PhysioBank, P., PhysioNet: components of a new research +resource for complex physiologic signals Circulation 2000 Volume +101 Issue 23 pp. E215–E220.

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Schirrmeister2017.html b/docs/generated/moabb.datasets.Schirrmeister2017.html new file mode 100644 index 00000000..d1c2600e --- /dev/null +++ b/docs/generated/moabb.datasets.Schirrmeister2017.html @@ -0,0 +1,667 @@ + + + + + + + + + + + + moabb.datasets.Schirrmeister2017 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Schirrmeister2017#

+
+
+class moabb.datasets.Schirrmeister2017[source]#
+

High-gamma dataset described in Schirrmeister et al. 2017.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

Schirrmeister2017

14

128

4

120

4s

500Hz

1

+
+

Dataset from [1]

+

Our “High-Gamma Dataset” is a 128-electrode dataset (of which we later only use +44 sensors covering the motor cortex, (see Section 2.7.1), obtained from 14 +healthy subjects (6 female, 2 left-handed, age 27.2 ± 3.6 (mean ± std)) with +roughly 1000 (963.1 ± 150.9, mean ± std) four-second trials of executed +movements divided into 13 runs per subject. The four classes of movements were +movements of either the left hand, the right hand, both feet, and rest (no +movement, but same type of visual cue as for the other classes). The training +set consists of the approx. 880 trials of all runs except the last two runs, +the test set of the approx. 160 trials of the last 2 runs. This dataset was +acquired in an EEG lab optimized for non-invasive detection of high- frequency +movement-related EEG components (Ball et al., 2008; Darvas et al., 2010).

+

Depending on the direction of a gray arrow that was shown on black back- +ground, the subjects had to repetitively clench their toes (downward arrow), +perform sequential finger-tapping of their left (leftward arrow) or right +(rightward arrow) hand, or relax (upward arrow). The movements were selected +to require little proximal muscular activity while still being complex enough +to keep subjects in- volved. Within the 4-s trials, the subjects performed the +repetitive movements at their own pace, which had to be maintained as long as +the arrow was showing. Per run, 80 arrows were displayed for 4 s each, with 3 +to 4 s of continuous random inter-trial interval. The order of presentation +was pseudo-randomized, with all four arrows being shown every four trials. +Ideally 13 runs were performed to collect 260 trials of each movement and rest. +The stimuli were presented and the data recorded with BCI2000 (Schalk et al., +2004). The experiment was approved by the ethical committee of the University +of Freiburg.

+

References

+
+
+[1] +

Schirrmeister, Robin Tibor, et al. “Deep learning with convolutional +neural networks for EEG decoding and visualization.” Human brain mapping 38.11 +(2017): 5391-5420.

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Shin2017A.html b/docs/generated/moabb.datasets.Shin2017A.html new file mode 100644 index 00000000..2557a7db --- /dev/null +++ b/docs/generated/moabb.datasets.Shin2017A.html @@ -0,0 +1,693 @@ + + + + + + + + + + + + moabb.datasets.Shin2017A — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Shin2017A#

+
+
+class moabb.datasets.Shin2017A(accept=False)[source]#
+

Motor Imagey Dataset from Shin et al 2017.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

Shin2017A

29

30

2

30

10s

200Hz

3

+
+

Dataset from [1].

+
+

Caution

+

You should accept the licence term [2] to download this dataset, using: +Shin2017A(accept=True)

+
+

Data Acquisition

+

EEG and NIRS data was collected in an ordinary bright room. EEG data was +recorded by a multichannel BrainAmp EEG amplifier with thirty active +electrodes (Brain Products GmbH, Gilching, Germany) with linked mastoids +reference at 1000 Hz sampling rate. The EEG amplifier was also used to +measure the electrooculogram (EOG), electrocardiogram (ECG) and respiration +with a piezo based breathing belt. Thirty EEG electrodes were placed on a +custom-made stretchy fabric cap (EASYCAP GmbH, Herrsching am Ammersee, +Germany) and placed according to the international 10-5 system (AFp1, AFp2, +AFF1h, AFF2h, AFF5h, AFF6h, F3, F4, F7, F8, FCC3h, FCC4h, FCC5h, FCC6h, T7, +T8, Cz, CCP3h, CCP4h, CCP5h, CCP6h, Pz, P3, P4, P7, P8, PPO1h, PPO2h, POO1, +POO2 and Fz for ground electrode).

+

NIRS data was collected by NIRScout (NIRx GmbH, Berlin, Germany) at 12.5 Hz +sampling rate. Each adjacent source-detector pair creates one physiological +NIRS channel. Fourteen sources and sixteen detectors resulting in +thirty-six +physiological channels were placed at frontal (nine channels around Fp1, +Fp2, and Fpz), motor (twelve channels around C3 and C4, respectively) and +visual areas (three channels around Oz). The inter-optode distance was 30 +mm. NIRS optodes were fixed on the same cap as the EEG electrodes. Ambient +lights were sufficiently blocked by a firm contact between NIRS optodes and +scalp and use of an opaque cap.

+

EOG was recorded using two vertical (above and below left eye) and two +horizontal (outer canthus of each eye) electrodes. ECG was recorded based +on +Einthoven triangle derivations I and II, and respiration was measured using +a respiration belt on the lower chest. EOG, ECG and respiration were +sampled +at the same sampling rate of the EEG. ECG and respiration data were not +analyzed in this study, but are provided along with the other signals.

+

Experimental Procedure

+

The subjects sat on a comfortable armchair in front of a 50-inch white +screen. The distance between their heads and the screen was 1.6 m. They +were +asked not to move any part of the body during the data recording. The +experiment consisted of three sessions of left and right hand MI (dataset +A)and MA and baseline tasks (taking a rest without any thought) (dataset B) +each. Each session comprised a 1 min pre-experiment resting period, 20 +repetitions of the given task and a 1 min post-experiment resting +period. The task started with 2 s of a visual introduction of the task, +followed by 10 s of a task period and resting period which was given +randomly from 15 to 17 s. At the beginning and end of the task period, a +short beep (250 ms) was played. All instructions were displayed on the +white +screen by a video projector. MI and MA tasks were performed in separate +sessions but in alternating order (i.e., sessions 1, 3 and 5 for MI +(dataset +A) and sessions 2, 4 and 6 for MA (dataset B)). Fig. 2 shows the schematic +diagram of the experimental paradigm. Five sorts of motion artifacts +induced +by eye and head movements (dataset C) were measured. The motion artifacts +were recorded after all MI and MA task recordings. The experiment did not +include the pre- and post-experiment resting state periods.

+

Motor Imagery (Dataset A)

+

For motor imagery, subjects were instructed to perform haptic motor imagery +(i.e. to imagine the feeling of opening and closing their hands as they +were +grabbing a ball) to ensure that actual motor imagery, not visual imagery, +was performed. All subjects were naive to the MI experiment. For the visual +instruction, a black arrow pointing to either the left or right side +appeared at the center of the screen for 2 s. The arrow disappeared with a +short beep sound and then a black fixation cross was displayed during the +task period. The subjects were asked to imagine hand gripping (opening and +closing their hands) in a 1 Hz pace. This pace was shown to and repeated by +the subjects by performing real hand gripping before the experiment. Motor +imagery was performed continuously over the task period. The task period +was finished with a short beep sound and a ‘STOP’ displayed for 1s on the +screen. The fixation cross was displayed again during the rest period and +the subjects were asked to gaze at it to minimize their eye movements. This +process was repeated twenty times in a single session (ten trials per +condition in a single session; thirty trials in the whole sessions). In a +single session, motor imagery tasks were performed on the basis of ten +subsequent blocks randomly consisting of one of two conditions: Either +first left and then right hand motor imagery or vice versa.

+

References

+
+
+[1] +

Shin, J., von Lühmann, A., Blankertz, B., Kim, D.W., Jeong, J., +Hwang, H.J. and Müller, K.R., 2017. Open access dataset for EEG+NIRS +single-trial classification. IEEE Transactions on Neural Systems +and Rehabilitation Engineering, 25(10), pp.1735-1745.

+
+
+[2] +

GNU General Public License, Version 3 +https://www.gnu.org/licenses/gpl-3.0.txt

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Shin2017B.html b/docs/generated/moabb.datasets.Shin2017B.html new file mode 100644 index 00000000..8c00d9f7 --- /dev/null +++ b/docs/generated/moabb.datasets.Shin2017B.html @@ -0,0 +1,688 @@ + + + + + + + + + + + + moabb.datasets.Shin2017B — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Shin2017B#

+
+
+class moabb.datasets.Shin2017B(accept=False)[source]#
+

Mental Arithmetic Dataset from Shin et al 2017.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

Shin2017B

29

30

2

30

10s

200Hz

3

+
+

Dataset from [1].

+
+

Caution

+

You should accept the licence term [2] to download this dataset, using: +Shin2017B(accept=True)

+
+

Data Acquisition

+

EEG and NIRS data was collected in an ordinary bright room. EEG data was +recorded by a multichannel BrainAmp EEG amplifier with thirty active +electrodes (Brain Products GmbH, Gilching, Germany) with linked mastoids +reference at 1000 Hz sampling rate. The EEG amplifier was also used to +measure the electrooculogram (EOG), electrocardiogram (ECG) and respiration +with a piezo based breathing belt. Thirty EEG electrodes were placed on a +custom-made stretchy fabric cap (EASYCAP GmbH, Herrsching am Ammersee, +Germany) and placed according to the international 10-5 system (AFp1, AFp2, +AFF1h, AFF2h, AFF5h, AFF6h, F3, F4, F7, F8, FCC3h, FCC4h, FCC5h, FCC6h, T7, +T8, Cz, CCP3h, CCP4h, CCP5h, CCP6h, Pz, P3, P4, P7, P8, PPO1h, PPO2h, POO1, +POO2 and Fz for ground electrode).

+

NIRS data was collected by NIRScout (NIRx GmbH, Berlin, Germany) at 12.5 Hz +sampling rate. Each adjacent source-detector pair creates one physiological +NIRS channel. Fourteen sources and sixteen detectors resulting in +thirty-six +physiological channels were placed at frontal (nine channels around Fp1, +Fp2, and Fpz), motor (twelve channels around C3 and C4, respectively) and +visual areas (three channels around Oz). The inter-optode distance was 30 +mm. NIRS optodes were fixed on the same cap as the EEG electrodes. Ambient +lights were sufficiently blocked by a firm contact between NIRS optodes and +scalp and use of an opaque cap.

+

EOG was recorded using two vertical (above and below left eye) and two +horizontal (outer canthus of each eye) electrodes. ECG was recorded based +on +Einthoven triangle derivations I and II, and respiration was measured using +a respiration belt on the lower chest. EOG, ECG and respiration were +sampled +at the same sampling rate of the EEG. ECG and respiration data were not +analyzed in this study, but are provided along with the other signals.

+

Experimental Procedure

+

The subjects sat on a comfortable armchair in front of a 50-inch white +screen. The distance between their heads and the screen was 1.6 m. They +were +asked not to move any part of the body during the data recording. The +experiment consisted of three sessions of left and right hand MI (dataset +A)and MA and baseline tasks (taking a rest without any thought) (dataset B) +each. Each session comprised a 1 min pre-experiment resting period, 20 +repetitions of the given task and a 1 min post-experiment resting +period. The task started with 2 s of a visual introduction of the task, +followed by 10 s of a task period and resting period which was given +randomly from 15 to 17 s. At the beginning and end of the task period, a +short beep (250 ms) was played. All instructions were displayed on the +white +screen by a video projector. MI and MA tasks were performed in separate +sessions but in alternating order (i.e., sessions 1, 3 and 5 for MI +(dataset +A) and sessions 2, 4 and 6 for MA (dataset B)). Fig. 2 shows the schematic +diagram of the experimental paradigm. Five sorts of motion artifacts +induced +by eye and head movements (dataset C) were measured. The motion artifacts +were recorded after all MI and MA task recordings. The experiment did not +include the pre- and post-experiment resting state periods.

+

Mental Arithmetic (Dataset B)

+

For the visual instruction of the MA task, an initial subtraction such as +‘three-digit number minus one-digit number’ (e.g., 384-8) appeared at the +center of the screen for 2 s. The subjects were instructed to memorize the +numbers while the initial subtraction was displayed on the screen. The +initial subtraction disappeared with a short beep sound and a black +fixation cross was displayed during the task period in which the subjects +were asked +to repeatedly perform to subtract the one-digit number from the result of +the previous subtraction. For the baseline task, no specific sign but the +black fixation cross was displayed on the screen, and the subjects were +instructed to take a rest. Note that there were other rest periods between +the MA and baseline task periods, as same with the MI paradigm. Both task +periods were finished with a short beep sound and a ‘STOP’ displayed for +1 s on the screen. The fixation cross was displayed again during the rest +period. MA and baseline trials were randomized in the same way as MI.

+

References

+
+
+[1] +

Shin, J., von Lühmann, A., Blankertz, B., Kim, D.W., Jeong, J., +Hwang, H.J. and Müller, K.R., 2017. Open access dataset for EEG+NIRS +single-trial classification. IEEE Transactions on Neural Systems +and Rehabilitation Engineering, 25(10), pp.1735-1745.

+
+
+[2] +

GNU General Public License, Version 3 +https://www.gnu.org/licenses/gpl-3.0.txt

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Sosulski2019.html b/docs/generated/moabb.datasets.Sosulski2019.html new file mode 100644 index 00000000..693ebc7f --- /dev/null +++ b/docs/generated/moabb.datasets.Sosulski2019.html @@ -0,0 +1,683 @@ + + + + + + + + + + + + moabb.datasets.Sosulski2019 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Sosulski2019#

+
+
+class moabb.datasets.Sosulski2019(use_soas_as_sessions=True, load_soa_60=False, reject_non_iid=False, interval=None)[source]#
+

P300 dataset from initial spot study.

+

Dataset [1], study on spatial transfer between SOAs [2], actual paradigm / online optimization [3].

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Trials / class

Trials length

Sampling rate

#Sessions

Sosulski2019

13

31

7500 NT / 1500 T

1.2s

1000Hz

1

+
+

Dataset description +This dataset contains multiple small trials of an auditory oddball paradigm. The paradigm presented two different +sinusoidal tones. A low-pitched (500 Hz, 40 ms duration) non-target tone and a high-pitched (1000 Hz, +40 ms duration) target tone. Subjects were instructed to attend to the high-pitched target tones and ignore the +low-pitched tones.

+

One trial (= one file) consisted of 90 tones, 15 targets and 75 non-targets. The order was pseudo-randomized in a +way that at least two non-target tones occur between two target tones. Additionally, if you split the 90 tones of +one trial into consecutive sets of six tones, there will always be exactly one target and five non-target tones +in each set.

+

In the first part of the experiment (run 1), each subject performed 50-70 trials with various different stimulus +onset asynchronies (SOAs) – i.e. the time between the onset of successive tones – for each trial. In the second +part (run 2), 4-5 SOAs were played, with blocks of 5 trials having the same SOA. All SOAs were in the range of 60 +ms to 600 ms. Regardless of the experiment part, after a set of five trials, subjects were given the opportunity +to take a short break to e.g. drink etc.

+

Finally, before and after each run, resting data was recorded. One minute with eyes open and one minute with eyes +closed, i.e. in total four minutes of resting data are available for each subject.

+

Data was recorded using a BrainAmp DC (BrainVision) amplifier and a 31 passive electrode EasyCap. The cap was +placed according to the extended 10-20 electrode layout. The reference electrode was placed on the nose. Before +recording, the cap was prepared such that impedances on all electrodes were around 20 kOhm. The EEG signal was +recorded at 1000 Hz.

+

The data contains 31 scalp channels, one EOG channel and five miscellaneous non-EEG signal channels. However, +only scalp EEG and the EOG channel is available in all subjects. The markers in the marker file indicate the +onset of target tones (21) and non-target tones (1).

+
+

Caution

+

Note that this wrapper currently only loads the second part of the experiment and uses pseudo-sessions +to achieve the functionality to handle different conditions in MOABB. As a result, the statistical testing +features of MOABB cannot be used for this dataset.

+
+

References

+
+
+[1] +

Sosulski, J., Tangermann, M.: Electroencephalogram signals recorded from 13 healthy subjects during an +auditory oddball paradigm under different stimulus onset asynchrony conditions. +Dataset. DOI: 10.6094/UNIFR/154576

+
+
+[2] +

Sosulski, J., Tangermann, M.: Spatial filters for auditory evoked potentials transfer between different +experimental conditions. Graz BCI Conference. 2019.

+
+
+[3] +

Sosulski, J., Hübner, D., Klein, A., Tangermann, M.: Online Optimization of Stimulation Speed in +an Auditory Brain-Computer Interface under Time Constraints. arXiv preprint. 2021.

+
+
+

Notes

+
+

New in version 0.4.5.

+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Thielen2015.html b/docs/generated/moabb.datasets.Thielen2015.html new file mode 100644 index 00000000..8c7d6871 --- /dev/null +++ b/docs/generated/moabb.datasets.Thielen2015.html @@ -0,0 +1,663 @@ + + + + + + + + + + + + moabb.datasets.Thielen2015 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Thielen2015#

+
+
+class moabb.datasets.Thielen2015[source]#
+

c-VEP dataset from Thielen et al. (2015)

+

Dataset [1] from the study on reconvolution for c-VEP [2].

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Sessions

Sampling rate

#Chan

Trials length

#Trial classes

#Trials / class

#Epoch classes

#Epochs / class

Codes

Presentation rate

Thielen2015

12

1

2048Hz

64

4.2s

36

3

2

27216 NT / 27216 T

Gold codes

120Hz

+
+

Dataset description

+

EEG recordings were obtained with a sampling rate of 2048 Hz, using a setup comprising 64 Ag/AgCl electrodes, and +amplified by a Biosemi ActiveTwo EEG amplifier. Electrode placement followed the international 10-10 system.

+

During the experimental sessions, participants actively operated a 6 x 6 visual speller brain-computer interface +(BCI) with real-time feedback, encompassing 36 distinct classes. Each cell within the symbol grid underwent +luminance modulation at full contrast, achieved through the application of pseudo-random noise-codes derived from a +set of modulated Gold codes. These binary codes have a balanced distribution of ones and zeros while adhering to a +limited run-length pattern, with a maximum run-length of 2 bits. Codes were presented at a rate of 120 Hz. Given +that one cycle of these modulated Gold codes comprises 126 bits, the duration of a complete cycle spans 1.05 +seconds.

+

Throughout the experiment, participants underwent four distinct blocks: an initial practice block consisting of two +runs, followed by a training block of one run. Subsequently, they engaged in a copy-spelling block comprising six +runs, and finally, a free-spelling block consisting of one run. Between the training and copy-spelling block, a +classifier was calibrated using data from the training block. This calibrated classifier was then applied during +both the copy-spelling and free-spelling runs. Additionally, during calibration, the stimulation codes were +tailored and optimized specifically for each individual participant.

+

Among the six copy-spelling runs, there were three fixed-length runs. Trials in these runs started with a cueing +phase, where the target symbol was highlighted in a green hue for 1 second. Participants maintained their gaze +fixated on the target symbol as all symbols flashed in sync with their corresponding pseudo-random noise-codes for a +duration of 4.2 seconds (equivalent to 4 code cycles). Immediately following this stimulation, the output of the +classifier was shown by coloring the cell blue for 1 second. Each run consisted of 36 trials, presented in a +randomized order.

+

Here, our focus is solely on the three copy-spelling runs characterized by fixed-length trials lasting 4.2 seconds +(equivalent to four code cycles). The other three runs utilized a dynamic stopping procedure, resulting in trials of +varying durations, rendering them unsuitable for benchmarking purposes. Similarly, the practice and free-spelling +runs included dynamic stopping and are ignored in this dataset. The training dataset, comprising 36 trials, used a +different noise-code set, and is therefore also ignored in this dataset. In total, this dataset should contain 108 +trials of 4.2 seconds each, with 3 repetitions for each of the 36 codes.

+

References

+
+
+[1] +

Thielen, J. (Jordy), Jason Farquhar, Desain, P.W.M. (Peter) (2023): Broad-Band Visually Evoked Potentials: +Re(con)volution in Brain-Computer Interfacing. Version 2. Radboud University. (dataset). +DOI: https://doi.org/10.34973/1ecz-1232

+
+
+[2] +

Thielen, J., Van Den Broek, P., Farquhar, J., & Desain, P. (2015). Broad-Band visually evoked potentials: +re(con)volution in brain-computer interfacing. PLOS ONE, 10(7), e0133797. +DOI: https://doi.org/10.1371/journal.pone.0133797

+
+
+

Notes

+
+

New in version 1.0.0.

+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Return the data paths of a single subject.

+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Thielen2021.html b/docs/generated/moabb.datasets.Thielen2021.html new file mode 100644 index 00000000..e543933f --- /dev/null +++ b/docs/generated/moabb.datasets.Thielen2021.html @@ -0,0 +1,660 @@ + + + + + + + + + + + + moabb.datasets.Thielen2021 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Thielen2021#

+
+
+class moabb.datasets.Thielen2021[source]#
+

c-VEP dataset from Thielen et al. (2021)

+

Dataset [1] from the study on zero-training c-VEP [2].

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Sessions

Sampling rate

#Chan

Trials length

#Trial classes

#Trials / class

#Epoch classes

#Epochs / class

Codes

Presentation rate

Thielen2021

30

1

512Hz

8

31.5s

20

5

2

94500 NT / 94500 T

Gold codes

60Hz

+
+

Dataset description

+

EEG recordings were acquired at a sampling rate of 512 Hz, employing 8 Ag/AgCl electrodes. The Biosemi ActiveTwo EEG +amplifier was utilized during the experiment. The electrode array consisted of Fz, T7, O1, POz, Oz, Iz, O2, and T8, +connected as EXG channels. This is a custom electrode montage as optimized in a previous study for c-VEP, see [3].

+

During the experimental sessions, participants engaged in passive operation (i.e., without feedback) of a 4 x 5 +visual speller brain-computer interface (BCI) comprising 20 distinct classes. Each cell of the symbol grid +underwent luminance modulation at full contrast, accomplished through pseudo-random noise-codes derived from a +collection of modulated Gold codes. These codes are binary, have a balanced distribution of ones and zeros, and +adhere to a limited run-length pattern (maximum run-length of 2 bits). The codes were presented at a presentation +rate of 60 Hz. As one cycle of these modulated Gold codes contains 126 bits, the duration of one cycle is 2.1 +seconds.

+

For each of the five blocks, a trial started with a cueing phase, during which the target symbol was highlighted in +a green hue for a duration of 1 second. Following this, participants maintained their gaze fixated on the target +symbol while all symbols flashed in accordance with their respective pseudo-random noise-codes for a duration of +31.5 seconds (i.e., 15 code cycles). Each block encompassed 20 trials, presented in a randomized sequence, thereby +ensuring that each symbol was attended to once within the span of a block.

+

Note, here, we only load the offline data of this study and ignore the online phase.

+

References

+
+
+[1] +

Thielen, J. (Jordy), Pieter Marsman, Jason Farquhar, Desain, P.W.M. (Peter) (2023): From full calibration to +zero training for a code-modulated visual evoked potentials brain computer interface. Version 3. Radboud +University. (dataset). +DOI: https://doi.org/10.34973/9txv-z787

+
+
+[2] +

Thielen, J., Marsman, P., Farquhar, J., & Desain, P. (2021). From full calibration to zero training for a +code-modulated visual evoked potentials for brain–computer interface. Journal of Neural Engineering, 18(5), +056007. +DOI: https://doi.org/10.1088/1741-2552/abecef

+
+
+[3] +

Ahmadi, S., Borhanazad, M., Tump, D., Farquhar, J., & Desain, P. (2019). Low channel count montages using +sensor tying for VEP-based BCI. Journal of Neural Engineering, 16(6), 066038. +DOI: https://doi.org/10.1088/1741-2552/ab4057

+
+
+

Notes

+
+

New in version 0.6.0.

+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Return the data paths of a single subject.

+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Wang2016.html b/docs/generated/moabb.datasets.Wang2016.html new file mode 100644 index 00000000..6541a437 --- /dev/null +++ b/docs/generated/moabb.datasets.Wang2016.html @@ -0,0 +1,685 @@ + + + + + + + + + + + + moabb.datasets.Wang2016 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Wang2016#

+
+
+class moabb.datasets.Wang2016[source]#
+

SSVEP Wang 2016 dataset.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials length

Sampling rate

#Sessions

Wang2016

34

62

40

6

5s

250Hz

1

+
+

Dataset from [1].

+

This dataset gathered SSVEP-BCI recordings of 35 healthy subjects (17 +females, aged 17-34 years, mean age: 22 years) focusing on 40 characters +flickering at different frequencies (8-15.8 Hz with an interval of 0.2 Hz). +For each subject, the experiment consisted of 6 blocks. Each block +contained 40 trials corresponding to all 40 characters indicated in a +random order. Each trial started with a visual cue (a red square) +indicating a target stimulus. The cue appeared for 0.5 s on the screen. +Subjects were asked to shift their gaze to the target as soon as possible +within the cue duration. Following the cue offset, all stimuli started to +flicker on the screen concurrently and lasted 5 s. After stimulus offset, +the screen was blank for 0.5 s before the next trial began, which allowed +the subjects to have short breaks between consecutive trials. Each trial +lasted a total of 6 s. To facilitate visual fixation, a red triangle +appeared below the flickering target during the stimulation period. In each +block, subjects were asked to avoid eye blinks during the stimulation +period. To avoid visual fatigue, there was a rest for several minutes +between two consecutive blocks.

+

EEG data were acquired using a Synamps2 system (Neuroscan, Inc.) with a +sampling rate of 1000 Hz. The amplifier frequency passband ranged from +0.15 Hz to 200 Hz. Sixty-four channels covered the whole scalp of the +subject and were aligned according to the international 10-20 system. +The ground was placed on midway between Fz and FPz. The reference was +located on the vertex. Electrode impedances were kept below 10 KΩ. To +remove the common power-line noise, a notch filter at 50 Hz was applied +in data recording. Event triggers generated by the computer to the +amplifier and recorded on an event channel synchronized to the EEG data.

+

The continuous EEG data was segmented into 6 s epochs (500 ms pre-stimulus, +5.5 s post-stimulus onset). The epochs were subsequently downsampled to +250 Hz. Thus each trial consisted of 1500 time points. Finally, these data +were stored as double-precision floating-point values in MATLAB and were +named as subject indices (i.e., S01.mat, …, S35.mat). For each file, the +data loaded in MATLAB generate a 4-D matrix named ‘data’ with dimensions +of [64, 1500, 40, 6]. The four dimensions indicate ‘Electrode index’, +‘Time points’, ‘Target index’, and ‘Block index’. The electrode positions +were saved in a ‘64-channels.loc’ file. Six trials were available for each +SSVEP frequency. Frequency and phase values for the 40 target indices were +saved in a ‘Freq_Phase.mat’ file.

+

Information for all subjects was listed in a ‘Sub_info.txt’ file. For each +subject, there are five factors including ‘Subject Index’, ‘Gender’, ‘Age’, +‘Handedness’, and ‘Group’. Subjects were divided into an ‘experienced’ +group (eight subjects, S01-S08) and a ‘naive’ group (27 subjects, S09-S35) +according to their experience in SSVEP-based BCIs.

+

References

+
+
+[1] +

Y. Wang, X. Chen, X. Gao and S. Gao, 2017, “A Benchmark Dataset for +SSVEP-Based Brain–Computer Interfaces,” in IEEE Transactions on Neural +Systems and Rehabilitation Engineering, vol. 25, no. 10, pp. 1746-1752, +doi: 10.1109/TNSRE.2016.2627556.

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Weibo2014.html b/docs/generated/moabb.datasets.Weibo2014.html new file mode 100644 index 00000000..8b20e73b --- /dev/null +++ b/docs/generated/moabb.datasets.Weibo2014.html @@ -0,0 +1,664 @@ + + + + + + + + + + + + moabb.datasets.Weibo2014 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Weibo2014#

+
+
+class moabb.datasets.Weibo2014[source]#
+

Motor Imagery dataset from Weibo et al 2014.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

Weibo2014

10

60

7

80

4s

200Hz

1

+
+

Dataset from the article Evaluation of EEG oscillatory patterns and +cognitive process during simple and compound limb motor imagery [1].

+

It contains data recorded on 10 subjects, with 60 electrodes.

+

This dataset was used to investigate the differences of the EEG patterns +between simple limb motor imagery and compound limb motor +imagery. Seven kinds of mental tasks have been designed, involving three +tasks of simple limb motor imagery (left hand, right hand, feet), three +tasks of compound limb motor imagery combining hand with hand/foot +(both hands, left hand combined with right foot, right hand combined with +left foot) and rest state.

+

At the beginning of each trial (8 seconds), a white circle appeared at the +center of the monitor. After 2 seconds, a red circle (preparation cue) +appeared for 1 second to remind the subjects of paying attention to the +character indication next. Then red circle disappeared and character +indication (‘Left Hand’, ‘Left Hand & Right Foot’, et al) was presented on +the screen for 4 seconds, during which the participants were asked to +perform kinesthetic motor imagery rather than a visual type of imagery +while avoiding any muscle movement. After 7 seconds, ‘Rest’ was presented +for 1 second before next trial (Fig. 1(a)). The experiments were divided +into 9 sections, involving 8 sections consisting of 60 trials each for six +kinds of MI tasks (10 trials for each MI task in one section) and one +section consisting of 80 trials for rest state. The sequence of six MI +tasks was randomized. Intersection break was about 5 to 10 minutes.

+

References

+
+
+[1] +

Yi, Weibo, et al. “Evaluation of EEG oscillatory patterns and +cognitive process during simple and compound limb motor imagery.” +PloS one 9.12 (2014). https://doi.org/10.1371/journal.pone.0114853

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.Zhou2016.html b/docs/generated/moabb.datasets.Zhou2016.html new file mode 100644 index 00000000..8158459e --- /dev/null +++ b/docs/generated/moabb.datasets.Zhou2016.html @@ -0,0 +1,684 @@ + + + + + + + + + + + + moabb.datasets.Zhou2016 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.Zhou2016#

+
+
+class moabb.datasets.Zhou2016[source]#
+

Motor Imagery dataset from Zhou et al 2016.

+
+

Dataset summary

+ + + + + + + + + + + + + + + + + + + + + + + +

Name

#Subj

#Chan

#Classes

#Trials / class

Trials len

Sampling rate

#Sessions

Zhou2016

4

14

3

160

5s

250Hz

3

+
+

Dataset from the article A Fully Automated Trial Selection Method for +Optimization of Motor Imagery Based Brain-Computer Interface [1]. +This dataset contains data recorded on 4 subjects performing 3 type of +motor imagery: left hand, right hand and feet.

+

Every subject went through three sessions, each of which contained two +consecutive runs with several minutes inter-run breaks, and each run +comprised 75 trials (25 trials per class). The intervals between two +sessions varied from several days to several months.

+

A trial started by a short beep indicating 1 s preparation time, +and followed by a red arrow pointing randomly to three directions (left, +right, or bottom) lasting for 5 s and then presented a black screen for +4 s. The subject was instructed to immediately perform the imagination +tasks of the left hand, right hand or foot movement respectively according +to the cue direction, and try to relax during the black screen.

+

References

+
+
+[1] +

Zhou B, Wu X, Lv Z, Zhang L, Guo X (2016) A Fully Automated +Trial Selection Method for Optimization of Motor Imagery Based +Brain-Computer Interface. PLoS ONE 11(9). +https://doi.org/10.1371/journal.pone.0162657

+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+

Examples using moabb.datasets.Zhou2016#

+
Benchmarking with MOABB showing the CO2 footprint +

Benchmarking with MOABB showing the CO2 footprint

+
Benchmarking with MOABB showing the CO2 footprint
+
Examples of how to use MOABB to benchmark pipelines. +

Examples of how to use MOABB to benchmark pipelines.

+
Examples of how to use MOABB to benchmark pipelines.
+
Cross-Session on Multiple Datasets +

Cross-Session on Multiple Datasets

+
Cross-Session on Multiple Datasets
+
Cache on disk intermediate data processing states +

Cache on disk intermediate data processing states

+
Cache on disk intermediate data processing states
+
Fixed interval windows processing +

Fixed interval windows processing

+
Fixed interval windows processing
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Tutorial 2: Using multiple datasets +

Tutorial 2: Using multiple datasets

+
Tutorial 2: Using multiple datasets
+
Tutorial 3: Benchmarking multiple pipelines +

Tutorial 3: Benchmarking multiple pipelines

+
Tutorial 3: Benchmarking multiple pipelines
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.base.BaseDataset.html b/docs/generated/moabb.datasets.base.BaseDataset.html new file mode 100644 index 00000000..d8c87c2e --- /dev/null +++ b/docs/generated/moabb.datasets.base.BaseDataset.html @@ -0,0 +1,786 @@ + + + + + + + + + + + + moabb.datasets.base.BaseDataset — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.base.BaseDataset#

+
+
+class moabb.datasets.base.BaseDataset(subjects, sessions_per_subject, events, code, interval, paradigm, doi=None, unit_factor=1000000.0)[source]#
+

Abstract Moabb BaseDataset.

+

Parameters required for all datasets

+
+
Parameters:
+
    +
  • subjects (List of int) – List of subject number (or tuple or numpy array)

  • +
  • sessions_per_subject (int) – Number of sessions per subject (if varying, take minimum)

  • +
  • events (dict of strings) – String codes for events matched with labels in the stim channel. +Currently imagery codes codes can include: +- left_hand +- right_hand +- hands +- feet +- rest +- left_hand_right_foot +- right_hand_left_foot +- tongue +- navigation +- subtraction +- word_ass (for word association)

  • +
  • code (string) – Unique identifier for dataset, used in all plots. +The code should be in CamelCase.

  • +
  • interval (list with 2 entries) – Imagery interval as defined in the dataset description

  • +
  • paradigm (['p300','imagery', 'ssvep']) – Defines what sort of dataset this is

  • +
  • doi (DOI for dataset, optional (for now)) –

  • +
+
+
+
+
+abstract data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+
+download(subject_list=None, path=None, force_update=False, update_path=None, accept=False, verbose=None)[source]#
+

Download all data from the dataset.

+

This function is only useful to download all the dataset at once.

+
+
Parameters:
+
    +
  • subject_list (list of int | None) – List of subjects id to download, if None all subjects +are downloaded.

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • accept (bool) – Accept licence term to download the data, if any. Default: False

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
+
+ +
+
+get_data(subjects=None, cache_config=None, process_pipeline=None)[source]#
+

Return the data corresponding to a list of subjects.

+

The returned data is a dictionary with the following structure:

+
data = {'subject_id' :
+            {'session_id':
+                {'run_id': run}
+            }
+        }
+
+
+

subjects are on top, then we have sessions, then runs. +A sessions is a recording done in a single day, without removing the +EEG cap. A session is constitued of at least one run. A run is a single +contiguous recording. Some dataset break session in multiple runs.

+

Processing steps can optionally be applied to the data using the +*_pipeline arguments. These pipelines are applied in the +following order: raw_pipeline -> epochs_pipeline -> +array_pipeline. If a *_pipeline argument is None, +the step will be skipped. Therefore, the array_pipeline may +either receive a mne.io.Raw or a mne.Epochs object +as input depending on whether epochs_pipeline is None or not.

+
+
Parameters:
+
    +
  • subjects (List of int) – List of subject number

  • +
  • cache_config (dict | CacheConfig) – Configuration for caching of datasets. See CacheConfig +for details.

  • +
  • process_pipeline (Pipeline | None) – Optional processing pipeline to apply to the data. +To generate an adequate pipeline, we recommend using +moabb.utils.make_process_pipelines(). +This pipeline will receive mne.io.BaseRaw objects. +The steps names of this pipeline should be elements of StepType. +According to their name, the steps should either return a +mne.io.BaseRaw, a mne.Epochs, or a numpy.ndarray(). +This pipeline must be “fixed” because it will not be trained, +i.e. no call to fit will be made.

  • +
+
+
Returns:
+

data – dict containing the raw data

+
+
Return type:
+

Dict

+
+
+
+ +
+ +
+

Examples using moabb.datasets.base.BaseDataset#

+
Benchmarking on MOABB with Tensorflow deep net architectures +

Benchmarking on MOABB with Tensorflow deep net architectures

+
Benchmarking on MOABB with Tensorflow deep net architectures
+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures +

Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures

+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures
+
Cross-session motor imagery with deep learning EEGNet v4 model +

Cross-session motor imagery with deep learning EEGNet v4 model

+
Cross-session motor imagery with deep learning EEGNet v4 model
+
Cross-Session Motor Imagery +

Cross-Session Motor Imagery

+
Cross-Session Motor Imagery
+
Cross-Session on Multiple Datasets +

Cross-Session on Multiple Datasets

+
Cross-Session on Multiple Datasets
+
Cross-Subject SSVEP +

Cross-Subject SSVEP

+
Cross-Subject SSVEP
+
Cache on disk intermediate data processing states +

Cache on disk intermediate data processing states

+
Cache on disk intermediate data processing states
+
Explore Paradigm Object +

Explore Paradigm Object

+
Explore Paradigm Object
+
Fixed interval windows processing +

Fixed interval windows processing

+
Fixed interval windows processing
+
Within Session P300 +

Within Session P300

+
Within Session P300
+
Within Session SSVEP +

Within Session SSVEP

+
Within Session SSVEP
+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
GridSearch within a session +

GridSearch within a session

+
GridSearch within a session
+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Within Session Motor Imagery with Learning Curve +

Within Session Motor Imagery with Learning Curve

+
Within Session Motor Imagery with Learning Curve
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Tutorial 4: Creating a dataset class +

Tutorial 4: Creating a dataset class

+
Tutorial 4: Creating a dataset class
+
Tutorial 0: Getting Started +

Tutorial 0: Getting Started

+
Tutorial 0: Getting Started
+
Tutorial 1: Simple Motor Imagery +

Tutorial 1: Simple Motor Imagery

+
Tutorial 1: Simple Motor Imagery
+
Tutorial 2: Using multiple datasets +

Tutorial 2: Using multiple datasets

+
Tutorial 2: Using multiple datasets
+
Tutorial 3: Benchmarking multiple pipelines +

Tutorial 3: Benchmarking multiple pipelines

+
Tutorial 3: Benchmarking multiple pipelines
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.base.CacheConfig.html b/docs/generated/moabb.datasets.base.CacheConfig.html new file mode 100644 index 00000000..f189c5ad --- /dev/null +++ b/docs/generated/moabb.datasets.base.CacheConfig.html @@ -0,0 +1,623 @@ + + + + + + + + + + + + moabb.datasets.base.CacheConfig — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.base.CacheConfig#

+
+
+class moabb.datasets.base.CacheConfig(save_raw: bool = False, save_epochs: bool = False, save_array: bool = False, use: bool = False, overwrite_raw: bool = False, overwrite_epochs: bool = False, overwrite_array: bool = False, path: Optional[Union[str, Path]] = None, verbose: Optional[str] = None)[source]#
+

Configuration for caching of datasets.

+
+
Parameters:
+
    +
  • save_* (bool) – This flag specifies whether to save the output of the corresponding +step to disk.

  • +
  • use (bool) – This flag specifies whether to use the disk cache in case it exists. +If True, the Raw or Epochs objects returned will not be preloaded +(this saves some time). Otherwise, they will be preloaded. +If use is False, the save_* and overwrite_* keys will be ignored.

  • +
  • overwrite_* (bool) – This flag specifies whether to overwrite the disk cache in +case it exist.

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(signifier)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • verbose (str) – Verbosity level. See mne.verbose.

  • +
+
+
+

Notes

+
+

New in version 1.0.0.

+
+
+
+__hash__ = None#
+
+ +
+
+classmethod make(dic: Union[None, Dict, CacheConfig] = None) CacheConfig[source]#
+

Create a CacheConfig object from a dict or another CacheConfig object.

+

Examples

+

Using default parameters:

+
>>> CacheConfig.make()
+CacheConfig(save=True, use=True, overwrite=True, path=None)
+
+
+

From a dict:

+
>>> dic = {'save': False}
+>>> CacheConfig.make(dic)
+CacheConfig(save=False, use=True, overwrite=True, path=None)
+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.compound_dataset.BI2014a_Il.html b/docs/generated/moabb.datasets.compound_dataset.BI2014a_Il.html new file mode 100644 index 00000000..14858ab9 --- /dev/null +++ b/docs/generated/moabb.datasets.compound_dataset.BI2014a_Il.html @@ -0,0 +1,577 @@ + + + + + + + + + + + + moabb.datasets.compound_dataset.BI2014a_Il — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.compound_dataset.BI2014a_Il#

+
+
+class moabb.datasets.compound_dataset.BI2014a_Il[source]#
+

A selection of subject from BI2014a with AUC < 0.7 with pipeline: +ERPCovariances(estimator=”lwf”), MDM(metric=”riemann”)

+

Notes

+
+

Note

+

BI2014a_Il was previously named bi2014a_il. bi2014a_il will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.compound_dataset.BI2014b_Il.html b/docs/generated/moabb.datasets.compound_dataset.BI2014b_Il.html new file mode 100644 index 00000000..bb780c8b --- /dev/null +++ b/docs/generated/moabb.datasets.compound_dataset.BI2014b_Il.html @@ -0,0 +1,577 @@ + + + + + + + + + + + + moabb.datasets.compound_dataset.BI2014b_Il — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.compound_dataset.BI2014b_Il#

+
+
+class moabb.datasets.compound_dataset.BI2014b_Il[source]#
+

A selection of subject from BI2014b with AUC < 0.7 with pipeline: +ERPCovariances(estimator=”lwf”), MDM(metric=”riemann”)

+

Notes

+
+

Note

+

BI2014b_Il was previously named bi2014b_il. bi2014b_il will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.compound_dataset.BI2015a_Il.html b/docs/generated/moabb.datasets.compound_dataset.BI2015a_Il.html new file mode 100644 index 00000000..0f6c3dec --- /dev/null +++ b/docs/generated/moabb.datasets.compound_dataset.BI2015a_Il.html @@ -0,0 +1,577 @@ + + + + + + + + + + + + moabb.datasets.compound_dataset.BI2015a_Il — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.compound_dataset.BI2015a_Il#

+
+
+class moabb.datasets.compound_dataset.BI2015a_Il[source]#
+

A selection of subject from BI2015a with AUC < 0.7 with pipeline: +ERPCovariances(estimator=”lwf”), MDM(metric=”riemann”)

+

Notes

+
+

Note

+

BI2015a_Il was previously named bi2015a_il. bi2015a_il will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.compound_dataset.BI2015b_Il.html b/docs/generated/moabb.datasets.compound_dataset.BI2015b_Il.html new file mode 100644 index 00000000..612f4398 --- /dev/null +++ b/docs/generated/moabb.datasets.compound_dataset.BI2015b_Il.html @@ -0,0 +1,577 @@ + + + + + + + + + + + + moabb.datasets.compound_dataset.BI2015b_Il — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.compound_dataset.BI2015b_Il#

+
+
+class moabb.datasets.compound_dataset.BI2015b_Il[source]#
+

A selection of subject from BI2015b with AUC < 0.7 with pipeline: +ERPCovariances(estimator=”lwf”), MDM(metric=”riemann”)

+

Notes

+
+

Note

+

BI2015b_Il was previously named bi2015b_il. bi2015b_il will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.compound_dataset.BI_Il.html b/docs/generated/moabb.datasets.compound_dataset.BI_Il.html new file mode 100644 index 00000000..5cff30c3 --- /dev/null +++ b/docs/generated/moabb.datasets.compound_dataset.BI_Il.html @@ -0,0 +1,577 @@ + + + + + + + + + + + + moabb.datasets.compound_dataset.BI_Il — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.compound_dataset.BI_Il#

+
+
+class moabb.datasets.compound_dataset.BI_Il[source]#
+

Subjects from braininvaders datasets with AUC < 0.7 with pipeline: +ERPCovariances(estimator=”lwf”), MDM(metric=”riemann”)

+

Notes

+
+

Note

+

BI_Il was previously named biIlliteracy. biIlliteracy will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.compound_dataset.Cattan2019_VR_Il.html b/docs/generated/moabb.datasets.compound_dataset.Cattan2019_VR_Il.html new file mode 100644 index 00000000..244bb1ff --- /dev/null +++ b/docs/generated/moabb.datasets.compound_dataset.Cattan2019_VR_Il.html @@ -0,0 +1,577 @@ + + + + + + + + + + + + moabb.datasets.compound_dataset.Cattan2019_VR_Il — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.compound_dataset.Cattan2019_VR_Il#

+
+
+class moabb.datasets.compound_dataset.Cattan2019_VR_Il[source]#
+

A selection of subject from Cattan2019_VR with AUC < 0.7 with pipeline: +ERPCovariances(estimator=”lwf”), MDM(metric=”riemann”)

+

Notes

+
+

Note

+

Cattan2019_VR_Il was previously named VirtualReality_il. VirtualReality_il will be removed in version 1.1.

+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.download.data_dl.html b/docs/generated/moabb.datasets.download.data_dl.html new file mode 100644 index 00000000..58c212d1 --- /dev/null +++ b/docs/generated/moabb.datasets.download.data_dl.html @@ -0,0 +1,603 @@ + + + + + + + + + + + + moabb.datasets.download.data_dl — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.download.data_dl#

+
+
+moabb.datasets.download.data_dl(url, sign, path=None, force_update=False, verbose=None)[source]#
+

Download file from url to specified path.

+

This function should replace data_path as the MNE will not support the download +of dataset anymore. This version is using Pooch.

+
+
Parameters:
+
    +
  • url (str) – Path to remote location of data

  • +
  • sign (str) – Signifier of dataset

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(signifier)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level (see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a list +of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+

Examples using moabb.datasets.download.data_dl#

+
Tutorial 4: Creating a dataset class +

Tutorial 4: Creating a dataset class

+
Tutorial 4: Creating a dataset class
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.download.data_path.html b/docs/generated/moabb.datasets.download.data_path.html new file mode 100644 index 00000000..af3aacf9 --- /dev/null +++ b/docs/generated/moabb.datasets.download.data_path.html @@ -0,0 +1,597 @@ + + + + + + + + + + + + moabb.datasets.download.data_path — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.download.data_path#

+
+
+moabb.datasets.download.data_path(url, sign, path=None, force_update=False, update_path=True, verbose=None)[source]#
+

Get path to local copy of given dataset URL. Deprecated

+

This is a low-level function useful for getting a local copy of a +remote dataset. It is deprecated in favor of data_dl.

+
+
Parameters:
+
    +
  • url (str) – Path to remote location of data

  • +
  • sign (str) – Signifier of dataset

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(signifier)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None, Deprecated) – Unused, kept for compatibility purpose.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level (see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a list +of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.download.fs_get_file_hash.html b/docs/generated/moabb.datasets.download.fs_get_file_hash.html new file mode 100644 index 00000000..25d1b325 --- /dev/null +++ b/docs/generated/moabb.datasets.download.fs_get_file_hash.html @@ -0,0 +1,582 @@ + + + + + + + + + + + + moabb.datasets.download.fs_get_file_hash — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.download.fs_get_file_hash#

+
+
+moabb.datasets.download.fs_get_file_hash(filelist)[source]#
+

Returns a dict associating figshare file id to MD5 hash.

+
+
Parameters:
+

filelist (list of dict) – HTTP request response from fs_get_file_list

+
+
Returns:
+

response – keys are file_id and values are md5 hash

+
+
Return type:
+

dict

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.download.fs_get_file_id.html b/docs/generated/moabb.datasets.download.fs_get_file_id.html new file mode 100644 index 00000000..5b06962a --- /dev/null +++ b/docs/generated/moabb.datasets.download.fs_get_file_id.html @@ -0,0 +1,582 @@ + + + + + + + + + + + + moabb.datasets.download.fs_get_file_id — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.download.fs_get_file_id#

+
+
+moabb.datasets.download.fs_get_file_id(filelist)[source]#
+

Returns a dict associating filename to figshare file id.

+
+
Parameters:
+

filelist (list of dict) – HTTP request response from fs_get_file_list

+
+
Returns:
+

response – keys are filename and values are file_id

+
+
Return type:
+

dict

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.download.fs_get_file_list.html b/docs/generated/moabb.datasets.download.fs_get_file_list.html new file mode 100644 index 00000000..0e5ae922 --- /dev/null +++ b/docs/generated/moabb.datasets.download.fs_get_file_list.html @@ -0,0 +1,585 @@ + + + + + + + + + + + + moabb.datasets.download.fs_get_file_list — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.download.fs_get_file_list#

+
+
+moabb.datasets.download.fs_get_file_list(article_id, version=None)[source]#
+

List all the files associated with a given article.

+
+
Parameters:
+
    +
  • article_id (str or int) – Figshare article ID

  • +
  • version (str or id, default is None) – Figshare article version. If None, selects the most recent version.

  • +
+
+
Returns:
+

response – HTTP request response as a python dict

+
+
Return type:
+

dict

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.download.fs_get_file_name.html b/docs/generated/moabb.datasets.download.fs_get_file_name.html new file mode 100644 index 00000000..75fa39db --- /dev/null +++ b/docs/generated/moabb.datasets.download.fs_get_file_name.html @@ -0,0 +1,582 @@ + + + + + + + + + + + + moabb.datasets.download.fs_get_file_name — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.download.fs_get_file_name#

+
+
+moabb.datasets.download.fs_get_file_name(filelist)[source]#
+

Returns a dict associating figshare file id to filename.

+
+
Parameters:
+

filelist (list of dict) – HTTP request response from fs_get_file_list

+
+
Returns:
+

response – keys are file_id and values are file name

+
+
Return type:
+

dict

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.download.fs_issue_request.html b/docs/generated/moabb.datasets.download.fs_issue_request.html new file mode 100644 index 00000000..07577de0 --- /dev/null +++ b/docs/generated/moabb.datasets.download.fs_issue_request.html @@ -0,0 +1,588 @@ + + + + + + + + + + + + moabb.datasets.download.fs_issue_request — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.download.fs_issue_request#

+
+
+moabb.datasets.download.fs_issue_request(method, url, headers, data=None, binary=False)[source]#
+

Wrapper for HTTP request.

+
+
Parameters:
+
    +
  • method (str) – HTTP method. One of GET, PUT, POST or DELETE

  • +
  • url (str) – URL for the request

  • +
  • headers (dict) – HTTP header information

  • +
  • data (dict) – Figshare article data

  • +
  • binary (bool) – Whether data is binary or not

  • +
+
+
Returns:
+

response_data – JSON response for the request returned as python dict

+
+
Return type:
+

dict

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.fake.FakeDataset.html b/docs/generated/moabb.datasets.fake.FakeDataset.html new file mode 100644 index 00000000..66da1a18 --- /dev/null +++ b/docs/generated/moabb.datasets.fake.FakeDataset.html @@ -0,0 +1,628 @@ + + + + + + + + + + + + moabb.datasets.fake.FakeDataset — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.fake.FakeDataset#

+
+
+class moabb.datasets.fake.FakeDataset(event_list=('fake1', 'fake2', 'fake3'), n_sessions=2, n_runs=2, n_subjects=10, code='FakeDataset', paradigm='imagery', channels=('C3', 'Cz', 'C4'), seed=None, sfreq=128, duration=120, n_events=60, stim=True, annotations=False)[source]#
+

Fake Dataset for test purpose.

+

By default, the dataset has 2 sessions, 10 subjects, and 3 classes.

+
+
Parameters:
+
    +
  • event_list (list or tuple of str) – List of event to generate, default: (“fake1”, “fake2”, “fake3”)

  • +
  • n_sessions (int, default 2) – Number of session to generate

  • +
  • n_runs (int, default 2) – Number of runs to generate

  • +
  • n_subjects (int, default 10) – Number of subject to generate

  • +
  • paradigm (['p300','imagery', 'ssvep']) – Defines what sort of dataset this is

  • +
  • channels (list or tuple of str) – List of channels to generate, default (“C3”, “Cz”, “C4”)

  • +
  • duration (float or list of float) – Duration of each run in seconds. If float, same duration for all +runs. If list, duration for each run.

  • +
  • n_events (int or list of int) – Number of events per run. If int, same number of events +for all runs. If list, number of events for each run.

  • +
  • stim (bool) – If True, pass events through stim channel.

  • +
  • annotations (bool) –

    If True, pass events through Annotations.

    +
    +

    New in version 0.4.3.

    +
    +

  • +
+
+
+
+
+data_path(subject, path=None, force_update=False, update_path=None, verbose=None)[source]#
+

Get path to local copy of a subject data.

+
+
Parameters:
+
    +
  • subject (int) – Number of subject to use

  • +
  • path (None | str) – Location of where to look for the data storing location. +If None, the environment variable or config parameter +MNE_DATASETS_(dataset)_PATH is used. If it doesn’t exist, the +“~/mne_data” directory is used. If the dataset +is not found under the given path, the data +will be automatically downloaded to the specified folder.

  • +
  • force_update (bool) – Force update of the dataset even if a local copy exists.

  • +
  • update_path (bool | None Deprecated) – If True, set the MNE_DATASETS_(dataset)_PATH in mne-python +config to the given path. If None, the user is prompted.

  • +
  • verbose (bool, str, int, or None) – If not None, override default verbose level +(see mne.verbose()).

  • +
+
+
Returns:
+

path – Local path to the given data file. This path is contained inside a +list of length one, for compatibility.

+
+
Return type:
+

list of str

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.fake.FakeVirtualRealityDataset.html b/docs/generated/moabb.datasets.fake.FakeVirtualRealityDataset.html new file mode 100644 index 00000000..35167779 --- /dev/null +++ b/docs/generated/moabb.datasets.fake.FakeVirtualRealityDataset.html @@ -0,0 +1,611 @@ + + + + + + + + + + + + moabb.datasets.fake.FakeVirtualRealityDataset — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.fake.FakeVirtualRealityDataset#

+
+
+class moabb.datasets.fake.FakeVirtualRealityDataset(seed=None)[source]#
+

Fake Cattan2019_VR dataset for test purpose.

+
+

New in version 0.5.0.

+
+
+
+get_block_repetition(paradigm, subjects, block_list, repetition_list)[source]#
+

Select data for all provided subjects, blocks and repetitions. Each +subject has 5 blocks of 12 repetitions.

+

The returned data is a dictionary with the following structure:

+
data = {'subject_id' :
+            {'session_id':
+                {'run_id': raw}
+            }
+        }
+
+
+
+

See also

+

BaseDataset.get_data, Cattan2019_VR.get_block_repetition

+
+
+
Parameters:
+
    +
  • subjects (List of int) – List of subject number

  • +
  • block_list (List of int) – List of block number (from 1 to 5)

  • +
  • repetition_list (List of int) – List of repetition number inside a block (from 1 to 12)

  • +
+
+
Returns:
+

data – dict containing the raw data

+
+
Return type:
+

Dict

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.utils.dataset_search.html b/docs/generated/moabb.datasets.utils.dataset_search.html new file mode 100644 index 00000000..ccde8f89 --- /dev/null +++ b/docs/generated/moabb.datasets.utils.dataset_search.html @@ -0,0 +1,593 @@ + + + + + + + + + + + + moabb.datasets.utils.dataset_search — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.datasets.utils.find_intersecting_channels.html b/docs/generated/moabb.datasets.utils.find_intersecting_channels.html new file mode 100644 index 00000000..4218862f --- /dev/null +++ b/docs/generated/moabb.datasets.utils.find_intersecting_channels.html @@ -0,0 +1,580 @@ + + + + + + + + + + + + moabb.datasets.utils.find_intersecting_channels — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.datasets.utils.find_intersecting_channels#

+
+
+moabb.datasets.utils.find_intersecting_channels(datasets, verbose=False)[source]#
+

Given a list of dataset instances return a list of channels shared by +all datasets. Skip datasets which have 0 overlap with the others.

+

returns: set of common channels, list of datasets with valid channels

+
+ +
+

Examples using moabb.datasets.utils.find_intersecting_channels#

+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.evaluations.CrossSessionEvaluation.html b/docs/generated/moabb.evaluations.CrossSessionEvaluation.html new file mode 100644 index 00000000..f15a91db --- /dev/null +++ b/docs/generated/moabb.evaluations.CrossSessionEvaluation.html @@ -0,0 +1,659 @@ + + + + + + + + + + + + moabb.evaluations.CrossSessionEvaluation — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.evaluations.CrossSessionEvaluation#

+
+
+class moabb.evaluations.CrossSessionEvaluation(paradigm, datasets=None, random_state=None, n_jobs=1, n_jobs_evaluation=1, overwrite=False, error_score='raise', suffix='', hdf5_path=None, additional_columns=None, return_epochs=False, return_raws=False, mne_labels=False, n_splits=None, save_model=False, cache_config=None)[source]#
+

Cross-session performance evaluation.

+

Evaluate performance of the pipeline across sessions but for a single +subject. Verifies that there is at least two sessions before starting +the evaluation.

+
+
Parameters:
+
    +
  • paradigm (Paradigm instance) – The paradigm to use.

  • +
  • datasets (List of Dataset instance) – The list of dataset to run the evaluation. If none, the list of +compatible dataset will be retrieved from the paradigm instance.

  • +
  • random_state (int, RandomState instance, default=None) – If not None, can guarantee same seed for shuffling examples.

  • +
  • n_jobs (int, default=1) – Number of jobs for fitting of pipeline.

  • +
  • n_jobs_evaluation (int, default=1) – Number of jobs for evaluation, processing in parallel the within session, +cross-session or cross-subject.

  • +
  • overwrite (bool, default=False) – If true, overwrite the results.

  • +
  • error_score ("raise" or numeric, default="raise") – Value to assign to the score if an error occurs in estimator fitting. If set to +‘raise’, the error is raised.

  • +
  • suffix (str) – Suffix for the results file.

  • +
  • hdf5_path (str) – Specific path for storing the results and models.

  • +
  • additional_columns (None) – Adding information to results.

  • +
  • return_epochs (bool, default=False) – use MNE epoch to train pipelines.

  • +
  • return_raws (bool, default=False) – use MNE raw to train pipelines.

  • +
  • mne_labels (bool, default=False) – if returning MNE epoch, use original dataset label if True

  • +
+
+
+
+
+evaluate(dataset, pipelines, param_grid, process_pipeline, postprocess_pipeline=None)[source]#
+

Evaluate results on a single dataset.

+

This method return a generator. each results item is a dict with +the following conversion:

+
res = {'time': Duration of the training ,
+       'dataset': dataset id,
+       'subject': subject id,
+       'session': session id,
+       'score': score,
+       'n_samples': number of training examples,
+       'n_channels': number of channel,
+       'pipeline': pipeline name}
+
+
+
+ +
+
+is_valid(dataset)[source]#
+

Verify the dataset is compatible with evaluation.

+

This method is called to verify dataset given in the constructor +are compatible with the evaluation context.

+

This method should return false if the dataset does not match the +evaluation. This is for example the case if the dataset does not +contain enough session for a cross-session eval.

+
+
Parameters:
+

dataset (dataset instance) – The dataset to verify.

+
+
+
+ +
+ +
+

Examples using moabb.evaluations.CrossSessionEvaluation#

+
Cross-session motor imagery with deep learning EEGNet v4 model +

Cross-session motor imagery with deep learning EEGNet v4 model

+
Cross-session motor imagery with deep learning EEGNet v4 model
+
Cross-Session Motor Imagery +

Cross-Session Motor Imagery

+
Cross-Session Motor Imagery
+
Cross-Session on Multiple Datasets +

Cross-Session on Multiple Datasets

+
Cross-Session on Multiple Datasets
+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
Tutorial 0: Getting Started +

Tutorial 0: Getting Started

+
Tutorial 0: Getting Started
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.evaluations.CrossSubjectEvaluation.html b/docs/generated/moabb.evaluations.CrossSubjectEvaluation.html new file mode 100644 index 00000000..e0d3cb1b --- /dev/null +++ b/docs/generated/moabb.evaluations.CrossSubjectEvaluation.html @@ -0,0 +1,642 @@ + + + + + + + + + + + + moabb.evaluations.CrossSubjectEvaluation — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.evaluations.CrossSubjectEvaluation#

+
+
+class moabb.evaluations.CrossSubjectEvaluation(paradigm, datasets=None, random_state=None, n_jobs=1, n_jobs_evaluation=1, overwrite=False, error_score='raise', suffix='', hdf5_path=None, additional_columns=None, return_epochs=False, return_raws=False, mne_labels=False, n_splits=None, save_model=False, cache_config=None)[source]#
+

Cross-subject evaluation performance.

+

Evaluate performance of the pipeline trained on all subjects but one, +concatenating sessions.

+
+
Parameters:
+
    +
  • paradigm (Paradigm instance) – The paradigm to use.

  • +
  • datasets (List of Dataset instance) – The list of dataset to run the evaluation. If none, the list of +compatible dataset will be retrieved from the paradigm instance.

  • +
  • random_state (int, RandomState instance, default=None) – If not None, can guarantee same seed for shuffling examples.

  • +
  • n_jobs (int, default=1) – Number of jobs for fitting of pipeline.

  • +
  • n_jobs_evaluation (int, default=1) – Number of jobs for evaluation, processing in parallel the within session, +cross-session or cross-subject.

  • +
  • overwrite (bool, default=False) – If true, overwrite the results.

  • +
  • error_score ("raise" or numeric, default="raise") – Value to assign to the score if an error occurs in estimator fitting. If set to +‘raise’, the error is raised.

  • +
  • suffix (str) – Suffix for the results file.

  • +
  • hdf5_path (str) – Specific path for storing the results and models.

  • +
  • additional_columns (None) – Adding information to results.

  • +
  • return_epochs (bool, default=False) – use MNE epoch to train pipelines.

  • +
  • return_raws (bool, default=False) – use MNE raw to train pipelines.

  • +
  • mne_labels (bool, default=False) – if returning MNE epoch, use original dataset label if True

  • +
  • n_splits (int, default=None) – Number of splits for cross-validation. If None, the number of splits +is equal to the number of subjects.

  • +
+
+
+
+
+evaluate(dataset, pipelines, param_grid, process_pipeline, postprocess_pipeline=None)[source]#
+

Evaluate results on a single dataset.

+

This method return a generator. each results item is a dict with +the following conversion:

+
res = {'time': Duration of the training ,
+       'dataset': dataset id,
+       'subject': subject id,
+       'session': session id,
+       'score': score,
+       'n_samples': number of training examples,
+       'n_channels': number of channel,
+       'pipeline': pipeline name}
+
+
+
+ +
+
+is_valid(dataset)[source]#
+

Verify the dataset is compatible with evaluation.

+

This method is called to verify dataset given in the constructor +are compatible with the evaluation context.

+

This method should return false if the dataset does not match the +evaluation. This is for example the case if the dataset does not +contain enough session for a cross-session eval.

+
+
Parameters:
+

dataset (dataset instance) – The dataset to verify.

+
+
+
+ +
+ +
+

Examples using moabb.evaluations.CrossSubjectEvaluation#

+
Cross-Subject SSVEP +

Cross-Subject SSVEP

+
Cross-Subject SSVEP
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.evaluations.WithinSessionEvaluation.html b/docs/generated/moabb.evaluations.WithinSessionEvaluation.html new file mode 100644 index 00000000..bb197242 --- /dev/null +++ b/docs/generated/moabb.evaluations.WithinSessionEvaluation.html @@ -0,0 +1,688 @@ + + + + + + + + + + + + moabb.evaluations.WithinSessionEvaluation — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.evaluations.WithinSessionEvaluation#

+
+
+class moabb.evaluations.WithinSessionEvaluation(n_perms: Optional[Union[int, list, tuple, ndarray]] = None, data_size: Optional[dict] = None, **kwargs)[source]#
+

Performance evaluation within session (k-fold cross-validation)

+

Within-session evaluation uses k-fold cross_validation to determine train +and test sets on separate session for each subject, it is possible to +estimate the performance on a subset of training examples to obtain +learning curves.

+
+
Parameters:
+
    +
  • n_perms – Number of permutations to perform. If an array +is passed it has to be equal in size to the data_size array. +Values in this array must be monotonically decreasing (performing +more permutations for more data is not useful to reduce standard +error of the mean). +Default: None

  • +
  • data_size – If None is passed, it performs conventional WithinSession evaluation. +Contains the policy to pick the datasizes to +evaluate, as well as the actual values. The dict has the +key ‘policy’ with either ‘ratio’ or ‘per_class’, and the key +‘value’ with the actual values as an numpy array. This array should be +sorted, such that values in data_size are strictly monotonically increasing. +Default: None

  • +
  • paradigm (Paradigm instance) – The paradigm to use.

  • +
  • datasets (List of Dataset instance) – The list of dataset to run the evaluation. If none, the list of +compatible dataset will be retrieved from the paradigm instance.

  • +
  • random_state (int, RandomState instance, default=None) – If not None, can guarantee same seed for shuffling examples.

  • +
  • n_jobs (int, default=1) – Number of jobs for fitting of pipeline.

  • +
  • n_jobs_evaluation (int, default=1) – Number of jobs for evaluation, processing in parallel the within session, +cross-session or cross-subject.

  • +
  • overwrite (bool, default=False) – If true, overwrite the results.

  • +
  • error_score ("raise" or numeric, default="raise") – Value to assign to the score if an error occurs in estimator fitting. If set to +‘raise’, the error is raised.

  • +
  • suffix (str) – Suffix for the results file.

  • +
  • hdf5_path (str) – Specific path for storing the results and models.

  • +
  • additional_columns (None) – Adding information to results.

  • +
  • return_epochs (bool, default=False) – use MNE epoch to train pipelines.

  • +
  • return_raws (bool, default=False) – use MNE raw to train pipelines.

  • +
  • mne_labels (bool, default=False) – if returning MNE epoch, use original dataset label if True

  • +
+
+
+
+
+evaluate(dataset, pipelines, param_grid, process_pipeline, postprocess_pipeline=None)[source]#
+

Evaluate results on a single dataset.

+

This method return a generator. each results item is a dict with +the following conversion:

+
res = {'time': Duration of the training ,
+       'dataset': dataset id,
+       'subject': subject id,
+       'session': session id,
+       'score': score,
+       'n_samples': number of training examples,
+       'n_channels': number of channel,
+       'pipeline': pipeline name}
+
+
+
+ +
+
+is_valid(dataset)[source]#
+

Verify the dataset is compatible with evaluation.

+

This method is called to verify dataset given in the constructor +are compatible with the evaluation context.

+

This method should return false if the dataset does not match the +evaluation. This is for example the case if the dataset does not +contain enough session for a cross-session eval.

+
+
Parameters:
+

dataset (dataset instance) – The dataset to verify.

+
+
+
+ +
+ +
+

Examples using moabb.evaluations.WithinSessionEvaluation#

+
Within Session P300 +

Within Session P300

+
Within Session P300
+
Within Session SSVEP +

Within Session SSVEP

+
Within Session SSVEP
+
GridSearch within a session +

GridSearch within a session

+
GridSearch within a session
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Within Session Motor Imagery with Learning Curve +

Within Session Motor Imagery with Learning Curve

+
Within Session Motor Imagery with Learning Curve
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Tutorial 4: Creating a dataset class +

Tutorial 4: Creating a dataset class

+
Tutorial 4: Creating a dataset class
+
Tutorial 5: Creating a dataset class +

Tutorial 5: Creating a dataset class

+
Tutorial 5: Creating a dataset class
+
Tutorial 1: Simple Motor Imagery +

Tutorial 1: Simple Motor Imagery

+
Tutorial 1: Simple Motor Imagery
+
Tutorial 2: Using multiple datasets +

Tutorial 2: Using multiple datasets

+
Tutorial 2: Using multiple datasets
+
Tutorial 3: Benchmarking multiple pipelines +

Tutorial 3: Benchmarking multiple pipelines

+
Tutorial 3: Benchmarking multiple pipelines
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.evaluations.base.BaseEvaluation.html b/docs/generated/moabb.evaluations.base.BaseEvaluation.html new file mode 100644 index 00000000..aa9163e2 --- /dev/null +++ b/docs/generated/moabb.evaluations.base.BaseEvaluation.html @@ -0,0 +1,721 @@ + + + + + + + + + + + + moabb.evaluations.base.BaseEvaluation — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.evaluations.base.BaseEvaluation#

+
+
+class moabb.evaluations.base.BaseEvaluation(paradigm, datasets=None, random_state=None, n_jobs=1, n_jobs_evaluation=1, overwrite=False, error_score='raise', suffix='', hdf5_path=None, additional_columns=None, return_epochs=False, return_raws=False, mne_labels=False, n_splits=None, save_model=False, cache_config=None)[source]#
+

Base class that defines necessary operations for an evaluation. +Evaluations determine what the train and test sets are and can implement +additional data preprocessing steps for more complicated algorithms.

+
+
Parameters:
+
    +
  • paradigm (Paradigm instance) – The paradigm to use.

  • +
  • datasets (List of Dataset instance) – The list of dataset to run the evaluation. If none, the list of +compatible dataset will be retrieved from the paradigm instance.

  • +
  • random_state (int, RandomState instance, default=None) – If not None, can guarantee same seed for shuffling examples.

  • +
  • n_jobs (int, default=1) – Number of jobs for fitting of pipeline.

  • +
  • n_jobs_evaluation (int, default=1) – Number of jobs for evaluation, processing in parallel the within session, +cross-session or cross-subject.

  • +
  • overwrite (bool, default=False) – If true, overwrite the results.

  • +
  • error_score ("raise" or numeric, default="raise") – Value to assign to the score if an error occurs in estimator fitting. If set to +‘raise’, the error is raised.

  • +
  • suffix (str) – Suffix for the results file.

  • +
  • hdf5_path (str) – Specific path for storing the results.

  • +
  • additional_columns (None) – Adding information to results.

  • +
  • return_epochs (bool, default=False) – use MNE epoch to train pipelines.

  • +
  • return_raws (bool, default=False) – use MNE raw to train pipelines.

  • +
  • mne_labels (bool, default=False) – if returning MNE epoch, use original dataset label if True

  • +
+
+
+
+
+abstract evaluate(dataset, pipelines, param_grid, process_pipeline, postprocess_pipeline=None)[source]#
+

Evaluate results on a single dataset.

+

This method return a generator. each results item is a dict with +the following conversion:

+
res = {'time': Duration of the training ,
+       'dataset': dataset id,
+       'subject': subject id,
+       'session': session id,
+       'score': score,
+       'n_samples': number of training examples,
+       'n_channels': number of channel,
+       'pipeline': pipeline name}
+
+
+
+ +
+
+abstract is_valid(dataset)[source]#
+

Verify the dataset is compatible with evaluation.

+

This method is called to verify dataset given in the constructor +are compatible with the evaluation context.

+

This method should return false if the dataset does not match the +evaluation. This is for example the case if the dataset does not +contain enough session for a cross-session eval.

+
+
Parameters:
+

dataset (dataset instance) – The dataset to verify.

+
+
+
+ +
+
+process(pipelines, param_grid=None, postprocess_pipeline=None)[source]#
+

Runs all pipelines on all datasets.

+

This function will apply all provided pipelines and return a dataframe +containing the results of the evaluation.

+
+
Parameters:
+
    +
  • pipelines (dict of pipeline instance.) – A dict containing the sklearn pipeline to evaluate.

  • +
  • param_grid (dict of str) – The key of the dictionary must be the same as the associated pipeline.

  • +
  • postprocess_pipeline (Pipeline | None) – Optional pipeline to apply to the data after the preprocessing. +This pipeline will either receive mne.io.BaseRaw, mne.Epochs +or np.ndarray() as input, depending on the values of return_epochs +and return_raws. +This pipeline must return an np.ndarray. +This pipeline must be “fixed” because it will not be trained, +i.e. no call to fit will be made.

  • +
+
+
Returns:
+

results – A dataframe containing the results.

+
+
Return type:
+

pd.DataFrame

+
+
+
+ +
+ +
+

Examples using moabb.evaluations.base.BaseEvaluation#

+
Cross-session motor imagery with deep learning EEGNet v4 model +

Cross-session motor imagery with deep learning EEGNet v4 model

+
Cross-session motor imagery with deep learning EEGNet v4 model
+
Cross-Session Motor Imagery +

Cross-Session Motor Imagery

+
Cross-Session Motor Imagery
+
Cross-Session on Multiple Datasets +

Cross-Session on Multiple Datasets

+
Cross-Session on Multiple Datasets
+
Cross-Subject SSVEP +

Cross-Subject SSVEP

+
Cross-Subject SSVEP
+
Within Session P300 +

Within Session P300

+
Within Session P300
+
Within Session SSVEP +

Within Session SSVEP

+
Within Session SSVEP
+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
GridSearch within a session +

GridSearch within a session

+
GridSearch within a session
+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Within Session Motor Imagery with Learning Curve +

Within Session Motor Imagery with Learning Curve

+
Within Session Motor Imagery with Learning Curve
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Tutorial 0: Getting Started +

Tutorial 0: Getting Started

+
Tutorial 0: Getting Started
+
Tutorial 1: Simple Motor Imagery +

Tutorial 1: Simple Motor Imagery

+
Tutorial 1: Simple Motor Imagery
+
Tutorial 2: Using multiple datasets +

Tutorial 2: Using multiple datasets

+
Tutorial 2: Using multiple datasets
+
Tutorial 3: Benchmarking multiple pipelines +

Tutorial 3: Benchmarking multiple pipelines

+
Tutorial 3: Benchmarking multiple pipelines
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.make_process_pipelines.html b/docs/generated/moabb.make_process_pipelines.html new file mode 100644 index 00000000..cd495321 --- /dev/null +++ b/docs/generated/moabb.make_process_pipelines.html @@ -0,0 +1,571 @@ + + + + + + + + + + + + moabb.make_process_pipelines — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + + + + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.BaseFixedIntervalWindowsProcessing.html b/docs/generated/moabb.paradigms.BaseFixedIntervalWindowsProcessing.html new file mode 100644 index 00000000..babceb18 --- /dev/null +++ b/docs/generated/moabb.paradigms.BaseFixedIntervalWindowsProcessing.html @@ -0,0 +1,633 @@ + + + + + + + + + + + + moabb.paradigms.BaseFixedIntervalWindowsProcessing — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.BaseFixedIntervalWindowsProcessing#

+
+
+class moabb.paradigms.BaseFixedIntervalWindowsProcessing(filters=None, baseline=None, channels=None, resample=None, length: float = 5.0, stride: float = 10.0, start_offset=0.0, stop_offset=None, marker=-1)[source]#
+

Base class for fixed interval windows processing.

+

Paradigm for creating epochs at fixed interval, +ignoring the stim channel and events of the dataset.

+
+
Parameters:
+
    +
  • filters (list of list (default [[7, 45]])) – bank of bandpass filter to apply.

  • +
  • 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.

  • +
  • length (float (default 5.0)) – Length of the epochs in seconds.

  • +
  • stride (float (default 10.0)) – Stride between epochs in seconds.

  • +
  • start_offset (float (default 0.0)) – Start from the beginning of the raw recordings in seconds.

  • +
  • stop_offset (float | None (default None)) – Stop offset from beginning of raw recordings in seconds. +If None, set to be the end of the recording.

  • +
  • marker (int (default -1)) – Marker to use for the events created.

  • +
+
+
+

Notes

+
+

New in version 1.0.0.

+
+
+
+property datasets#
+

Property that define the list of compatible datasets.

+
+ +
+
+is_valid(dataset)[source]#
+

Verify the dataset is compatible with the paradigm.

+

This method is called to verify dataset is compatible with the +paradigm.

+

This method should raise an error if the dataset is not compatible +with the paradigm. This is for example the case if the +dataset is an ERP dataset for motor imagery paradigm, or if the +dataset does not contain any of the required events.

+
+
Parameters:
+

dataset (dataset instance) – The dataset to verify.

+
+
+
+ +
+ +
+

Examples using moabb.paradigms.BaseFixedIntervalWindowsProcessing#

+
Fixed interval windows processing +

Fixed interval windows processing

+
Fixed interval windows processing
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.CVEP.html b/docs/generated/moabb.paradigms.CVEP.html new file mode 100644 index 00000000..54dda020 --- /dev/null +++ b/docs/generated/moabb.paradigms.CVEP.html @@ -0,0 +1,607 @@ + + + + + + + + + + + + moabb.paradigms.CVEP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.CVEP#

+
+
+class moabb.paradigms.CVEP(fmin=1.0, fmax=45.0, **kwargs)[source]#
+

Single bandpass c-VEP paradigm for epoch-level decoding.

+

c-VEP paradigm with only one bandpass filter (default 1 to 45 Hz) +Metric is ‘roc-auc’ if 2 classes and ‘accuracy’ if more. +This paradigm is meant to be used for epoch-level decoding of c-VEP +datasets; this means that the goal of the classifiers with this paradigm +is to predict, for every stimulation one by one, the amplitude of +the target code. The code value is between 0 (i.e., stimulation off) +and 1 (i.e., maximal stimulation).

+
+
Parameters:
+
    +
  • fmin (float (default 1.0)) – cutoff frequency (Hz) for the highpass filter

  • +
  • fmax (float (default 45.0)) – cutoff frequency (Hz) for the lowpass filter

  • +
  • events (List of str | None (default None)) – Event to use for epoching. Note, we stick to a convention where the +intensity level is encoded as float. For example, a binary sequence +would have events 1.0 (i.e., on) and 0.0 (i.e., off). If None, default +to all events defined in the dataset.

  • +
  • n_classes (int or None (default None)) – Number of classes each dataset must have. All dataset classes if None

  • +
  • 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 (default None)) – 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.

  • +
+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.FilterBankCVEP.html b/docs/generated/moabb.paradigms.FilterBankCVEP.html new file mode 100644 index 00000000..96f913f8 --- /dev/null +++ b/docs/generated/moabb.paradigms.FilterBankCVEP.html @@ -0,0 +1,606 @@ + + + + + + + + + + + + moabb.paradigms.FilterBankCVEP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.FilterBankCVEP#

+
+
+class moabb.paradigms.FilterBankCVEP(filters=((1.0, 45.0), (12.0, 45.0), (30.0, 45.0)), **kwargs)[source]#
+

Filterbank c-VEP paradigm for epoch-level decoding.

+

c-VEP paradigm with multiple bandpass filters. +Metric is ‘roc-auc’ if 2 classes and ‘accuracy’ if more. +This paradigm is meant to be used for epoch-level decoding of c-VEP +datasets; this means that the goal of the classifiers with this paradigm +is to predict, for every stimulation one by one, the amplitude of +the target code. The code value is between 0 (i.e., stimulation off) +and 1 (i.e., maximal stimulation).

+
+
Parameters:
+
    +
  • filters (tuple of tuple | None (default ((1., 45.), (12., 45.), (30., 45.)))) – Bank of bandpass filter to apply.

  • +
  • events (List of str | None (default None)) – Event to use for epoching. Note, we stick to a convention where the +intensity level is encoded as float. For example, a binary sequence +would have events 1.0 (i.e., on) and 0.0 (i.e., off). If None, default +to all events defined in the dataset.

  • +
  • n_classes (int or None (default None)) – Number of classes each dataset must have. All dataset classes if None

  • +
  • 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 (default None)) – 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.

  • +
+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.FilterBankFixedIntervalWindowsProcessing.html b/docs/generated/moabb.paradigms.FilterBankFixedIntervalWindowsProcessing.html new file mode 100644 index 00000000..c5e083cf --- /dev/null +++ b/docs/generated/moabb.paradigms.FilterBankFixedIntervalWindowsProcessing.html @@ -0,0 +1,603 @@ + + + + + + + + + + + + moabb.paradigms.FilterBankFixedIntervalWindowsProcessing — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.FilterBankFixedIntervalWindowsProcessing#

+
+
+class moabb.paradigms.FilterBankFixedIntervalWindowsProcessing(filters=((8, 12), (12, 16), (16, 20), (20, 24), (24, 28), (28, 32)), baseline=None, channels=None, resample=None, length: float = 5.0, stride: float = 10.0, start_offset=0.0, stop_offset=None, marker=-1)[source]#
+

Filter bank fixed interval windows processing.

+

Paradigm for creating epochs at fixed interval +with multiple narrow bandpass filters, +ignoring the stim channel and events of the dataset.

+
+
Parameters:
+
    +
  • filters (list of list (default ((8, 12), (12, 16), (16, 20), (20, 24), (24, 28), (28, 32)))) – bank of bandpass filter to apply.

  • +
  • 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.

  • +
  • length (float (default 5.0)) – Length of the epochs in seconds.

  • +
  • stride (float (default 10.0)) – Stride between epochs in seconds.

  • +
  • start_offset (float (default 0.0)) – Start from the beginning of the raw recordings in seconds.

  • +
  • stop_offset (float | None (default None)) – Stop offset from beginning of raw recordings in seconds. +If None, set to be the end of the recording.

  • +
  • marker (int (default -1)) – Marker to use for the events created.

  • +
+
+
+
+ +
+

Examples using moabb.paradigms.FilterBankFixedIntervalWindowsProcessing#

+
Fixed interval windows processing +

Fixed interval windows processing

+
Fixed interval windows processing
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.FilterBankLeftRightImagery.html b/docs/generated/moabb.paradigms.FilterBankLeftRightImagery.html new file mode 100644 index 00000000..3bd32516 --- /dev/null +++ b/docs/generated/moabb.paradigms.FilterBankLeftRightImagery.html @@ -0,0 +1,590 @@ + + + + + + + + + + + + moabb.paradigms.FilterBankLeftRightImagery — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.FilterBankLeftRightImagery#

+
+
+class moabb.paradigms.FilterBankLeftRightImagery(**kwargs)[source]#
+

Filter Bank Motor Imagery for left hand/right hand classification.

+

Metric is ‘roc_auc’

+
+
+property scoring#
+

Property that defines scoring metric (e.g. ROC-AUC or accuracy +or f-score), given as a sklearn-compatible string or a compatible +sklearn scorer.

+
+ +
+ +
+

Examples using moabb.paradigms.FilterBankLeftRightImagery#

+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.FilterBankMotorImagery.html b/docs/generated/moabb.paradigms.FilterBankMotorImagery.html new file mode 100644 index 00000000..aa16d6d0 --- /dev/null +++ b/docs/generated/moabb.paradigms.FilterBankMotorImagery.html @@ -0,0 +1,625 @@ + + + + + + + + + + + + moabb.paradigms.FilterBankMotorImagery — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.FilterBankMotorImagery#

+
+
+class moabb.paradigms.FilterBankMotorImagery(n_classes=2, **kwargs)[source]#
+

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.

  • +
+
+
+
+
+property datasets#
+

Property that define the list of compatible datasets.

+
+ +
+
+is_valid(dataset)[source]#
+

Verify the dataset is compatible with the paradigm.

+

This method is called to verify dataset is compatible with the +paradigm.

+

This method should raise an error if the dataset is not compatible +with the paradigm. This is for example the case if the +dataset is an ERP dataset for motor imagery paradigm, or if the +dataset does not contain any of the required events.

+
+
Parameters:
+

dataset (dataset instance) – The dataset to verify.

+
+
+
+ +
+
+property scoring#
+

Property that defines scoring metric (e.g. ROC-AUC or accuracy +or f-score), given as a sklearn-compatible string or a compatible +sklearn scorer.

+
+ +
+ +
+

Examples using moabb.paradigms.FilterBankMotorImagery#

+
Explore Paradigm Object +

Explore Paradigm Object

+
Explore Paradigm Object
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.FilterBankSSVEP.html b/docs/generated/moabb.paradigms.FilterBankSSVEP.html new file mode 100644 index 00000000..caf37e50 --- /dev/null +++ b/docs/generated/moabb.paradigms.FilterBankSSVEP.html @@ -0,0 +1,610 @@ + + + + + + + + + + + + moabb.paradigms.FilterBankSSVEP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.FilterBankSSVEP#

+
+
+class moabb.paradigms.FilterBankSSVEP(filters=None, **kwargs)[source]#
+

Filtered bank n-class SSVEP paradigm.

+

SSVEP paradigm with multiple narrow bandpass filters, centered around the +frequencies of considered events. +Metric is ‘roc-auc’ if 2 classes and ‘accuracy’ if more. +:param filters: If None, bandpass set around freqs of events with [f_n-0.5, f_n+0.5] +:type filters: list of list | None (default None) +:param events: List of stimulation frequencies. If None, use all stimulus

+
+

found in the dataset.

+
+
+
Parameters:
+
    +
  • n_classes (int or None (default 2)) – Number of classes each dataset must have. All dataset classes if None

  • +
  • 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.

  • +
+
+
+
+ +
+

Examples using moabb.paradigms.FilterBankSSVEP#

+
Cross-Subject SSVEP +

Cross-Subject SSVEP

+
Cross-Subject SSVEP
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.FixedIntervalWindowsProcessing.html b/docs/generated/moabb.paradigms.FixedIntervalWindowsProcessing.html new file mode 100644 index 00000000..49186ea8 --- /dev/null +++ b/docs/generated/moabb.paradigms.FixedIntervalWindowsProcessing.html @@ -0,0 +1,613 @@ + + + + + + + + + + + + moabb.paradigms.FixedIntervalWindowsProcessing — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.FixedIntervalWindowsProcessing#

+
+
+class moabb.paradigms.FixedIntervalWindowsProcessing(fmin=7, fmax=45, baseline=None, channels=None, resample=None, length: float = 5.0, stride: float = 10.0, start_offset=0.0, stop_offset=None, marker=-1)[source]#
+

Fixed interval windows processing.

+

Paradigm for creating epochs at fixed interval, +ignoring the stim channel and events of the dataset.

+
+
Parameters:
+
+
fmin: float (default 7)

cutoff frequency (Hz) for the high pass filter

+
+
fmax: float (default 45)

cutoff frequency (Hz) for the low pass filter

+
+
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.

+
+
length: float (default 5.0)

Length of the epochs in seconds.

+
+
stride: float (default 10.0)

Stride between epochs in seconds.

+
+
start_offset: float (default 0.0)

Start from the beginning of the raw recordings in seconds.

+
+
stop_offset: float | None (default None)

Stop offset from beginning of raw recordings in seconds. +If None, set to be the end of the recording.

+
+
marker: int (default -1)

Marker to use for the events created.

+
+
+
+
+
+ +
+

Examples using moabb.paradigms.FixedIntervalWindowsProcessing#

+
Fixed interval windows processing +

Fixed interval windows processing

+
Fixed interval windows processing
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.LeftRightImagery.html b/docs/generated/moabb.paradigms.LeftRightImagery.html new file mode 100644 index 00000000..801a1184 --- /dev/null +++ b/docs/generated/moabb.paradigms.LeftRightImagery.html @@ -0,0 +1,632 @@ + + + + + + + + + + + + moabb.paradigms.LeftRightImagery — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.LeftRightImagery#

+
+
+class moabb.paradigms.LeftRightImagery(**kwargs)[source]#
+

Motor Imagery for left hand/right hand classification.

+

Metric is ‘roc_auc’

+
+
+property scoring#
+

Property that defines scoring metric (e.g. ROC-AUC or accuracy +or f-score), given as a sklearn-compatible string or a compatible +sklearn scorer.

+
+ +
+ +
+

Examples using moabb.paradigms.LeftRightImagery#

+
Benchmarking with MOABB showing the CO2 footprint +

Benchmarking with MOABB showing the CO2 footprint

+
Benchmarking with MOABB showing the CO2 footprint
+
Examples of how to use MOABB to benchmark pipelines. +

Examples of how to use MOABB to benchmark pipelines.

+
Examples of how to use MOABB to benchmark pipelines.
+
Cross-Session Motor Imagery +

Cross-Session Motor Imagery

+
Cross-Session Motor Imagery
+
Cross-Session on Multiple Datasets +

Cross-Session on Multiple Datasets

+
Cross-Session on Multiple Datasets
+
Cache on disk intermediate data processing states +

Cache on disk intermediate data processing states

+
Cache on disk intermediate data processing states
+
Explore Paradigm Object +

Explore Paradigm Object

+
Explore Paradigm Object
+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
Within Session Motor Imagery with Learning Curve +

Within Session Motor Imagery with Learning Curve

+
Within Session Motor Imagery with Learning Curve
+
Tutorial 4: Creating a dataset class +

Tutorial 4: Creating a dataset class

+
Tutorial 4: Creating a dataset class
+
Tutorial 0: Getting Started +

Tutorial 0: Getting Started

+
Tutorial 0: Getting Started
+
Tutorial 1: Simple Motor Imagery +

Tutorial 1: Simple Motor Imagery

+
Tutorial 1: Simple Motor Imagery
+
Tutorial 2: Using multiple datasets +

Tutorial 2: Using multiple datasets

+
Tutorial 2: Using multiple datasets
+
Tutorial 3: Benchmarking multiple pipelines +

Tutorial 3: Benchmarking multiple pipelines

+
Tutorial 3: Benchmarking multiple pipelines
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.MotorImagery.html b/docs/generated/moabb.paradigms.MotorImagery.html new file mode 100644 index 00000000..f847dc4b --- /dev/null +++ b/docs/generated/moabb.paradigms.MotorImagery.html @@ -0,0 +1,652 @@ + + + + + + + + + + + + moabb.paradigms.MotorImagery — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.MotorImagery#

+
+
+class moabb.paradigms.MotorImagery(n_classes=None, **kwargs)[source]#
+

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.

  • +
  • fmin (float (default 8)) – 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.

  • +
+
+
+
+
+property datasets#
+

Property that define the list of compatible datasets.

+
+ +
+
+is_valid(dataset)[source]#
+

Verify the dataset is compatible with the paradigm.

+

This method is called to verify dataset is compatible with the +paradigm.

+

This method should raise an error if the dataset is not compatible +with the paradigm. This is for example the case if the +dataset is an ERP dataset for motor imagery paradigm, or if the +dataset does not contain any of the required events.

+
+
Parameters:
+

dataset (dataset instance) – The dataset to verify.

+
+
+
+ +
+
+property scoring#
+

Property that defines scoring metric (e.g. ROC-AUC or accuracy +or f-score), given as a sklearn-compatible string or a compatible +sklearn scorer.

+
+ +
+ +
+

Examples using moabb.paradigms.MotorImagery#

+
Cross-session motor imagery with deep learning EEGNet v4 model +

Cross-session motor imagery with deep learning EEGNet v4 model

+
Cross-session motor imagery with deep learning EEGNet v4 model
+
Explore Paradigm Object +

Explore Paradigm Object

+
Explore Paradigm Object
+
Fixed interval windows processing +

Fixed interval windows processing

+
Fixed interval windows processing
+
GridSearch within a session +

GridSearch within a session

+
GridSearch within a session
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.P300.html b/docs/generated/moabb.paradigms.P300.html new file mode 100644 index 00000000..5fcb2511 --- /dev/null +++ b/docs/generated/moabb.paradigms.P300.html @@ -0,0 +1,605 @@ + + + + + + + + + + + + moabb.paradigms.P300 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.P300#

+
+
+class moabb.paradigms.P300(**kwargs)[source]#
+

P300 for Target/NonTarget classification.

+

Metric is ‘roc_auc’

+
+
+property scoring#
+

Property that defines scoring metric (e.g. ROC-AUC or accuracy +or f-score), given as a sklearn-compatible string or a compatible +sklearn scorer.

+
+ +
+ +
+

Examples using moabb.paradigms.P300#

+
Example of P300 classification with different epoch size. +

sphx_glr_auto_examples_noplot_vr_pc_p300_different_epoch_size.py

+
Example of P300 classification with different epoch size.
+
Within Session P300 +

Within Session P300

+
Within Session P300
+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Tutorial 5: Creating a dataset class +

Tutorial 5: Creating a dataset class

+
Tutorial 5: Creating a dataset class
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.SSVEP.html b/docs/generated/moabb.paradigms.SSVEP.html new file mode 100644 index 00000000..8b707bbd --- /dev/null +++ b/docs/generated/moabb.paradigms.SSVEP.html @@ -0,0 +1,610 @@ + + + + + + + + + + + + moabb.paradigms.SSVEP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.SSVEP#

+
+
+class moabb.paradigms.SSVEP(fmin=7, fmax=45, **kwargs)[source]#
+

Single bandpass filter SSVEP.

+

SSVEP paradigm with only one bandpass filter (default 7 to 45 Hz) +Metric is ‘roc-auc’ if 2 classes and ‘accuracy’ if more

+
+
Parameters:
+
    +
  • fmin (float (default 7)) – cutoff frequency (Hz) for the high pass filter

  • +
  • fmax (float (default 45)) – cutoff frequency (Hz) for the low pass filter

  • +
  • events (list of str | None (default None)) – List of stimulation frequencies. If None, use all stimulus +found in the dataset.

  • +
  • n_classes (int or None (default None)) – Number of classes each dataset must have. All dataset classes if None

  • +
  • 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.

  • +
+
+
+
+ +
+

Examples using moabb.paradigms.SSVEP#

+
Cross-Subject SSVEP +

Cross-Subject SSVEP

+
Cross-Subject SSVEP
+
Within Session SSVEP +

Within Session SSVEP

+
Within Session SSVEP
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.SinglePass.html b/docs/generated/moabb.paradigms.SinglePass.html new file mode 100644 index 00000000..e750ecc4 --- /dev/null +++ b/docs/generated/moabb.paradigms.SinglePass.html @@ -0,0 +1,662 @@ + + + + + + + + + + + + moabb.paradigms.SinglePass — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.SinglePass#

+
+
+class moabb.paradigms.SinglePass(fmin=1, fmax=24, **kwargs)[source]#
+

Single Bandpass filter P300.

+

P300 paradigm with only one bandpass filter (default 1 to 24 Hz)

+
+
Parameters:
+
    +
  • fmin (float (default 1)) – cutoff frequency (Hz) for the high pass filter

  • +
  • fmax (float (default 24)) – cutoff frequency (Hz) for the low 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.

  • +
+
+
+
+ +
+

Examples using moabb.paradigms.SinglePass#

+
Examples of how to use MOABB to benchmark pipelines. +

Examples of how to use MOABB to benchmark pipelines.

+
Examples of how to use MOABB to benchmark pipelines.
+
Cross-session motor imagery with deep learning EEGNet v4 model +

Cross-session motor imagery with deep learning EEGNet v4 model

+
Cross-session motor imagery with deep learning EEGNet v4 model
+
Cross-Session Motor Imagery +

Cross-Session Motor Imagery

+
Cross-Session Motor Imagery
+
Cross-Session on Multiple Datasets +

Cross-Session on Multiple Datasets

+
Cross-Session on Multiple Datasets
+
Cache on disk intermediate data processing states +

Cache on disk intermediate data processing states

+
Cache on disk intermediate data processing states
+
Explore Paradigm Object +

Explore Paradigm Object

+
Explore Paradigm Object
+
Fixed interval windows processing +

Fixed interval windows processing

+
Fixed interval windows processing
+
Within Session P300 +

Within Session P300

+
Within Session P300
+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
GridSearch within a session +

GridSearch within a session

+
GridSearch within a session
+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Within Session Motor Imagery with Learning Curve +

Within Session Motor Imagery with Learning Curve

+
Within Session Motor Imagery with Learning Curve
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Tutorial 0: Getting Started +

Tutorial 0: Getting Started

+
Tutorial 0: Getting Started
+
Tutorial 1: Simple Motor Imagery +

Tutorial 1: Simple Motor Imagery

+
Tutorial 1: Simple Motor Imagery
+
Tutorial 2: Using multiple datasets +

Tutorial 2: Using multiple datasets

+
Tutorial 2: Using multiple datasets
+
Tutorial 3: Benchmarking multiple pipelines +

Tutorial 3: Benchmarking multiple pipelines

+
Tutorial 3: Benchmarking multiple pipelines
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.base.BaseParadigm.html b/docs/generated/moabb.paradigms.base.BaseParadigm.html new file mode 100644 index 00000000..7ba0786e --- /dev/null +++ b/docs/generated/moabb.paradigms.base.BaseParadigm.html @@ -0,0 +1,588 @@ + + + + + + + + + + + + moabb.paradigms.base.BaseParadigm — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.base.BaseParadigm#

+
+
+class moabb.paradigms.base.BaseParadigm(filters, events: Optional[List[str]] = None, tmin=0.0, tmax=None, baseline=None, channels=None, resample=None)[source]#
+

Base class for paradigms.

+
+
Parameters:
+

events (List of str | None (default None)) – event to use for epoching. If None, default to all events defined in +the dataset.

+
+
+
+
+abstract property scoring#
+

Property that defines scoring metric (e.g. ROC-AUC or accuracy +or f-score), given as a sklearn-compatible string or a compatible +sklearn scorer.

+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.base.BaseProcessing.html b/docs/generated/moabb.paradigms.base.BaseProcessing.html new file mode 100644 index 00000000..e9c10976 --- /dev/null +++ b/docs/generated/moabb.paradigms.base.BaseProcessing.html @@ -0,0 +1,729 @@ + + + + + + + + + + + + moabb.paradigms.base.BaseProcessing — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.base.BaseProcessing#

+
+
+class moabb.paradigms.base.BaseProcessing(filters: List[Tuple[float, float]], tmin: float = 0.0, tmax: Optional[float] = None, baseline: Optional[Tuple[float, float]] = None, channels: Optional[List[str]] = None, resample: Optional[float] = None)[source]#
+

Base Processing.

+

Please use one of the child classes

+
+
Parameters:
+
    +
  • filters (list of list (defaults [[7, 35]])) – bank of bandpass filter to apply.

  • +
  • 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.

  • +
+
+
+
+
+abstract property datasets#
+

Property that define the list of compatible datasets.

+
+ +
+
+get_data(dataset, subjects=None, return_epochs=False, return_raws=False, cache_config=None, postprocess_pipeline=None)[source]#
+

Return the data for a list of subject.

+

return the data, labels and a dataframe with metadata. the dataframe +will contain at least the following columns

+
    +
  • subject : the subject indice

  • +
  • session : the session indice

  • +
  • run : the run indice

  • +
+
+
Parameters:
+
    +
  • dataset – A dataset instance.

  • +
  • subjects (List of int) – List of subject number

  • +
  • return_epochs (boolean) – This flag specifies whether to return only the data array or the +complete processed mne.Epochs

  • +
  • return_raws (boolean) – To return raw files and events, to ensure compatibility with braindecode. +Mutually exclusive with return_epochs

  • +
  • cache_config (dict | CacheConfig) – Configuration for caching of datasets. See moabb.datasets.base.CacheConfig for details.

  • +
  • postprocess_pipeline (Pipeline | None) – Optional pipeline to apply to the data after the preprocessing. +This pipeline will either receive mne.io.BaseRaw, mne.Epochs +or np.ndarray() as input, depending on the values of return_epochs +and return_raws. +This pipeline must return an np.ndarray. +This pipeline must be “fixed” because it will not be trained, +i.e. no call to fit will be made.

  • +
+
+
Returns:
+

    +
  • X (Union[np.ndarray, mne.Epochs]) – the data that will be used as features for the model +Note: if return_epochs=True, this is mne.Epochs +if return_epochs=False, this is np.ndarray

  • +
  • labels (np.ndarray) – the labels for training / evaluating the model

  • +
  • metadata (pd.DataFrame) – A dataframe containing the metadata.

  • +
+

+
+
+
+ +
+
+abstract is_valid(dataset)[source]#
+

Verify the dataset is compatible with the paradigm.

+

This method is called to verify dataset is compatible with the +paradigm.

+

This method should raise an error if the dataset is not compatible +with the paradigm. This is for example the case if the +dataset is an ERP dataset for motor imagery paradigm, or if the +dataset does not contain any of the required events.

+
+
Parameters:
+

dataset (dataset instance) – The dataset to verify.

+
+
+
+ +
+
+make_labels_pipeline(dataset, return_epochs=False, return_raws=False)[source]#
+

Returns the pipeline that extracts the labels from the +output of the postprocess_pipeline. +Refer to the arguments of get_data() for more information.

+
+ +
+
+make_process_pipelines(dataset, return_epochs=False, return_raws=False, postprocess_pipeline=None)[source]#
+

Return the pre-processing pipelines corresponding to this paradigm (one per frequency band). +Refer to the arguments of get_data() for more information.

+
+ +
+
+match_all(datasets: List[BaseDataset], shift=-0.5, channel_merge_strategy: str = 'intersect', ignore=['stim'])[source]#
+

Initialize this paradigm to match all datasets in parameter: +- self.resample is set to match the minimum frequency in all datasets, minus shift.

+
+

If the frequency is 128 for example, then MNE can return 128 or 129 samples +depending on the dataset, even if the length of the epochs is 1s +Setting shift=-0.5 solves this particular issue.

+
+
    +
  • self.channels is initialized with the channels which are common to all datasets.

  • +
+
+
Parameters:
+
    +
  • datasets (List[BaseDataset]) – A dataset instance.

  • +
  • shift (List[BaseDataset]) – Shift the sampling frequency by this value +E.g.: if sampling=128 and shift=-0.5, then it returns 127.5 Hz

  • +
  • channel_merge_strategy (str (default: 'intersect')) – Accepts two values: +- ‘intersect’: keep only channels common to all datasets +- ‘union’: keep all channels from all datasets, removing duplicate

  • +
  • ignore (List[string]) – A list of channels to ignore

  • +
  • ..versionadded: – 0.6.0:

  • +
+
+
+
+ +
+
+prepare_process(dataset)[source]#
+

Prepare processing of raw files.

+

This function allows to set parameter of the paradigm class prior to +the preprocessing (process_raw). Does nothing by default and could be +overloaded if needed.

+
+
Parameters:
+

dataset (dataset instance) – The dataset corresponding to the raw file. mainly use to access +dataset specific information.

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.motor_imagery.BaseMotorImagery.html b/docs/generated/moabb.paradigms.motor_imagery.BaseMotorImagery.html new file mode 100644 index 00000000..89d3791b --- /dev/null +++ b/docs/generated/moabb.paradigms.motor_imagery.BaseMotorImagery.html @@ -0,0 +1,633 @@ + + + + + + + + + + + + moabb.paradigms.motor_imagery.BaseMotorImagery — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.motor_imagery.BaseMotorImagery#

+
+
+class moabb.paradigms.motor_imagery.BaseMotorImagery(filters=([7, 35],), events=None, tmin=0.0, tmax=None, baseline=None, channels=None, resample=None)[source]#
+

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)) – 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.

  • +
+
+
+
+
+property datasets#
+

Property that define the list of compatible datasets.

+
+ +
+
+is_valid(dataset)[source]#
+

Verify the dataset is compatible with the paradigm.

+

This method is called to verify dataset is compatible with the +paradigm.

+

This method should raise an error if the dataset is not compatible +with the paradigm. This is for example the case if the +dataset is an ERP dataset for motor imagery paradigm, or if the +dataset does not contain any of the required events.

+
+
Parameters:
+

dataset (dataset instance) – The dataset to verify.

+
+
+
+ +
+
+property scoring#
+

Property that defines scoring metric (e.g. ROC-AUC or accuracy +or f-score), given as a sklearn-compatible string or a compatible +sklearn scorer.

+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.motor_imagery.FilterBank.html b/docs/generated/moabb.paradigms.motor_imagery.FilterBank.html new file mode 100644 index 00000000..b26d47a1 --- /dev/null +++ b/docs/generated/moabb.paradigms.motor_imagery.FilterBank.html @@ -0,0 +1,571 @@ + + + + + + + + + + + + moabb.paradigms.motor_imagery.FilterBank — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.motor_imagery.FilterBank#

+
+
+class moabb.paradigms.motor_imagery.FilterBank(filters=([8, 12], [12, 16], [16, 20], [20, 24], [24, 28], [28, 32]), **kwargs)[source]#
+

Filter Bank MI.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.motor_imagery.SinglePass.html b/docs/generated/moabb.paradigms.motor_imagery.SinglePass.html new file mode 100644 index 00000000..b0bae7b3 --- /dev/null +++ b/docs/generated/moabb.paradigms.motor_imagery.SinglePass.html @@ -0,0 +1,650 @@ + + + + + + + + + + + + moabb.paradigms.motor_imagery.SinglePass — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.motor_imagery.SinglePass#

+
+
+class moabb.paradigms.motor_imagery.SinglePass(fmin=8, fmax=32, **kwargs)[source]#
+

Single Bandpass filter motor Imagery.

+

Motor imagery paradigm with only one bandpass filter (default 8 to 32 Hz)

+
+
Parameters:
+
    +
  • fmin (float (default 8)) – cutoff frequency (Hz) for the high pass filter

  • +
  • fmax (float (default 32)) – cutoff frequency (Hz) for the low 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.

  • +
+
+
+
+ +
+

Examples using moabb.paradigms.motor_imagery.SinglePass#

+
Examples of how to use MOABB to benchmark pipelines. +

Examples of how to use MOABB to benchmark pipelines.

+
Examples of how to use MOABB to benchmark pipelines.
+
Cross-session motor imagery with deep learning EEGNet v4 model +

Cross-session motor imagery with deep learning EEGNet v4 model

+
Cross-session motor imagery with deep learning EEGNet v4 model
+
Cross-Session Motor Imagery +

Cross-Session Motor Imagery

+
Cross-Session Motor Imagery
+
Cross-Session on Multiple Datasets +

Cross-Session on Multiple Datasets

+
Cross-Session on Multiple Datasets
+
Cache on disk intermediate data processing states +

Cache on disk intermediate data processing states

+
Cache on disk intermediate data processing states
+
Explore Paradigm Object +

Explore Paradigm Object

+
Explore Paradigm Object
+
Fixed interval windows processing +

Fixed interval windows processing

+
Fixed interval windows processing
+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
GridSearch within a session +

GridSearch within a session

+
GridSearch within a session
+
Select Electrodes and Resampling +

Select Electrodes and Resampling

+
Select Electrodes and Resampling
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
Within Session Motor Imagery with Learning Curve +

Within Session Motor Imagery with Learning Curve

+
Within Session Motor Imagery with Learning Curve
+
Tutorial 0: Getting Started +

Tutorial 0: Getting Started

+
Tutorial 0: Getting Started
+
Tutorial 1: Simple Motor Imagery +

Tutorial 1: Simple Motor Imagery

+
Tutorial 1: Simple Motor Imagery
+
Tutorial 2: Using multiple datasets +

Tutorial 2: Using multiple datasets

+
Tutorial 2: Using multiple datasets
+
Tutorial 3: Benchmarking multiple pipelines +

Tutorial 3: Benchmarking multiple pipelines

+
Tutorial 3: Benchmarking multiple pipelines
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.p300.BaseP300.html b/docs/generated/moabb.paradigms.p300.BaseP300.html new file mode 100644 index 00000000..cb1c0548 --- /dev/null +++ b/docs/generated/moabb.paradigms.p300.BaseP300.html @@ -0,0 +1,633 @@ + + + + + + + + + + + + moabb.paradigms.p300.BaseP300 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.p300.BaseP300#

+
+
+class moabb.paradigms.p300.BaseP300(filters=([1, 24],), events=None, tmin=0.0, tmax=None, baseline=None, channels=None, resample=None)[source]#
+

Base P300 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)) – 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.

  • +
+
+
+
+
+property datasets#
+

Property that define the list of compatible datasets.

+
+ +
+
+is_valid(dataset)[source]#
+

Verify the dataset is compatible with the paradigm.

+

This method is called to verify dataset is compatible with the +paradigm.

+

This method should raise an error if the dataset is not compatible +with the paradigm. This is for example the case if the +dataset is an ERP dataset for motor imagery paradigm, or if the +dataset does not contain any of the required events.

+
+
Parameters:
+

dataset (dataset instance) – The dataset to verify.

+
+
+
+ +
+
+property scoring#
+

Property that defines scoring metric (e.g. ROC-AUC or accuracy +or f-score), given as a sklearn-compatible string or a compatible +sklearn scorer.

+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.paradigms.ssvep.BaseSSVEP.html b/docs/generated/moabb.paradigms.ssvep.BaseSSVEP.html new file mode 100644 index 00000000..6d17eda1 --- /dev/null +++ b/docs/generated/moabb.paradigms.ssvep.BaseSSVEP.html @@ -0,0 +1,642 @@ + + + + + + + + + + + + moabb.paradigms.ssvep.BaseSSVEP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.paradigms.ssvep.BaseSSVEP#

+
+
+class moabb.paradigms.ssvep.BaseSSVEP(filters=((7, 45),), events=None, n_classes=None, tmin=0.0, tmax=None, baseline=None, channels=None, resample=None)[source]#
+

Base SSVEP Paradigm.

+
+
Parameters:
+
    +
  • filters (list of list | None (default [7, 45])) – Bank of bandpass filter to apply.

  • +
  • events (list of str | None (default None)) – List of stimulation frequencies. If None, use all stimulus +found in the dataset.

  • +
  • n_classes (int or None (default None)) – Number of classes each dataset must have. All dataset classes if None.

  • +
  • 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.

  • +
+
+
+
+
+property datasets#
+

List of datasets valid for the paradigm.

+
+ +
+
+is_valid(dataset)[source]#
+

Check if dataset is valid for the SSVEP paradigm.

+
+ +
+
+prepare_process(dataset)[source]#
+

Prepare dataset for processing, and using events if needed.

+

This function is called before the processing function, and is used to +prepare the dataset for processing. This includes: +get the events used for the paradigm, and set the filters if needed. +:param dataset: Dataset to prepare. +:type dataset: moabb.datasets.base.BaseDataset

+
+ +
+
+property scoring#
+

Return the default scoring method for this paradigm.

+

If n_classes use the roc_auc, else use accuracy. More details +about this default scoring method can be found in the original +moabb paper.

+
+ +
+
+used_events(dataset)[source]#
+

Return the mne events used for the dataset.

+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.classification.SSVEP_CCA.html b/docs/generated/moabb.pipelines.classification.SSVEP_CCA.html new file mode 100644 index 00000000..db166ced --- /dev/null +++ b/docs/generated/moabb.pipelines.classification.SSVEP_CCA.html @@ -0,0 +1,704 @@ + + + + + + + + + + + + moabb.pipelines.classification.SSVEP_CCA — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.classification.SSVEP_CCA#

+
+
+class moabb.pipelines.classification.SSVEP_CCA(interval, freqs, n_harmonics=3)[source]#
+

Classifier based on Canonical Correlation Analysis for SSVEP.

+

A CCA is computed from the set of training signals and some pure +sinusoids to act as reference. +Classification is made by taking the frequency with the max correlation, +as proposed in [1].

+
+
Parameters:
+
    +
  • interval (list of length 2) – List of form [tmin, tmax]. With tmin and tmax as defined in the SSVEP +paradigm moabb.paradigms.SSVEP()

  • +
  • freqs (dict with n_classes keys) – Frequencies corresponding to the SSVEP stimulation frequencies. +They are used to identify SSVEP classes presents in the data.

  • +
  • n_harmonics (int) – Number of stimulation frequency’s harmonics to be used in the generation +of the CCA reference signal.

  • +
+
+
+

References

+
+
+[1] +

Bin, G., Gao, X., Yan, Z., Hong, B., & Gao, S. (2009). An online +multi-channel SSVEP-based brain-computer interface using a +canonical correlation analysis method. Journal of neural +engineering, 6(4), 046002. +https://doi.org/10.1088/1741-2560/6/4/046002

+
+
+
+
+fit(X, y, sample_weight=None)[source]#
+

Compute reference sinusoid signal.

+

These sinusoid are generated for each frequency in the dataset

+
+ +
+
+predict(X)[source]#
+

Predict is made by taking the maximum correlation coefficient.

+
+ +
+
+predict_proba(X)[source]#
+

Probability could be computed from the correlation coefficient.

+
+ +
+
+set_fit_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') SSVEP_CCA[source]#
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in fit.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_score_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') SSVEP_CCA[source]#
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in score.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.classification.SSVEP_MsetCCA.html b/docs/generated/moabb.pipelines.classification.SSVEP_MsetCCA.html new file mode 100644 index 00000000..01c17249 --- /dev/null +++ b/docs/generated/moabb.pipelines.classification.SSVEP_MsetCCA.html @@ -0,0 +1,708 @@ + + + + + + + + + + + + moabb.pipelines.classification.SSVEP_MsetCCA — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.classification.SSVEP_MsetCCA#

+
+
+class moabb.pipelines.classification.SSVEP_MsetCCA(freqs, n_filters=1, n_jobs=1)[source]#
+

Classifier based on MsetCCA for SSVEP.

+
+

The MsetCCA method learns multiple linear transforms to extract +SSVEP common features from multiple sets of EEG data. These are then used +to compute the reference signal used in CCA [1].

+
+
+
Parameters:
+
    +
  • freqs (dict with n_classes keys) – Frequencies corresponding to the SSVEP stimulation frequencies. +They are used to identify SSVEP classes presents in the data.

  • +
  • n_filters (int) – Number of multisets spatial filters used per sample data. +It corresponds to the number of eigen vectors taken the solution of the +MAXVAR objective function as formulated in Eq.5 in [1].

  • +
+
+
+

References

+
+
+[1] +(1,2) +

Zhang, Y.U., Zhou, G., Jin, J., Wang, X. and Cichocki, A. (2014). Frequency +recognition in SSVEP-based BCI using multiset canonical correlation analysis. +International journal of neural systems, 24(04), p.1450013. +https://doi.org/10.1142/S0129065714500130

+
+
+

Notes

+
+

New in version 0.5.0.

+
+
+
+fit(X, y, sample_weight=None)[source]#
+

Compute the optimized reference signal at each stimulus +frequency.

+
+ +
+
+predict(X)[source]#
+

Predict is made by taking the maximum correlation coefficient.

+
+ +
+
+predict_proba(X)[source]#
+

Probability could be computed from the correlation coefficient.

+
+ +
+
+set_fit_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') SSVEP_MsetCCA[source]#
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in fit.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_score_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') SSVEP_MsetCCA[source]#
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in score.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.classification.SSVEP_TRCA.html b/docs/generated/moabb.pipelines.classification.SSVEP_TRCA.html new file mode 100644 index 00000000..f88576de --- /dev/null +++ b/docs/generated/moabb.pipelines.classification.SSVEP_TRCA.html @@ -0,0 +1,821 @@ + + + + + + + + + + + + moabb.pipelines.classification.SSVEP_TRCA — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.classification.SSVEP_TRCA#

+
+
+class moabb.pipelines.classification.SSVEP_TRCA(interval, freqs, downsample=1, is_ensemble=True, method='original', estimator='scm')[source]#
+

Classifier based on the Task-Related Component Analysis method [1]_ for +SSVEP.

+
+
Parameters:
+
    +
  • sfreq (float) – Sampling frequency of the data to be analyzed.

  • +
  • freqs (dict with n_classes keys) – Frequencies corresponding to the SSVEP components. These are +necessary to design the filterbank bands.

  • +
  • downsample (int, default=1) – Factor by which downsample the data. A downsample value of N will result +on a sampling frequency of (sfreq // N) by taking one sample every N of +the original data. In the original TRCA paper [1]_ data are at 250Hz.

  • +
  • is_ensemble (bool, default=False) – If True, predict on new data using the Ensemble-TRCA method described +in [1]_.

  • +
  • method (str, default='original') – ‘original’ computes euclidean mean for S as in the original paper [1]_. +‘riemann’ variation computes geodesic mean instead. This geodesic +mean is more robust to outlier but negatively impacted by ill-conditioned +matrices (when only few samples are available for training for instance). +If the geometric mean can’t be estimated, please consider trying ‘logeuclid’. +It computes log-euclidean mean instead of the affine-invariant one and is more robust +computationally. +‘riemann’ and ‘logeuclid’ variations are useful when lots of noisy +training data are available. With few training data ‘original’ is more +appropriate.

  • +
  • estimator (str) – For both methods, regularization to use for covariance matrices estimations. +Consider ‘schaefer’, ‘lwf’, ‘oas’ or ‘scm’ for no regularization. +In the original implementation from TRCA paper [1]_, no regularization +is used. So method=’original’ and regul=’scm’ is similar to original +implementation.

  • +
+
+
+
+
+fb_coefs#
+

Alpha coefficients for the fusion of the filterbank sub-bands.

+
+
Type:
+

list of len (n_fbands)

+
+
+
+ +
+
+classes_#
+

Array with the class labels extracted at fit time.

+
+
Type:
+

ndarray of shape (n_classes,)

+
+
+
+ +
+
+n_classes#
+

Number of unique labels/classes.

+
+
Type:
+

int

+
+
+
+ +
+
+templates_#
+

Template data obtained by averaging all training trials for a given +class. Each class templates is divided in n_fbands sub-bands extracted +from the filterbank approach.

+
+
Type:
+

ndarray of shape (n_classes, n_bands, n_channels, n_samples)

+
+
+
+ +
+
+weights_#
+

Weight coefficients for the different electrodes which are used +as spatial filters for the data.

+
+
Type:
+

ndarray of shape (n_fbands, n_classes, n_channels)

+
+
+
+ +
+
+Reference#
+
+ +
+
+----------
+
+ +
+
+.. [1] M. Nakanishi, Y. Wang, X. Chen, Y. -T. Wang, X. Gao, and T.-P. Jung,
+

“Enhancing detection of SSVEPs for a high-speed brain speller using +task-related component analysis”, +IEEE Trans. Biomed. Eng, 65(1):104-112, 2018.

+
+ +
+
+Code based on the Matlab implementation from authors of [1]_
+
+ +
+
+(https
+
+
Type:
+

//github.com/mnakanishi/TRCA-SSVEP).

+
+
+
+ +

Notes

+
+

New in version 0.4.4.

+
+
+
+fit(X, y)[source]#
+

Extract spatial filters and templates from the given calibration +data.

+
+
Parameters:
+
    +
  • X (ndarray of shape (n_trials, n_channels, n_samples)) – Training data. Trials are grouped by class, divided in n_fbands bands by +the filterbank approach and then used to calculate weight vectors and +templates for each class and band.

  • +
  • y (ndarray of shape (n_trials,)) – Label vector in respect to X.

  • +
+
+
Returns:
+

self – Instance of classifier.

+
+
Return type:
+

CCA object

+
+
+
+ +
+
+predict(X)[source]#
+

Make predictions on unseen data.

+

The new data observation X will be filtered +with weights previously extracted and compared to the templates to assess +similarity with each of them and select a class based on the maximal value.

+
+
Parameters:
+

X (ndarray of shape (n_trials, n_channels, n_samples)) – Testing data. This will be divided in self.n_fbands using the filter- bank approach, +then it will be transformed by the different spatial filters and compared to the +previously fit templates according to the selected method for analysis (ensemble or +not). Finally, correlation scores for all sub-bands of each class will be combined, +resulting on a single correlation score per class, from which the maximal one is +identified as the predicted class of the data.

+
+
Returns:
+

y_pred – Prediction vector in respect to X.

+
+
Return type:
+

ndarray of shape (n_trials,)

+
+
+
+ +
+
+predict_proba(X)[source]#
+

Make predictions on unseen data with the associated probabilities.

+

The new data observation X will be filtered +with weights previously extracted and compared to the templates to assess +similarity with each of them and select a class based on the maximal value.

+
+
Parameters:
+

X (ndarray of shape (n_trials, n_channels, n_samples)) – Testing data. This will be divided in self.n_fbands using the filter-bank approach, +then it will be transformed by the different spatial filters and compared to the +previously fit templates according to the selected method for analysis (ensemble or +not). Finally, correlation scores for all sub-bands of each class will be combined, +resulting on a single correlation score per class, from which the maximal one is +identified as the predicted class of the data.

+
+
Returns:
+

y_pred – Prediction vector in respect to X.

+
+
Return type:
+

ndarray of shape (n_trials,)

+
+
+
+ +
+
+set_score_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') SSVEP_TRCA[source]#
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in score.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.csp.TRCSP.html b/docs/generated/moabb.pipelines.csp.TRCSP.html new file mode 100644 index 00000000..6fe440af --- /dev/null +++ b/docs/generated/moabb.pipelines.csp.TRCSP.html @@ -0,0 +1,582 @@ + + + + + + + + + + + + moabb.pipelines.csp.TRCSP — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.csp.TRCSP#

+
+
+class moabb.pipelines.csp.TRCSP(nfilter=4, metric='euclid', log=True, alpha=1)[source]#
+

Weighted Tikhonov-regularized CSP as described in Lotte and Guan +2011.

+
+
+fit(X, y)[source]#
+

Train spatial filters.

+

Only deals with two class

+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.deep_learning.KerasDeepConvNet.html b/docs/generated/moabb.pipelines.deep_learning.KerasDeepConvNet.html new file mode 100644 index 00000000..580428cb --- /dev/null +++ b/docs/generated/moabb.pipelines.deep_learning.KerasDeepConvNet.html @@ -0,0 +1,719 @@ + + + + + + + + + + + + moabb.pipelines.deep_learning.KerasDeepConvNet — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.deep_learning.KerasDeepConvNet#

+
+
+class moabb.pipelines.deep_learning.KerasDeepConvNet(loss, optimizer='Adam', epochs=1000, batch_size=64, verbose=0, random_state=None, validation_split=0.2, history_plot=False, path=None, **kwargs)[source]#
+

Keras implementation of the Deep Convolutional Network as described in +[1].

+

This implementation is taken from code by the Army Research Laboratory (ARL) +at vlawhern/arl-eegmodels

+

We use the original parameter implemented on the paper.

+

Note that this implementation has not been verified by the original +authors.

+

References

+
+
+[1] +

Schirrmeister, R. T., Springenberg, J. T., Fiederer, L. D. J., Glasstetter, M., Eggensperger, +K., Tangermann, M., … & Ball, T. (2017). Deep learning with convolutional neural networks +for EEG decoding and visualization. Human brain mapping, 38(11), 5391-5420. +https://doi.org/10.1002/hbm.23730

+
+
+

Notes

+
+

New in version 0.5.0.

+
+
+
+set_fit_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasDeepConvNet[source]#
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in fit.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_partial_fit_request(*, classes: Union[bool, None, str] = '$UNCHANGED$', sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasDeepConvNet[source]#
+

Request metadata passed to the partial_fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to partial_fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to partial_fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
    +
  • classes (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for classes parameter in partial_fit.

  • +
  • sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in partial_fit.

  • +
+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_score_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasDeepConvNet[source]#
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in score.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.deep_learning.KerasEEGITNet.html b/docs/generated/moabb.pipelines.deep_learning.KerasEEGITNet.html new file mode 100644 index 00000000..31e6f571 --- /dev/null +++ b/docs/generated/moabb.pipelines.deep_learning.KerasEEGITNet.html @@ -0,0 +1,717 @@ + + + + + + + + + + + + moabb.pipelines.deep_learning.KerasEEGITNet — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.deep_learning.KerasEEGITNet#

+
+
+class moabb.pipelines.deep_learning.KerasEEGITNet(loss, optimizer='Adam', epochs=1000, batch_size=64, verbose=0, random_state=None, validation_split=0.2, history_plot=False, path=None, **kwargs)[source]#
+

Keras implementation of the EEGITNet as described in [1].

+

This implementation is taken from code by +at AbbasSalami/EEG-ITNet

+

We use the original parameter implemented on the paper.

+

Note that this implementation has not been verified by the original +authors.

+

References

+
+
+[1] +

Salami, A., Andreu-Perez, J., & Gillmeister, H. (2022). EEG-ITNet: An explainable inception temporal +convolutional network for motor imagery classification. IEEE Access, 10, 36672-36685. +https://doi.org/10.1109/ACCESS.2022.3161489

+
+
+

Notes

+
+

New in version 0.5.0.

+
+
+
+set_fit_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGITNet[source]#
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in fit.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_partial_fit_request(*, classes: Union[bool, None, str] = '$UNCHANGED$', sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGITNet[source]#
+

Request metadata passed to the partial_fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to partial_fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to partial_fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
    +
  • classes (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for classes parameter in partial_fit.

  • +
  • sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in partial_fit.

  • +
+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_score_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGITNet[source]#
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in score.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.deep_learning.KerasEEGNeX.html b/docs/generated/moabb.pipelines.deep_learning.KerasEEGNeX.html new file mode 100644 index 00000000..4633a6c4 --- /dev/null +++ b/docs/generated/moabb.pipelines.deep_learning.KerasEEGNeX.html @@ -0,0 +1,717 @@ + + + + + + + + + + + + moabb.pipelines.deep_learning.KerasEEGNeX — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.deep_learning.KerasEEGNeX#

+
+
+class moabb.pipelines.deep_learning.KerasEEGNeX(loss, optimizer='Adam', epochs=1000, batch_size=64, verbose=0, random_state=None, validation_split=0.2, history_plot=False, path=None, **kwargs)[source]#
+

Keras implementation of the EEGNex as described in [1].

+

This implementation is taken from code by +at chenxiachan/EEGNeX

+

We use the original parameter implemented on the paper.

+

Note that this implementation has not been verified by the original +authors.

+

References

+
+
+[1] +

Chen, X., Teng, X., Chen, H., Pan, Y., & Geyer, P. (2022). Toward reliable signals decoding for +electroencephalogram: A benchmark study to EEGNeX. arXiv preprint arXiv:2207.12369. +https://doi.org/10.48550/arXiv.2207.12369

+
+
+

Notes

+
+

New in version 0.5.0.

+
+
+
+set_fit_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGNeX[source]#
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in fit.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_partial_fit_request(*, classes: Union[bool, None, str] = '$UNCHANGED$', sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGNeX[source]#
+

Request metadata passed to the partial_fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to partial_fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to partial_fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
    +
  • classes (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for classes parameter in partial_fit.

  • +
  • sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in partial_fit.

  • +
+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_score_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGNeX[source]#
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in score.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.deep_learning.KerasEEGNet_8_2.html b/docs/generated/moabb.pipelines.deep_learning.KerasEEGNet_8_2.html new file mode 100644 index 00000000..8cc03cc6 --- /dev/null +++ b/docs/generated/moabb.pipelines.deep_learning.KerasEEGNet_8_2.html @@ -0,0 +1,718 @@ + + + + + + + + + + + + moabb.pipelines.deep_learning.KerasEEGNet_8_2 — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.deep_learning.KerasEEGNet_8_2#

+
+
+class moabb.pipelines.deep_learning.KerasEEGNet_8_2(loss, optimizer='Adam', epochs=1000, batch_size=64, verbose=0, random_state=None, validation_split=0.2, history_plot=False, path=None, **kwargs)[source]#
+

Keras implementation of the EEGNet as described in [1].

+

This implementation is taken from code by the Army Research Laboratory (ARL) +at vlawhern/arl-eegmodels

+

We use the original parameter implemented on the paper.

+

Note that this implementation has not been verified by the original +authors.

+

References

+
+
+[1] +

Lawhern, V. J., Solon, A. J., Waytowich, N. R., Gordon, S. M., Hung, C. P., & Lance, B. J. (2018). EEGNet: +a compact convolutional neural network for EEG-based brain–computer interfaces. Journal of neural +engineering, 15(5), 056013. +https://doi.org/10.1088/1741-2552/aace8c

+
+
+

Notes

+
+

New in version 0.5.0.

+
+
+
+set_fit_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGNet_8_2[source]#
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in fit.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_partial_fit_request(*, classes: Union[bool, None, str] = '$UNCHANGED$', sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGNet_8_2[source]#
+

Request metadata passed to the partial_fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to partial_fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to partial_fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
    +
  • classes (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for classes parameter in partial_fit.

  • +
  • sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in partial_fit.

  • +
+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_score_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGNet_8_2[source]#
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in score.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.deep_learning.KerasEEGTCNet.html b/docs/generated/moabb.pipelines.deep_learning.KerasEEGTCNet.html new file mode 100644 index 00000000..c8947ccf --- /dev/null +++ b/docs/generated/moabb.pipelines.deep_learning.KerasEEGTCNet.html @@ -0,0 +1,718 @@ + + + + + + + + + + + + moabb.pipelines.deep_learning.KerasEEGTCNet — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.deep_learning.KerasEEGTCNet#

+
+
+class moabb.pipelines.deep_learning.KerasEEGTCNet(loss, optimizer='Adam', epochs=1000, batch_size=64, verbose=0, random_state=None, validation_split=0.2, history_plot=False, path=None, **kwargs)[source]#
+

Keras implementation of the EEGTCNet as described in [1].

+

This implementation is taken from code by +at iis-eth-zurich/eeg-tcnet

+

We use the original parameter implemented on the paper.

+

Note that this implementation has not been verified by the original +authors.

+

References

+
+
+[1] +

Ingolfsson, T. M., Hersche, M., Wang, X., Kobayashi, N., Cavigelli, L., & Benini, L. (2020, October). +EEG-TCNet: An accurate temporal convolutional network for embedded motor-imagery brain–machine interfaces. +In 2020 IEEE International Conference on Systems, Man, and Cybernetics (SMC) (pp. 2958-2965). IEEE. +https://doi.org/10.1109/SMC42975.2020.9283028

+
+
+

Notes

+
+

New in version 0.5.0.

+
+
+
+set_fit_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGTCNet[source]#
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in fit.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_partial_fit_request(*, classes: Union[bool, None, str] = '$UNCHANGED$', sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGTCNet[source]#
+

Request metadata passed to the partial_fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to partial_fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to partial_fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
    +
  • classes (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for classes parameter in partial_fit.

  • +
  • sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in partial_fit.

  • +
+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_score_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasEEGTCNet[source]#
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in score.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.deep_learning.KerasShallowConvNet.html b/docs/generated/moabb.pipelines.deep_learning.KerasShallowConvNet.html new file mode 100644 index 00000000..42a2b85f --- /dev/null +++ b/docs/generated/moabb.pipelines.deep_learning.KerasShallowConvNet.html @@ -0,0 +1,719 @@ + + + + + + + + + + + + moabb.pipelines.deep_learning.KerasShallowConvNet — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.deep_learning.KerasShallowConvNet#

+
+
+class moabb.pipelines.deep_learning.KerasShallowConvNet(loss, optimizer='Adam', epochs=1000, batch_size=64, verbose=0, random_state=None, validation_split=0.2, history_plot=False, path=None, **kwargs)[source]#
+

Keras implementation of the Shallow Convolutional Network as described +in [1].

+

This implementation is taken from code by the Army Research Laboratory (ARL) +at vlawhern/arl-eegmodels

+

We use the original parameter implemented on the paper.

+

Note that this implementation has not been verified by the original +authors.

+

References

+
+
+[1] +

Schirrmeister, R. T., Springenberg, J. T., Fiederer, L. D. J., Glasstetter, M., Eggensperger, +K., Tangermann, M., … & Ball, T. (2017). Deep learning with convolutional neural networks +for EEG decoding and visualization. Human brain mapping, 38(11), 5391-5420. +https://doi.org/10.1002/hbm.23730

+
+
+

Notes

+
+

New in version 0.5.0.

+
+
+
+set_fit_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasShallowConvNet[source]#
+

Request metadata passed to the fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in fit.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_partial_fit_request(*, classes: Union[bool, None, str] = '$UNCHANGED$', sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasShallowConvNet[source]#
+

Request metadata passed to the partial_fit method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to partial_fit if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to partial_fit.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+
    +
  • classes (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for classes parameter in partial_fit.

  • +
  • sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in partial_fit.

  • +
+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+
+set_score_request(*, sample_weight: Union[bool, None, str] = '$UNCHANGED$') KerasShallowConvNet[source]#
+

Request metadata passed to the score method.

+

Note that this method is only relevant if +enable_metadata_routing=True (see sklearn.set_config()). +Please see User Guide on how the routing +mechanism works.

+

The options for each parameter are:

+
    +
  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • +
  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • +
  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • +
  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

  • +
+

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the +existing request. This allows you to change the request for some +parameters and not others.

+
+

New in version 1.3.

+
+
+

Note

+

This method is only relevant if this estimator is used as a +sub-estimator of a meta-estimator, e.g. used inside a +Pipeline. Otherwise it has no effect.

+
+
+
Parameters:
+

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in score.

+
+
Returns:
+

self – The updated object.

+
+
Return type:
+

object

+
+
+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.features.AugmentedDataset.html b/docs/generated/moabb.pipelines.features.AugmentedDataset.html new file mode 100644 index 00000000..61798c0c --- /dev/null +++ b/docs/generated/moabb.pipelines.features.AugmentedDataset.html @@ -0,0 +1,582 @@ + + + + + + + + + + + + moabb.pipelines.features.AugmentedDataset — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.features.AugmentedDataset#

+
+
+class moabb.pipelines.features.AugmentedDataset(order: int = 1, lag: int = 1)[source]#
+

Dataset augmentation methods in a higher dimensional space.

+

This transformation allow to create an embedding version of the current +dataset. The implementation and the application is described in [1].

+

References

+
+
+[1] +

Carrara, I., & Papadopoulo, T. (2023). Classification of BCI-EEG based on augmented covariance matrix. +arXiv preprint arXiv:2302.04508. +https://doi.org/10.48550/arXiv.2302.04508

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.features.ExtendedSSVEPSignal.html b/docs/generated/moabb.pipelines.features.ExtendedSSVEPSignal.html new file mode 100644 index 00000000..14b730d9 --- /dev/null +++ b/docs/generated/moabb.pipelines.features.ExtendedSSVEPSignal.html @@ -0,0 +1,594 @@ + + + + + + + + + + + + moabb.pipelines.features.ExtendedSSVEPSignal — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.features.ExtendedSSVEPSignal#

+
+
+class moabb.pipelines.features.ExtendedSSVEPSignal[source]#
+

Prepare FilterBank SSVEP EEG signal for estimating extended covariances.

+

Riemannian approaches on SSVEP rely on extended covariances +matrices, where the filtered signals are contenated to estimate a +large covariance matrice.

+

FilterBank SSVEP EEG are of shape (n_trials, n_channels, n_times, +n_freqs) and should be convert in (n_trials, n_channels*n_freqs, +n_times) to estimate covariance matrices of (n_channels*n_freqs, +n_channels*n_freqs).

+
+
+fit(X, y)[source]#
+

No need to fit for ExtendedSSVEPSignal.

+
+ +
+
+transform(X)[source]#
+

Transpose and reshape EEG for extended covmat estimation.

+
+ +
+ +
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.features.FM.html b/docs/generated/moabb.pipelines.features.FM.html new file mode 100644 index 00000000..ead404c3 --- /dev/null +++ b/docs/generated/moabb.pipelines.features.FM.html @@ -0,0 +1,587 @@ + + + + + + + + + + + + moabb.pipelines.features.FM — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.features.FM#

+
+
+class moabb.pipelines.features.FM(freq=128)[source]#
+

Transformer to scale sampling frequency.

+
+
+fit(X, y)[source]#
+

Only for scikit-learn compatibility.

+
+ +
+
+transform(X)[source]#
+

transform.

+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.features.LogVariance.html b/docs/generated/moabb.pipelines.features.LogVariance.html new file mode 100644 index 00000000..068d312b --- /dev/null +++ b/docs/generated/moabb.pipelines.features.LogVariance.html @@ -0,0 +1,587 @@ + + + + + + + + + + + + moabb.pipelines.features.LogVariance — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.features.LogVariance#

+
+
+class moabb.pipelines.features.LogVariance[source]#
+

LogVariance transformer.

+
+
+fit(X, y)[source]#
+

fit.

+
+ +
+
+transform(X)[source]#
+

transform.

+
+ +
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.features.StandardScaler_Epoch.html b/docs/generated/moabb.pipelines.features.StandardScaler_Epoch.html new file mode 100644 index 00000000..38166482 --- /dev/null +++ b/docs/generated/moabb.pipelines.features.StandardScaler_Epoch.html @@ -0,0 +1,578 @@ + + + + + + + + + + + + moabb.pipelines.features.StandardScaler_Epoch — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.features.StandardScaler_Epoch#

+
+
+class moabb.pipelines.features.StandardScaler_Epoch[source]#
+

Function to standardize the X raw data for the DeepLearning Method.

+
+ +
+

Examples using moabb.pipelines.features.StandardScaler_Epoch#

+
Load Model (Scikit, Pytorch, Keras) with MOABB +

Load Model (Scikit, Pytorch, Keras) with MOABB

+
Load Model (Scikit, Pytorch, Keras) with MOABB
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.utils.FilterBank.html b/docs/generated/moabb.pipelines.utils.FilterBank.html new file mode 100644 index 00000000..bdf5be09 --- /dev/null +++ b/docs/generated/moabb.pipelines.utils.FilterBank.html @@ -0,0 +1,587 @@ + + + + + + + + + + + + moabb.pipelines.utils.FilterBank — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.utils.FilterBank#

+
+
+moabb.pipelines.utils.FilterBank(estimator, flatten=True)[source]#
+

Apply a given identical pipeline over a bank of filter.

+

The pipeline provided with the constrictor will be appield on the 4th +axis of the input data. This pipeline should be used with a FilterBank +paradigm.

+

This can be used to build a filterbank CSP, for example:

+
pipeline = make_pipeline(FilterBank(estimator=CSP()), LDA())
+
+
+
+
Parameters:
+
    +
  • estimator (sklean Estimator) – the sklearn pipeline to apply on each band of the filter bank.

  • +
  • flatten (bool (True)) – If True, output of each band are concatenated together on the feature +axis. if False, output are stacked.

  • +
+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.utils.create_pipeline_from_config.html b/docs/generated/moabb.pipelines.utils.create_pipeline_from_config.html new file mode 100644 index 00000000..36b6b175 --- /dev/null +++ b/docs/generated/moabb.pipelines.utils.create_pipeline_from_config.html @@ -0,0 +1,584 @@ + + + + + + + + + + + + moabb.pipelines.utils.create_pipeline_from_config — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.utils.create_pipeline_from_config#

+
+
+moabb.pipelines.utils.create_pipeline_from_config(config)[source]#
+

Create a pipeline from a config file.

+

takes a config dict as input and return the corresponding pipeline.

+

If the pipeline is a Tensorflow pipeline it convert also the optimizer function and the callbacks.

+
+
Parameters:
+

config (Dict.) – Dict containing the config parameters.

+
+
Returns:
+

pipeline – sklearn Pipeline

+
+
Return type:
+

Pipeline

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.utils_deep_model.EEGNet.html b/docs/generated/moabb.pipelines.utils_deep_model.EEGNet.html new file mode 100644 index 00000000..11a4a0c3 --- /dev/null +++ b/docs/generated/moabb.pipelines.utils_deep_model.EEGNet.html @@ -0,0 +1,586 @@ + + + + + + + + + + + + moabb.pipelines.utils_deep_model.EEGNet — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.utils_deep_model.EEGNet#

+
+
+moabb.pipelines.utils_deep_model.EEGNet(data, input_layer, filters_1=8, kernel_size=64, depth=2, dropout=0.5, activation='elu')[source]#
+

EEGNet block implementation as described in [1].

+

This implementation is taken from code by The Integrated Systems Laboratory of ETH Zurich +at iis-eth-zurich/eeg-tcnet

+

We use the original parameter implemented on the paper.

+

Note that this implementation has not been verified by the original +authors.

+

References

+
+
+[1] +

Lawhern, V. J., Solon, A. J., Waytowich, N. R., Gordon, S. M., Hung, C. P., & Lance, B. J. (2018). EEGNet: +a compact convolutional neural network for EEG-based brain–computer interfaces. Journal of neural +engineering, 15(5), 056013. +https://doi.org/10.1088/1741-2552/aace8c

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.utils_deep_model.EEGNet_TC.html b/docs/generated/moabb.pipelines.utils_deep_model.EEGNet_TC.html new file mode 100644 index 00000000..50cf8f55 --- /dev/null +++ b/docs/generated/moabb.pipelines.utils_deep_model.EEGNet_TC.html @@ -0,0 +1,570 @@ + + + + + + + + + + + + moabb.pipelines.utils_deep_model.EEGNet_TC — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.utils_deep_model.EEGNet_TC#

+
+
+moabb.pipelines.utils_deep_model.EEGNet_TC(self, input_layer, F1=8, kernLength=64, D=2, dropout=0.1, activation='elu')[source]#
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.utils_deep_model.TCN_block.html b/docs/generated/moabb.pipelines.utils_deep_model.TCN_block.html new file mode 100644 index 00000000..d04f5de2 --- /dev/null +++ b/docs/generated/moabb.pipelines.utils_deep_model.TCN_block.html @@ -0,0 +1,583 @@ + + + + + + + + + + + + moabb.pipelines.utils_deep_model.TCN_block — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.utils_deep_model.TCN_block#

+
+
+moabb.pipelines.utils_deep_model.TCN_block(input_layer, input_dimension, depth, kernel_size, filters, dropout, activation)[source]#
+

Temporal Convolutional Network (TCN), TCN_block from [1].

+

This implementation is taken from code by The Integrated Systems Laboratory of ETH Zurich +at iis-eth-zurich/eeg-tcnet

+

References

+
+
+[1] +

Ingolfsson, T. M., Hersche, M., Wang, X., Kobayashi, N., Cavigelli, L., & Benini, L. (2020, October). +EEG-TCNet: An accurate temporal convolutional network for embedded motor-imagery brain–machine interfaces. +In 2020 IEEE International Conference on Systems, Man, and Cybernetics (SMC) (pp. 2958-2965). IEEE. +https://doi.org/10.48550/arXiv.2006.00622

+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader.html b/docs/generated/moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader.html new file mode 100644 index 00000000..9d2b3169 --- /dev/null +++ b/docs/generated/moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader.html @@ -0,0 +1,572 @@ + + + + + + + + + + + + moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader#

+
+
+moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader(drop_last_window=False, kw_args=None)[source]#
+

Class to Load the data from MOABB in a format compatible with +braindecode.

+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.pipelines.utils_pytorch.InputShapeSetterEEG.html b/docs/generated/moabb.pipelines.utils_pytorch.InputShapeSetterEEG.html new file mode 100644 index 00000000..e016dc2e --- /dev/null +++ b/docs/generated/moabb.pipelines.utils_pytorch.InputShapeSetterEEG.html @@ -0,0 +1,591 @@ + + + + + + + + + + + + moabb.pipelines.utils_pytorch.InputShapeSetterEEG — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.pipelines.utils_pytorch.InputShapeSetterEEG#

+
+
+moabb.pipelines.utils_pytorch.InputShapeSetterEEG(params_list=None, input_dim_fn=<function get_shape_from_baseconcat>, module_name='module')[source]#
+

Sets the input dimension of the PyTorch module to the input dimension +of the training data. +This can be of use when the shape of X is not known beforehand, +e.g. when using a skorch model within an sklearn pipeline and +grid-searching feature transformers, or using feature selection +methods.InputShapeSetterEEG +Basic usage:

+
+
Parameters:
+
    +
  • params_list (list) – The list of parameters that define the +input dimension in its __init__ method. +Usually the mandatory parameters from the model.

  • +
  • input_dim_fn (callable, None (default=None)) – In case your X value is more complex and deriving the input +dimension is not as easy as X.shape[-1] you can pass a callable +to this parameter which takes X and returns the input dimension.

  • +
  • module_name (str (default='module')) – Only needs change when you are using more than one module in your +skorch model (e.g., in case of GANs).

  • +
+
+
+
+ +
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.set_download_dir.html b/docs/generated/moabb.set_download_dir.html new file mode 100644 index 00000000..1451b730 --- /dev/null +++ b/docs/generated/moabb.set_download_dir.html @@ -0,0 +1,593 @@ + + + + + + + + + + + + moabb.set_download_dir — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.set_download_dir#

+
+
+moabb.set_download_dir(path)[source]#
+

Set the download directory if required to change from default mne path.

+
+
Parameters:
+
    +
  • path (None | str) –

  • +
  • location (The new storage) –

  • +
  • exist (and MNE_DATA config does not) –

  • +
  • the (a warning is raised and) –

  • +
  • created (path is) –

  • +
  • None (If) –

  • +
  • exist

  • +
  • the

  • +
  • directory (storage location is set to the MNE default) –

  • +
+
+
+
+ +
+

Examples using moabb.set_download_dir#

+
Change Download Directory +

Change Download Directory

+
Change Download Directory
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.set_log_level.html b/docs/generated/moabb.set_log_level.html new file mode 100644 index 00000000..2c30c284 --- /dev/null +++ b/docs/generated/moabb.set_log_level.html @@ -0,0 +1,649 @@ + + + + + + + + + + + + moabb.set_log_level — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.set_log_level#

+
+
+moabb.set_log_level(level='INFO')[source]#
+

Set log level.

+

Set the general log level. Use one of the levels supported by python +logging, i.e.: DEBUG, INFO, WARNING, ERROR, CRITICAL

+
+ +
+

Examples using moabb.set_log_level#

+
Benchmarking with MOABB showing the CO2 footprint +

Benchmarking with MOABB showing the CO2 footprint

+
Benchmarking with MOABB showing the CO2 footprint
+
Load Model (Scikit, Pytorch, Keras) with MOABB +

Load Model (Scikit, Pytorch, Keras) with MOABB

+
Load Model (Scikit, Pytorch, Keras) with MOABB
+
Convert a MOABB dataset to BIDS +

Convert a MOABB dataset to BIDS

+
Convert a MOABB dataset to BIDS
+
Examples of how to use MOABB to benchmark pipelines. +

Examples of how to use MOABB to benchmark pipelines.

+
Examples of how to use MOABB to benchmark pipelines.
+
Benchmarking on MOABB with Tensorflow deep net architectures +

Benchmarking on MOABB with Tensorflow deep net architectures

+
Benchmarking on MOABB with Tensorflow deep net architectures
+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures +

Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures

+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures
+
Benchmarking with MOABB with Grid Search +

Benchmarking with MOABB with Grid Search

+
Benchmarking with MOABB with Grid Search
+
Cross-Session Motor Imagery +

Cross-Session Motor Imagery

+
Cross-Session Motor Imagery
+
Cross-Session on Multiple Datasets +

Cross-Session on Multiple Datasets

+
Cross-Session on Multiple Datasets
+
Cross-Subject SSVEP +

Cross-Subject SSVEP

+
Cross-Subject SSVEP
+
Cache on disk intermediate data processing states +

Cache on disk intermediate data processing states

+
Cache on disk intermediate data processing states
+
Fixed interval windows processing +

Fixed interval windows processing

+
Fixed interval windows processing
+
Within Session P300 +

Within Session P300

+
Within Session P300
+
Within Session SSVEP +

Within Session SSVEP

+
Within Session SSVEP
+
FilterBank CSP versus CSP +

FilterBank CSP versus CSP

+
FilterBank CSP versus CSP
+
MNE Epochs-based pipelines +

MNE Epochs-based pipelines

+
MNE Epochs-based pipelines
+
Statistical Analysis +

Statistical Analysis

+
Statistical Analysis
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Within Session Motor Imagery with Learning Curve +

Within Session Motor Imagery with Learning Curve

+
Within Session Motor Imagery with Learning Curve
+
Within Session P300 with Learning Curve +

Within Session P300 with Learning Curve

+
Within Session P300 with Learning Curve
+
Tutorial 0: Getting Started +

Tutorial 0: Getting Started

+
Tutorial 0: Getting Started
+
Tutorial 1: Simple Motor Imagery +

Tutorial 1: Simple Motor Imagery

+
Tutorial 1: Simple Motor Imagery
+
Tutorial 2: Using multiple datasets +

Tutorial 2: Using multiple datasets

+
Tutorial 2: Using multiple datasets
+
Tutorial 3: Benchmarking multiple pipelines +

Tutorial 3: Benchmarking multiple pipelines

+
Tutorial 3: Benchmarking multiple pipelines
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/generated/moabb.setup_seed.html b/docs/generated/moabb.setup_seed.html new file mode 100644 index 00000000..d74c8e77 --- /dev/null +++ b/docs/generated/moabb.setup_seed.html @@ -0,0 +1,595 @@ + + + + + + + + + + + + moabb.setup_seed — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

moabb.setup_seed#

+
+
+moabb.setup_seed(seed: int) None[source]#
+

Set the seed for random, numpy, TensorFlow and PyTorch.

+
+
Parameters:
+

seed (int) – The random seed to use.

+
+
Return type:
+

None

+
+
+
+ +
+

Examples using moabb.setup_seed#

+
Load Model (Scikit, Pytorch, Keras) with MOABB +

Load Model (Scikit, Pytorch, Keras) with MOABB

+
Load Model (Scikit, Pytorch, Keras) with MOABB
+
Benchmarking on MOABB with Tensorflow deep net architectures +

Benchmarking on MOABB with Tensorflow deep net architectures

+
Benchmarking on MOABB with Tensorflow deep net architectures
+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures +

Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures

+
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures
+
Cross-session motor imagery with deep learning EEGNet v4 model +

Cross-session motor imagery with deep learning EEGNet v4 model

+
Cross-session motor imagery with deep learning EEGNet v4 model
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/genindex.html b/docs/genindex.html new file mode 100644 index 00000000..ca65f650 --- /dev/null +++ b/docs/genindex.html @@ -0,0 +1,1271 @@ + + + + + + + + + + + Index — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+ + + + + +
+ + +

Index

+ +
+ _ + | A + | B + | C + | D + | E + | F + | G + | H + | I + | K + | L + | M + | N + | O + | P + | R + | S + | T + | U + | W + | Z + +
+

_

+ + +
+ +

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + +
+ +

K

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + +
+ +

W

+ + + +
+ +

Z

+ + +
+ + + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..05169633 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,745 @@ + + + + + + + + + + + + Mother of all BCI Benchmarks — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+ + + + + +
+ +
+

Mother of all BCI Benchmarks

#

+

+ + Build a comprehensive benchmark of popular Brain-Computer Interface (BCI) algorithms applied on an extensive list of freely available EEG datasets. +

+

Disclaimer#

+

This is an open science project that may evolve depending on the need of the +community.

+DOI +Build Status +Code style: black +codecov +PyPI +Downloads +
+
+

Welcome!#

+

Thank you for visiting the Mother of all BCI Benchmark documentation and associated +GitHub repository

+

This document is a hub to give you some information about the project. Jump straight to +one of the sections below, or just scroll down to find out more.

+
+

The problem#

+

Brain-Computer Interfaces +allow to interact with a computer using brain signals. In this project, we focus mostly on +electroencephalographic signals +(EEG), that is a very active +research domain, with worldwide scientific contributions. Still:

+
    +
  • Reproducible Research in BCI has a long way to go.

  • +
  • While many BCI datasets are made freely available, researchers do not publish code, and +reproducing results required to benchmark new algorithms turns out to be trickier than +it should be.

  • +
  • Performances can be significantly impacted by parameters of the preprocessing steps, +toolboxes used and implementation “tricks” that are almost never reported in the +literature.

  • +
+

As a result, there is no comprehensive benchmark of BCI algorithms, and newcomers are +spending a tremendous amount of time browsing literature to find out what algorithm works +best and on which dataset.

+
+
+

The solution#

+

The Mother of all BCI Benchmarks allows to:

+
    +
  • Build a comprehensive benchmark of popular BCI algorithms applied on an extensive list +of freely available EEG datasets.

  • +
  • The code is available on GitHub, serving as a reference point for the future algorithmic +developments.

  • +
  • Algorithms can be ranked and promoted on a website, providing a clear picture of the +different solutions available in the field.

  • +
+

This project will be successful when we read in an abstract “ … the proposed method +obtained a score of 89% on the MOABB (Mother of All BCI Benchmarks), outperforming the +state of the art by 5% …”.

+
+
+

Use MOABB#

+

First, you could take a look at our tutorials that cover +the most important concepts and use cases. Also, we have a gallery of +examples available.

+
+
+
+

Core Team#

+

This project is under the umbrella of NeuroTechX, the international +community for NeuroTech enthusiasts.

+

The project is currently maintained by:

+ + + + + + + + + + + + + + + + + + + +
Sylvain ChevallierBruno AristimunhaIgor CarraraPierre GuetschelSara Sedlar
Sylvain ChevallierBruno AristimunhaIgor CarraraPierre GuetschelSara Sedlar

The Mother of all BCI Benchmarks was founded by Alexander Barachant and Vinay Jayaram, who +are experts in the field of Brain-Computer Interfaces (BCI). At moment, both works as +Research Scientist

+ + + + + + + + + + + + +
Alexander BarachantVinay Jayaram
Alexander BarachantVinay Jayaram
+
+

Contributors#

+

The MOABB is a community project, and we are always thankful for all the contributors!

+

Special acknowledge for the extra MOABB contributors:

+ + + + + + + + + + +
Pedro Rodrigues
 Pedro L. C. Rodrigues
+

What do we need?#

+

You! In whatever way you can help.

+

We need expertise in programming, user experience, software sustainability, documentation +and technical writing and project management.

+

We’d love your feedback along the way.

+

Our primary goal is to build a comprehensive benchmark of popular BCI algorithms applied +on an extensive list of freely available EEG datasets, and we’re excited to support the +professional development of any and all of our contributors. If you’re looking to learn to +code, try out working collaboratively, or translate your skills to the digital domain, +we’re here to help.

+
+
+ +
+

Contact us#

+

If you want to report a problem or suggest an enhancement, we’d love for you to +open an issue at this GitHub repository +because then we can get right on it.

+

For a less formal discussion or exchanging ideas, you can also reach us on the Gitter +channel or join our weekly office hours! This an open video meeting +happening on a regular basis, please ask +the link on the gitter channel. We are also on NeuroTechX Slack channel +#moabb.

+
+
+
+

Citing MOABB and related publications#

+

If you use MOABB in your experiments, please cite this library when +publishing a paper to increase the visibility of open science initiatives:

+
    +
  • Aristimunha, B., Carrara, I., Guetschel, P., Sedlar, S., Rodrigues, P., Sosulski, J., Narayanan, D., Bjareholt, E., Quentin, B., Schirrmeister, R. T.,Kalunga, E., Darmet, L., Gregoire, C., Abdul Hussain, A., Gatti, R., Goncharenko, V., Thielen, J., Moreau, T., Roy, Y., Jayaram, V., Barachant,A., & Chevallier, S. Mother of all BCI Benchmarks (MOABB), 2023. DOI: 10.5281/zenodo.10034223

  • +
+

and here is the Bibtex version:

+
@software{Aristimunha_Mother_of_all_2023,
+  author = {Aristimunha, Bruno and Carrara, Igor and Guetschel, Pierre and Sedlar, Sara and Rodrigues, Pedro and Sosulski, Jan and Narayanan, Divyesh and Bjareholt, Erik and Quentin, Barthelemy and Schirrmeister, Robin Tibor and Kalunga, Emmanuel and Darmet, Ludovic and Gregoire, Cattan and Abdul Hussain, Ali and Gatti, Ramiro and Goncharenko, Vladislav and Thielen, Jordy and Moreau, Thomas and Roy, Yannick and Jayaram, Vinay and Barachant, Alexandre and Chevallier, Sylvain},
+  doi = {10.5281/zenodo.10034223},
+  title = {{Mother of all BCI Benchmarks}},
+  url = {https://github.com/NeuroTechX/moabb},
+  version = {1.0.0},
+  year = {2023}
+}
+
+
+

If you want to cite the scientific contributions of MOABB, you could use the following paper:

+ +

Here is the BibTeX entry for the above paper:

+
@article{moabb2018,
+  title={MOABB: trustworthy algorithm benchmarking for BCIs},
+  author={Jayaram, Vinay and Barachant, Alexandre},
+  journal={Journal of neural engineering},
+  volume={15},
+  number={6},
+  pages={066011},
+  year={2018},
+  publisher={IOP Publishing}
+}
+
+
+

If you publish a paper using MOABB, please contact us on +gitter +or open an issue, and we will add your paper to the dedicated wiki +page.

+
+
+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/install/install.html b/docs/install/install.html new file mode 100644 index 00000000..c9972a3b --- /dev/null +++ b/docs/install/install.html @@ -0,0 +1,614 @@ + + + + + + + + + + + + Installation — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Installation#

+

MOABB is written in Python 3, specifically for version 3.8 or above.

+

The package is distributed via Python package index (PyPI), and you can access the +source code via Github repository. The pre-built Docker images using the core +library and all optional dependencies are available on DockerHub.

+

There are different ways to install MOABB:

+
+
+
+
+
+

Install via pip

+

For Beginners

+
+
+MOABB Installer with pip +

New to Python? Use our standalone installers that include +everything to get you started!

+
+ +
+
+
+
+
+

Building from src and the dev env

+

For Advanced Users

+
+
+Terminal Window +

Already familiar with Python? +Follow our setup instructions for building from Github and start to contribute!

+
+ +
+
+
+
+
+

Using our docker environment

+

For Advanced Users

+
+
+Terminal Docker +

Already familiar with Docker? +Follow our setup instructions for using your docker image!

+
+ +
+
+
+
+
+
+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/install/install_pip.html b/docs/install/install_pip.html new file mode 100644 index 00000000..a7f54b3e --- /dev/null +++ b/docs/install/install_pip.html @@ -0,0 +1,585 @@ + + + + + + + + + + + + Installing from PyPI — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Installing from PyPI#

+

MOABB can be installed via pip from PyPI.

+
+

Warning

+

MOABB is only compatible with Python 3.8, 3.9, 3.10 and 3.11.

+
+
+

Note

+

We recommend the most updated version of pip to install from PyPI.

+
+

Below are the installation commands for the most common use cases.

+
pip install bash
+
+
+

MOABB can also be installed with sets of optional dependencies to enable the deep learning modules, the tracker of the carbon emission module or the documentation environment.

+

For example, to install all the optional dependencies.

+
pip install moabb[deepleaning, carbonemission, docs]
+
+
+

If you install the deep learning submodule using the pip, the installation commands above usually install a CPU variant of PyTorch or Tensorflow.

+

To use the potential of the deep learning modules (TensorFlow or PyTorch) with GPU, we recommend the following sequence before installing the moabb with dependencies:

+
    +
  1. Install the latest NVIDIA driver.

  2. +
  3. Check PyTorch Official Guide or TensorFlow Official Guide, for the recommended CUDA versions. For the Pip package, the user must download the CUDA manually, install it on the system, and ensure CUDA_PATH is appropriately set and working!

  4. +
  5. Continue to follow the guide and install PyTorch or TensorFlow.

  6. +
  7. Install moabb using one of the ways with the dependency parameter `[deeplearning].

  8. +
+

See Troubleshooting section if you have a problem.

+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/install/install_source.html b/docs/install/install_source.html new file mode 100644 index 00000000..aad30824 --- /dev/null +++ b/docs/install/install_source.html @@ -0,0 +1,663 @@ + + + + + + + + + + + + Installing from sources — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Installing from sources#

+

If you want to test features under development or contribute to the library, or if you want to test the new tools that have been tested in moabb and not released yet, this is the right tutorial for you!

+
+

Note

+

If you are only trying to install MOABB, we recommend using the pip installation Installation for details on that.

+
+
+

Clone the repository from GitHub#

+

The first thing you should do is clone the MOABB repository to your computer and enter inside the repository.

+
git clone https://github.com/neurotechx/moabb && cd moabb
+
+
+

You should now be in the root directory of the MOABB repository.

+
+
+

Installing Moabb from the source#

+

If you want to only install Moabb from source once and not do any development +work, then the recommended way to build and install is to use pip:

+

For the latest development version, directly from GitHub:

+
pip install https://github.com/NeuroTechX/moabb/archive/refs/heads/develop.zip
+
+
+

If you have a local clone of the MOABB git repository:

+
pip install .
+
+
+

You can also install MOABB in editable mode (i.e. changes to the source code).

+
+
+

Building MOABB from source with the development environment#

+

If you want to build from source to work on MOABB itself, then follow these steps:

+
    +
  1. Install poetry by running the following command (only needs to be done once per machine):

  2. +
+
curl -sSL https://install.python-poetry.org | python3 -
+
+
+

You could also check checkout poetry installation instruction or +use conda forge version

+

We need the most updated version of the poetry to ensure the compatibility with optional dependency.

+
+

Note

+

If you have any group-related errors at the end of this section, you may not run the proper version of poetry.

+
+
    +
  1. (Optional) We recommend disabling automatic environment creation:

  2. +
+
poetry config virtualenvs.create false
+
+
+
+

Note

+

This step is optional. Skip if you are not sure.

+
+
    +
  1. If you want to install without any optional dependency

  2. +
+

You will need to run this command in the project directory:

+
poetry install
+
+
+
    +
  1. If you want to install with an optional dependency

  2. +
+

You will need to run this command in the project directory:

+
poetry install --extras "deeplearning carbonemission docs"
+
+
+

For a full list of dependencies, see the pyproject.toml file.

+

To contribute with a library you must install pre-commit, follow this tutorial Installation Pre-Commit. To more details to become a contributors, see +contributors’ guidelines. +for a detailed explanation.

+
+
+
+

Testing if your installation is working#

+

To verify that MOABB is installed and running correctly, run the following command:

+
python -m unittest moabb.tests
+
+
+

For more information, please see the contributors’ guidelines.

+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/install/using_docker.html b/docs/install/using_docker.html new file mode 100644 index 00000000..987a7489 --- /dev/null +++ b/docs/install/using_docker.html @@ -0,0 +1,621 @@ + + + + + + + + + + + + Moabb and docker — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Moabb and docker#

+
+

If you want to use the docker image pre-build#

+

Moabb has a default image to run the benchmark. You have two options to +download this image: build from scratch or pull from the docker hub. +We recommend pulling from the docker hub.

+

If this were your first time using docker, you would need to install +the docker and login on docker hub. We recommend the +official +docker documentation for this step, it is essential to follow the +instructions.

+

After installing docker, you can pull the image from the docker hub:

+
docker pull baristimunha/moabb
+# rename the tag to moabb
+docker tag baristimunha/moabb moabb
+
+
+

If you want to build the image from scratch, you can use the following +command at the root. You may have to login with the API key in the NGC +Catalog to run this command.

+
bash docker/create_docker.sh
+
+
+

With the image downloaded or rebuilt from scratch, you will have an +image called moabb. To run the default benchmark, still at the root +of the project, and you can use the following command:

+
mkdir dataset
+mkdir results
+mkdir output
+bash docker/run_docker.sh PATH_TO_ROOT_FOLDER
+
+
+

An example of the command is:

+
cd /home/user/project/moabb
+mkdir dataset
+mkdir results
+mkdir output
+bash docker/run_docker.sh /home/user/project/moabb
+
+
+

Note: It is important to use an absolute path for the root folder to +run, but you can modify the run_docker.sh script to save in another path +beyond the root of the project. By default, the script will save the +results in the project’s root in the folder results, the datasets in +the folder dataset and the output in the folder output.

+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/main_concepts.html b/docs/main_concepts.html new file mode 100644 index 00000000..cdd5222e --- /dev/null +++ b/docs/main_concepts.html @@ -0,0 +1,608 @@ + + + + + + + + + + + + Architecture and Main Concepts — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Architecture and Main Concepts#

+architecture +

There are 4 main concepts in the MOABB: the datasets, the paradigm, the evaluation, and +the pipelines. In addition, we offer statistical and visualization utilities to simplify +the workflow.

+
+

Datasets#

+

A dataset handles and abstracts low-level access to the data. The dataset will read data +stored locally, in the format in which they have been downloaded, and will convert them +into an MNE raw object. There are options to pool all the different recording sessions per +subject or to evaluate them separately.

+
+
+

Paradigm#

+

A paradigm defines how the raw data will be converted to trials ready to be processed by a +decoding algorithm. This is a function of the paradigm used, i.e. in motor imagery one can +have two-class, multi-class, or continuous paradigms; similarly, different preprocessing +is necessary for ERP vs ERD paradigms.

+
+
+

Evaluations#

+

An evaluation defines how we go from trials per subject and session to a generalization +statistic (AUC score, f-score, accuracy, etc) – it can be either within-recording-session +accuracy, across-session within-subject accuracy, across-subject accuracy, or other +transfer learning settings.

+
+
+

Pipelines#

+

Pipeline defines all steps required by an algorithm to obtain predictions. Pipelines are +typically a chain of sklearn compatible transformers and end with a sklearn compatible +estimator. See +Pipelines +for more info.

+
+
+

Statistics and visualization#

+

Once an evaluation has been run, the raw results are returned as a DataFrame. This can be +further processed via the following commands to generate some basic visualization and +statistical comparisons:

+
from moabb.analysis import analyze
+
+results = evaluation.process(pipeline_dict)
+analyze(results)
+
+
+
+
+ + +
+ + + + + +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/objects.inv b/docs/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..2dcd0b37e659324b9be9f0d0f501a80d1a06a092 GIT binary patch literal 9036 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�}gRz?ZBVF3!OSOw-ZV1g>9 z&-HCyF4dQSlZ&HEi8-MZs)jbbeT|giS{W>jI55abE$)(JTyt}V*~q2R_*1Vk<3)^2 zSuW8i$wjW#t4Lrj(_Xtc+{L-LR8MYA#&fmst4!t~<-+{u8tL4}*|R>l@u^0DnvCgc z?Yh+Gpim(B(>0Mj<<2Rtn{Ef;R1gk_;DI`_P)5nq)sh97)@9P_+R~bG2}UW|L8=Ft zyD<@5rThj)({sBT6i!H_4huHPa4|O7=z*annIr&f98=d^xK<5$0AXIJd@irrl46~8i) z`n7b|2m#Y1shc*2+No==iir?LGPqF+{jj3DW;s%=Y?rvn8FDseF#YQCqlbP-l7vqL zNq5w?up}=T)dd~`b)CKAJGH$-+J2drUYBRxf6Y2LN~(P6q?_1O`(C7?n_+#I+dT-Q zbDAYgQG71S;~p9c7)KdkGec;9Z~~`7Ve!@|!mtB_uF;p-2mDRpj0ua-e1JRD*i?4q?+H|^*NgaR&TA_x7UE-*+nxH zMj1#~cjitF(!CnL8m@J>VgA~FsBD#EHbJ~@SbzJ;hD&LwAF>HTl_S8Sbe+oIY5fNS zwk|;Twf)a(^w5s$+GYZ{r`}~U(+I7HmX~QSG*&$lEN0K?<6Oq79nK(j@AYu@)D?kX z@w8hc`ghzv(5*yG+eqM;hWmqd4&cI8ZXqxZ{RizBz=f{dI$#|758En$3tqivz&!fz zxjO(Ev1FToKGyHCnl6b&v#hSye*1NFiBj=`Iz-@)UZ|D^gjuoH2m0@|fGP>vWF_?` zp}*J~sd=F7I|4v_lUEXDDhEr7dLb{jTqqGJUpEAceUT+XwOr9!Az1GZSQb=AgIgbz z1b4fILW$Vx6+^73mskgci5)H0poLFf(}T%OG9z^_uv7=rJ6f}Y3cuB=oKmFG9sh1i zZ7S)SH8- + + + + + + + + + Documentation overview — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Documentation overview#

+
+

Note

+

If you haven’t already installed MOABB, please take a look +at our installation guides. Please also kindly find some +resources for learn_python +from MNE if you need to, and the basic module from +NeuroMatch Academy.

+
+

The documentation for MOABB is divided into three main sections:

+
    +
  1. The Getting Started provide a sequential tutorial to start to +use MOABB. They are designed to be read in order, and provide detailed +explanations, sample code, and expected output for the most common MOABB +analysis tasks. The emphasis is on thorough explanations that get new users +up to speed quickly, at the expense of covering only a limited number of +topics.

  2. +
  3. MOABB comes with working code samples that exhibit various modules and techniques. +The examples are categorized into the four categories: +Simple, +Advanced, +External, +and Evaluation. +While these examples may not provide the same level of descriptive explanations as +tutorials, they are a beneficial resource for discovering novel ideas for analysis +or plotting. Moreover, they illustrate how to use MOABB to implement specific module.

  4. +
  5. The API reference that provides documentation for +the classes, functions and methods in the MOABB codebase. This is the +same information that is rendered when running +help(moabb.<function_name>) in an interactive Python session, or +when typing moabb.<function_name>? in an IPython session or Jupyter +notebook.

  6. +
+

The rest of the MOABB documentation pages are shown in the navigation menu, +including the list of example datasets, information about +the MOABB license, +how to contribute to MOABB, +how to cite MOABB, and explanations of the +external library dependencies that MOABB uses, including Deep Learning, Code Carbon, +Docs and others.

+
+
+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/paper_results.html b/docs/paper_results.html new file mode 100644 index 00000000..bd35aadd --- /dev/null +++ b/docs/paper_results.html @@ -0,0 +1,743 @@ + + + + + + + + + + + + The largest EEG-based Benchmark for Open Science — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ + + + + +
+

The largest EEG-based Benchmark for Open Science#

+

We report the results of the benchmark study performed in: +The largest EEG-based BCI reproducibility study for open science: the MOABB benchmark

+

This study conducts an extensive Brain-computer interfaces (BCI) reproducibility analysis on open electroencephalography datasets, +aiming to assess existing solutions and establish open and reproducible benchmarks for effective comparison within the field. Please note that the results are obtained using Within-Session evaluation. +The results are reported regarding mean accuracy and standard deviation across all folds for all sessions and subjects.

+

If you use the same evaluation procedure, you should expect similar results if you use the same pipelines and datasets, with some minor variations due to the randomness of the cross-validation procedure.

+

You can copy and use the table in your work, but please **cite the paper** if you do so.

+
+
+

Motor Imagery#

+

Motor Imagery is a BCI paradigm where the subject imagines performing a movement. +Each imagery task is associated with a different class, and each task has its difficulty level related to how the brain generates the signal.

+

Here, we present three different scenarios for Motor Imagery classification:

+
    +
  1. Left vs Right Hand: We use only the classes Left Hand and Right Hand.

  2. +
  3. Right Hand vs Feet: We use only Right Hand and Feet classes.

  4. +
  5. All classes: We use all the classes in the dataset, when there are more than classes that are not Left Hand and Right Hand.

  6. +
+

All the results here are for within-session evaluation, a 5-fold cross-validation, over the subject’s session.

+
+
+

Motor Imagery - Left vs Right Hand#

+

Left vs Right Hand: We use only the classes Left Hand and Right Hand.

+ + + + + + + + + + + + + + + +

Pipelines

BNCI2014_001

BNCI2014_004

Cho2017

GrosseWentrup2009

Lee2019_MI

PhysionetMI

Schirrmeister2017

Shin2017A

Weibo2014

Zhou2016

+ +
+
+

Motor Imagery - Right Hand vs Feet#

+

Right Hand vs Feet: We use only Right Hand and Feet classes.

+ + + + + + + + + + + + + + +

Pipeline

AlexMI

BNCI2014_001

BNCI2014_002

BNCI2015_001

BNCI2015_004

PhysionetMI

Schirrmeister2017

Weibo2014

Zhou2016

+ + +
+
+

Motor Imagery - All classes#

+

All classes: We use all the classes in the dataset, when there are more than classes that are not Left Hand and Right Hand.

+ + + + + + + + + + + +

Pipelines

AlexMI

BNCI2014_001

PhysionetMI

Schirrmeister2017

Weibo2014

Zhou2016

+
+
+

SSVEP (All classes)#

+

Here, we have the results of the within-session evaluation, a 5-fold cross-validation, over the subject’s session. +We use all the classes available in the dataset.

+ + + + + + + + + + + + + + + + +

Pipeline

Kalunga2016

Lee2019_SSVEP

MAMEM1

MAMEM2

MAMEM3

Nakanishi2015

Wang2016

+ + +
+
+

P300/ERP (All classes)#

+

Here, we have the results of the within-session evaluation, a 5-fold cross-validation, over the subject’s session. +We use all the classes available in the dataset.

+ + + + + + + + + + + + + + + + + + + + +

Pipelines

BNCI2014_008

BNCI2014_009

BNCI2015_003

BI2012

BI2013a

BI2014a

BI2014b

BI2015a

BI2015b

Cattan2019_VR

EPFLP300

Huebner2017

Huebner2018

Lee2019_ERP

Sosulski2019

+ + + +

+
+
+ + +
+ + + + + +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/paradigms.html b/docs/paradigms.html new file mode 100644 index 00000000..09a024cc --- /dev/null +++ b/docs/paradigms.html @@ -0,0 +1,651 @@ + + + + + + + + + + + + Paradigms — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Paradigms#

+

A paradigm defines how the raw data will be converted to trials ready to be +processed by a decoding algorithm.

+

This is a function of the paradigm used, i.e. in motor imagery one can +have two-class, multi-class, or continuous paradigms; similarly, +different preprocessing is necessary for ERP vs ERD paradigms.

+
+

Motor Imagery Paradigms#

+ + + + + + + + + + + + + + + +

MotorImagery([n_classes])

N-class motor imagery.

LeftRightImagery(**kwargs)

Motor Imagery for left hand/right hand classification.

FilterBankLeftRightImagery(**kwargs)

Filter Bank Motor Imagery for left hand/right hand classification.

FilterBankMotorImagery([n_classes])

Filter bank n-class motor imagery.

+
+
+

P300 Paradigms#

+ + + + + + + + + +

SinglePass([fmin, fmax])

Single Bandpass filter P300.

P300(**kwargs)

P300 for Target/NonTarget classification.

+
+
+

SSVEP Paradigms#

+ + + + + + + + + +

SSVEP([fmin, fmax])

Single bandpass filter SSVEP.

FilterBankSSVEP([filters])

Filtered bank n-class SSVEP paradigm.

+
+
+

c-VEP Paradigms#

+ + + + + + + + + +

CVEP([fmin, fmax])

Single bandpass c-VEP paradigm for epoch-level decoding.

FilterBankCVEP([filters])

Filterbank c-VEP paradigm for epoch-level decoding.

+
+
+

Fixed Interval Windows Processings#

+ + + + + + + + + +

FixedIntervalWindowsProcessing([fmin, fmax, ...])

Fixed interval windows processing.

FilterBankFixedIntervalWindowsProcessing([...])

Filter bank fixed interval windows processing.

+
+
+

Base & Utils#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

motor_imagery.BaseMotorImagery([filters, ...])

Base Motor imagery paradigm.

motor_imagery.SinglePass([fmin, fmax])

Single Bandpass filter motor Imagery.

motor_imagery.FilterBank([filters])

Filter Bank MI.

p300.BaseP300([filters, events, tmin, tmax, ...])

Base P300 paradigm.

ssvep.BaseSSVEP([filters, events, ...])

Base SSVEP Paradigm.

BaseFixedIntervalWindowsProcessing([...])

Base class for fixed interval windows processing.

base.BaseParadigm(filters[, events, tmin, ...])

Base class for paradigms.

base.BaseProcessing(filters[, tmin, tmax, ...])

Base Processing.

+
+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/pipelines.html b/docs/pipelines.html new file mode 100644 index 00000000..fd4f1ba4 --- /dev/null +++ b/docs/pipelines.html @@ -0,0 +1,623 @@ + + + + + + + + + + + + Pipelines — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Pipelines#

+

Pipeline defines all steps required by an algorithm to obtain predictions.

+

Pipelines are typically a chain of sklearn compatible transformers and +end with a sklearn compatible estimator.

+
+

Pipelines#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

features.LogVariance()

LogVariance transformer.

features.FM([freq])

Transformer to scale sampling frequency.

features.ExtendedSSVEPSignal()

Prepare FilterBank SSVEP EEG signal for estimating extended covariances.

features.AugmentedDataset([order, lag])

Dataset augmentation methods in a higher dimensional space.

features.StandardScaler_Epoch()

Function to standardize the X raw data for the DeepLearning Method.

csp.TRCSP([nfilter, metric, log, alpha])

Weighted Tikhonov-regularized CSP as described in Lotte and Guan 2011.

classification.SSVEP_CCA(interval, freqs[, ...])

Classifier based on Canonical Correlation Analysis for SSVEP.

classification.SSVEP_TRCA(interval, freqs[, ...])

Classifier based on the Task-Related Component Analysis method [1]_ for SSVEP.

classification.SSVEP_MsetCCA(freqs[, ...])

Classifier based on MsetCCA for SSVEP.

deep_learning.KerasDeepConvNet(loss[, ...])

Keras implementation of the Deep Convolutional Network as described in [R679315cfbef6-1].

deep_learning.KerasEEGITNet(loss[, ...])

Keras implementation of the EEGITNet as described in [Rf5b2ee1af1ae-1].

deep_learning.KerasEEGNet_8_2(loss[, ...])

Keras implementation of the EEGNet as described in [Rd83becb56589-1].

deep_learning.KerasEEGNeX(loss[, optimizer, ...])

Keras implementation of the EEGNex as described in [R643fa75c3283-1].

deep_learning.KerasEEGTCNet(loss[, ...])

Keras implementation of the EEGTCNet as described in [R89b58824c471-1].

deep_learning.KerasShallowConvNet(loss[, ...])

Keras implementation of the Shallow Convolutional Network as described in [R2ccacb732305-1].

+
+
+

Base & Utils#

+ + + + + + + + + + + + + + + + + + + + + + + + +

utils.create_pipeline_from_config(config)

Create a pipeline from a config file.

utils.FilterBank(estimator[, flatten])

Apply a given identical pipeline over a bank of filter.

utils_deep_model.EEGNet(data, input_layer[, ...])

EEGNet block implementation as described in [R820c2366bc63-1].

utils_deep_model.EEGNet_TC(self, input_layer)

utils_deep_model.TCN_block(input_layer, ...)

Temporal Convolutional Network (TCN), TCN_block from [R2eea69aed7b6-1].

utils_pytorch.BraindecodeDatasetLoader([...])

Class to Load the data from MOABB in a format compatible with braindecode.

utils_pytorch.InputShapeSetterEEG([...])

Sets the input dimension of the PyTorch module to the input dimension of the training data.

+
+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/py-modindex.html b/docs/py-modindex.html new file mode 100644 index 00000000..547532c8 --- /dev/null +++ b/docs/py-modindex.html @@ -0,0 +1,542 @@ + + + + + + + + + + + Python Module Index — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+ + + + + + + + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/search.html b/docs/search.html new file mode 100644 index 00000000..6a6c8b02 --- /dev/null +++ b/docs/search.html @@ -0,0 +1,521 @@ + + + + + + + + + + Search - moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+ + +
+

Search

+ + + +
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/searchindex.js b/docs/searchindex.js new file mode 100644 index 00000000..6f461a02 --- /dev/null +++ b/docs/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["CONTRIBUTING", "README", "analysis", "api", "auto_examples/advanced_examples/index", "auto_examples/advanced_examples/plot_filterbank_csp_vs_csp", "auto_examples/advanced_examples/plot_grid_search_withinsession", "auto_examples/advanced_examples/plot_mne_and_scikit_estimators", "auto_examples/advanced_examples/plot_select_electrodes_resample", "auto_examples/advanced_examples/plot_statistical_analysis", "auto_examples/advanced_examples/sg_execution_times", "auto_examples/changing_download_directory", "auto_examples/example_codecarbon", "auto_examples/external/index", "auto_examples/external/plot_learning_curve_p300_external", "auto_examples/external/sg_execution_times", "auto_examples/index", "auto_examples/learning_curve/index", "auto_examples/learning_curve/plot_learning_curve_motor_imagery", "auto_examples/learning_curve/plot_learning_curve_p300", "auto_examples/learning_curve/sg_execution_times", "auto_examples/load_model", "auto_examples/noplot_bids_conversion", "auto_examples/noplot_phmd_ml_spectrum", "auto_examples/noplot_vr_pc_p300_different_epoch_size", "auto_examples/plot_benchmark", "auto_examples/plot_benchmark_DL", "auto_examples/plot_benchmark_braindecode", "auto_examples/plot_benchmark_grid_search", "auto_examples/plot_braindecode", "auto_examples/plot_cross_session_motor_imagery", "auto_examples/plot_cross_session_multiple_datasets", "auto_examples/plot_cross_subject_ssvep", "auto_examples/plot_disk_cache", "auto_examples/plot_explore_paradigm", "auto_examples/plot_fixed_interval_windows", "auto_examples/plot_within_session_p300", "auto_examples/plot_within_session_ssvep", "auto_examples/sg_execution_times", "auto_tutorials/4_adding_a_dataset", "auto_tutorials/index", "auto_tutorials/noplot_tutorial_5_build_a_custom_dataset", "auto_tutorials/plot_Getting_Started", "auto_tutorials/sg_execution_times", "auto_tutorials/tutorial_1_simple_example_motor_imagery", "auto_tutorials/tutorial_2_using_mulitple_datasets", "auto_tutorials/tutorial_3_benchmarking_multiple_pipelines", "cite", "dataset_summary", "datasets", "evaluations", "generated/moabb.analysis.meta_analysis.collapse_session_scores", "generated/moabb.analysis.meta_analysis.combine_effects", "generated/moabb.analysis.meta_analysis.combine_pvalues", "generated/moabb.analysis.meta_analysis.compute_dataset_statistics", "generated/moabb.analysis.meta_analysis.find_significant_differences", "generated/moabb.analysis.plotting.meta_analysis_plot", "generated/moabb.analysis.plotting.paired_plot", "generated/moabb.analysis.plotting.score_plot", "generated/moabb.analysis.plotting.summary_plot", "generated/moabb.benchmark", "generated/moabb.datasets.AlexMI", "generated/moabb.datasets.BI2012", "generated/moabb.datasets.BI2013a", "generated/moabb.datasets.BI2014a", "generated/moabb.datasets.BI2014b", "generated/moabb.datasets.BI2015a", "generated/moabb.datasets.BI2015b", "generated/moabb.datasets.BNCI2014_001", "generated/moabb.datasets.BNCI2014_002", "generated/moabb.datasets.BNCI2014_004", "generated/moabb.datasets.BNCI2014_008", "generated/moabb.datasets.BNCI2014_009", "generated/moabb.datasets.BNCI2015_001", "generated/moabb.datasets.BNCI2015_003", "generated/moabb.datasets.BNCI2015_004", "generated/moabb.datasets.CastillosBurstVEP100", "generated/moabb.datasets.CastillosBurstVEP40", "generated/moabb.datasets.CastillosCVEP100", "generated/moabb.datasets.CastillosCVEP40", "generated/moabb.datasets.Cattan2019_PHMD", "generated/moabb.datasets.Cattan2019_VR", "generated/moabb.datasets.Cho2017", "generated/moabb.datasets.DemonsP300", "generated/moabb.datasets.EPFLP300", "generated/moabb.datasets.GrosseWentrup2009", "generated/moabb.datasets.Huebner2017", "generated/moabb.datasets.Huebner2018", "generated/moabb.datasets.Kalunga2016", "generated/moabb.datasets.Lee2019_ERP", "generated/moabb.datasets.Lee2019_MI", "generated/moabb.datasets.Lee2019_SSVEP", "generated/moabb.datasets.MAMEM1", "generated/moabb.datasets.MAMEM2", "generated/moabb.datasets.MAMEM3", "generated/moabb.datasets.Nakanishi2015", "generated/moabb.datasets.Ofner2017", "generated/moabb.datasets.PhysionetMI", "generated/moabb.datasets.Schirrmeister2017", "generated/moabb.datasets.Shin2017A", "generated/moabb.datasets.Shin2017B", "generated/moabb.datasets.Sosulski2019", "generated/moabb.datasets.Thielen2015", "generated/moabb.datasets.Thielen2021", "generated/moabb.datasets.Wang2016", "generated/moabb.datasets.Weibo2014", "generated/moabb.datasets.Zhou2016", "generated/moabb.datasets.base.BaseDataset", "generated/moabb.datasets.base.CacheConfig", "generated/moabb.datasets.compound_dataset.BI2014a_Il", "generated/moabb.datasets.compound_dataset.BI2014b_Il", "generated/moabb.datasets.compound_dataset.BI2015a_Il", "generated/moabb.datasets.compound_dataset.BI2015b_Il", "generated/moabb.datasets.compound_dataset.BI_Il", "generated/moabb.datasets.compound_dataset.Cattan2019_VR_Il", "generated/moabb.datasets.download.data_dl", "generated/moabb.datasets.download.data_path", "generated/moabb.datasets.download.fs_get_file_hash", "generated/moabb.datasets.download.fs_get_file_id", "generated/moabb.datasets.download.fs_get_file_list", "generated/moabb.datasets.download.fs_get_file_name", "generated/moabb.datasets.download.fs_issue_request", "generated/moabb.datasets.fake.FakeDataset", "generated/moabb.datasets.fake.FakeVirtualRealityDataset", "generated/moabb.datasets.utils.dataset_search", "generated/moabb.datasets.utils.find_intersecting_channels", "generated/moabb.evaluations.CrossSessionEvaluation", "generated/moabb.evaluations.CrossSubjectEvaluation", "generated/moabb.evaluations.WithinSessionEvaluation", "generated/moabb.evaluations.base.BaseEvaluation", "generated/moabb.make_process_pipelines", "generated/moabb.paradigms.BaseFixedIntervalWindowsProcessing", "generated/moabb.paradigms.CVEP", "generated/moabb.paradigms.FilterBankCVEP", "generated/moabb.paradigms.FilterBankFixedIntervalWindowsProcessing", "generated/moabb.paradigms.FilterBankLeftRightImagery", "generated/moabb.paradigms.FilterBankMotorImagery", "generated/moabb.paradigms.FilterBankSSVEP", "generated/moabb.paradigms.FixedIntervalWindowsProcessing", "generated/moabb.paradigms.LeftRightImagery", "generated/moabb.paradigms.MotorImagery", "generated/moabb.paradigms.P300", "generated/moabb.paradigms.SSVEP", "generated/moabb.paradigms.SinglePass", "generated/moabb.paradigms.base.BaseParadigm", "generated/moabb.paradigms.base.BaseProcessing", "generated/moabb.paradigms.motor_imagery.BaseMotorImagery", "generated/moabb.paradigms.motor_imagery.FilterBank", "generated/moabb.paradigms.motor_imagery.SinglePass", "generated/moabb.paradigms.p300.BaseP300", "generated/moabb.paradigms.ssvep.BaseSSVEP", "generated/moabb.pipelines.classification.SSVEP_CCA", "generated/moabb.pipelines.classification.SSVEP_MsetCCA", "generated/moabb.pipelines.classification.SSVEP_TRCA", "generated/moabb.pipelines.csp.TRCSP", "generated/moabb.pipelines.deep_learning.KerasDeepConvNet", "generated/moabb.pipelines.deep_learning.KerasEEGITNet", "generated/moabb.pipelines.deep_learning.KerasEEGNeX", "generated/moabb.pipelines.deep_learning.KerasEEGNet_8_2", "generated/moabb.pipelines.deep_learning.KerasEEGTCNet", "generated/moabb.pipelines.deep_learning.KerasShallowConvNet", "generated/moabb.pipelines.features.AugmentedDataset", "generated/moabb.pipelines.features.ExtendedSSVEPSignal", "generated/moabb.pipelines.features.FM", "generated/moabb.pipelines.features.LogVariance", "generated/moabb.pipelines.features.StandardScaler_Epoch", "generated/moabb.pipelines.utils.FilterBank", "generated/moabb.pipelines.utils.create_pipeline_from_config", "generated/moabb.pipelines.utils_deep_model.EEGNet", "generated/moabb.pipelines.utils_deep_model.EEGNet_TC", "generated/moabb.pipelines.utils_deep_model.TCN_block", "generated/moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader", "generated/moabb.pipelines.utils_pytorch.InputShapeSetterEEG", "generated/moabb.set_download_dir", "generated/moabb.set_log_level", "generated/moabb.setup_seed", "index", "install/install", "install/install_pip", "install/install_source", "install/using_docker", "main_concepts", "overview", "paper_results", "paradigms", "pipelines", "utils", "whats_new"], "filenames": ["CONTRIBUTING.md", "README.md", "analysis.rst", "api.rst", "auto_examples/advanced_examples/index.rst", "auto_examples/advanced_examples/plot_filterbank_csp_vs_csp.rst", "auto_examples/advanced_examples/plot_grid_search_withinsession.rst", "auto_examples/advanced_examples/plot_mne_and_scikit_estimators.rst", "auto_examples/advanced_examples/plot_select_electrodes_resample.rst", "auto_examples/advanced_examples/plot_statistical_analysis.rst", "auto_examples/advanced_examples/sg_execution_times.rst", "auto_examples/changing_download_directory.rst", "auto_examples/example_codecarbon.rst", "auto_examples/external/index.rst", "auto_examples/external/plot_learning_curve_p300_external.rst", "auto_examples/external/sg_execution_times.rst", "auto_examples/index.rst", "auto_examples/learning_curve/index.rst", "auto_examples/learning_curve/plot_learning_curve_motor_imagery.rst", "auto_examples/learning_curve/plot_learning_curve_p300.rst", "auto_examples/learning_curve/sg_execution_times.rst", "auto_examples/load_model.rst", "auto_examples/noplot_bids_conversion.rst", "auto_examples/noplot_phmd_ml_spectrum.rst", "auto_examples/noplot_vr_pc_p300_different_epoch_size.rst", "auto_examples/plot_benchmark.rst", "auto_examples/plot_benchmark_DL.rst", "auto_examples/plot_benchmark_braindecode.rst", "auto_examples/plot_benchmark_grid_search.rst", "auto_examples/plot_braindecode.rst", "auto_examples/plot_cross_session_motor_imagery.rst", "auto_examples/plot_cross_session_multiple_datasets.rst", "auto_examples/plot_cross_subject_ssvep.rst", "auto_examples/plot_disk_cache.rst", "auto_examples/plot_explore_paradigm.rst", "auto_examples/plot_fixed_interval_windows.rst", "auto_examples/plot_within_session_p300.rst", "auto_examples/plot_within_session_ssvep.rst", "auto_examples/sg_execution_times.rst", "auto_tutorials/4_adding_a_dataset.rst", "auto_tutorials/index.rst", "auto_tutorials/noplot_tutorial_5_build_a_custom_dataset.rst", "auto_tutorials/plot_Getting_Started.rst", "auto_tutorials/sg_execution_times.rst", "auto_tutorials/tutorial_1_simple_example_motor_imagery.rst", "auto_tutorials/tutorial_2_using_mulitple_datasets.rst", "auto_tutorials/tutorial_3_benchmarking_multiple_pipelines.rst", "cite.rst", "dataset_summary.rst", "datasets.rst", "evaluations.rst", "generated/moabb.analysis.meta_analysis.collapse_session_scores.rst", "generated/moabb.analysis.meta_analysis.combine_effects.rst", "generated/moabb.analysis.meta_analysis.combine_pvalues.rst", "generated/moabb.analysis.meta_analysis.compute_dataset_statistics.rst", "generated/moabb.analysis.meta_analysis.find_significant_differences.rst", "generated/moabb.analysis.plotting.meta_analysis_plot.rst", "generated/moabb.analysis.plotting.paired_plot.rst", "generated/moabb.analysis.plotting.score_plot.rst", "generated/moabb.analysis.plotting.summary_plot.rst", "generated/moabb.benchmark.rst", "generated/moabb.datasets.AlexMI.rst", "generated/moabb.datasets.BI2012.rst", "generated/moabb.datasets.BI2013a.rst", "generated/moabb.datasets.BI2014a.rst", "generated/moabb.datasets.BI2014b.rst", "generated/moabb.datasets.BI2015a.rst", "generated/moabb.datasets.BI2015b.rst", "generated/moabb.datasets.BNCI2014_001.rst", "generated/moabb.datasets.BNCI2014_002.rst", "generated/moabb.datasets.BNCI2014_004.rst", "generated/moabb.datasets.BNCI2014_008.rst", "generated/moabb.datasets.BNCI2014_009.rst", "generated/moabb.datasets.BNCI2015_001.rst", "generated/moabb.datasets.BNCI2015_003.rst", "generated/moabb.datasets.BNCI2015_004.rst", "generated/moabb.datasets.CastillosBurstVEP100.rst", "generated/moabb.datasets.CastillosBurstVEP40.rst", "generated/moabb.datasets.CastillosCVEP100.rst", "generated/moabb.datasets.CastillosCVEP40.rst", "generated/moabb.datasets.Cattan2019_PHMD.rst", "generated/moabb.datasets.Cattan2019_VR.rst", "generated/moabb.datasets.Cho2017.rst", "generated/moabb.datasets.DemonsP300.rst", "generated/moabb.datasets.EPFLP300.rst", "generated/moabb.datasets.GrosseWentrup2009.rst", "generated/moabb.datasets.Huebner2017.rst", "generated/moabb.datasets.Huebner2018.rst", "generated/moabb.datasets.Kalunga2016.rst", "generated/moabb.datasets.Lee2019_ERP.rst", "generated/moabb.datasets.Lee2019_MI.rst", "generated/moabb.datasets.Lee2019_SSVEP.rst", "generated/moabb.datasets.MAMEM1.rst", "generated/moabb.datasets.MAMEM2.rst", "generated/moabb.datasets.MAMEM3.rst", "generated/moabb.datasets.Nakanishi2015.rst", "generated/moabb.datasets.Ofner2017.rst", "generated/moabb.datasets.PhysionetMI.rst", "generated/moabb.datasets.Schirrmeister2017.rst", "generated/moabb.datasets.Shin2017A.rst", "generated/moabb.datasets.Shin2017B.rst", "generated/moabb.datasets.Sosulski2019.rst", "generated/moabb.datasets.Thielen2015.rst", "generated/moabb.datasets.Thielen2021.rst", "generated/moabb.datasets.Wang2016.rst", "generated/moabb.datasets.Weibo2014.rst", "generated/moabb.datasets.Zhou2016.rst", "generated/moabb.datasets.base.BaseDataset.rst", "generated/moabb.datasets.base.CacheConfig.rst", "generated/moabb.datasets.compound_dataset.BI2014a_Il.rst", "generated/moabb.datasets.compound_dataset.BI2014b_Il.rst", "generated/moabb.datasets.compound_dataset.BI2015a_Il.rst", "generated/moabb.datasets.compound_dataset.BI2015b_Il.rst", "generated/moabb.datasets.compound_dataset.BI_Il.rst", "generated/moabb.datasets.compound_dataset.Cattan2019_VR_Il.rst", "generated/moabb.datasets.download.data_dl.rst", "generated/moabb.datasets.download.data_path.rst", "generated/moabb.datasets.download.fs_get_file_hash.rst", "generated/moabb.datasets.download.fs_get_file_id.rst", "generated/moabb.datasets.download.fs_get_file_list.rst", "generated/moabb.datasets.download.fs_get_file_name.rst", "generated/moabb.datasets.download.fs_issue_request.rst", "generated/moabb.datasets.fake.FakeDataset.rst", "generated/moabb.datasets.fake.FakeVirtualRealityDataset.rst", "generated/moabb.datasets.utils.dataset_search.rst", "generated/moabb.datasets.utils.find_intersecting_channels.rst", "generated/moabb.evaluations.CrossSessionEvaluation.rst", "generated/moabb.evaluations.CrossSubjectEvaluation.rst", "generated/moabb.evaluations.WithinSessionEvaluation.rst", "generated/moabb.evaluations.base.BaseEvaluation.rst", "generated/moabb.make_process_pipelines.rst", "generated/moabb.paradigms.BaseFixedIntervalWindowsProcessing.rst", "generated/moabb.paradigms.CVEP.rst", "generated/moabb.paradigms.FilterBankCVEP.rst", "generated/moabb.paradigms.FilterBankFixedIntervalWindowsProcessing.rst", "generated/moabb.paradigms.FilterBankLeftRightImagery.rst", "generated/moabb.paradigms.FilterBankMotorImagery.rst", "generated/moabb.paradigms.FilterBankSSVEP.rst", "generated/moabb.paradigms.FixedIntervalWindowsProcessing.rst", "generated/moabb.paradigms.LeftRightImagery.rst", "generated/moabb.paradigms.MotorImagery.rst", "generated/moabb.paradigms.P300.rst", "generated/moabb.paradigms.SSVEP.rst", "generated/moabb.paradigms.SinglePass.rst", "generated/moabb.paradigms.base.BaseParadigm.rst", "generated/moabb.paradigms.base.BaseProcessing.rst", "generated/moabb.paradigms.motor_imagery.BaseMotorImagery.rst", "generated/moabb.paradigms.motor_imagery.FilterBank.rst", "generated/moabb.paradigms.motor_imagery.SinglePass.rst", "generated/moabb.paradigms.p300.BaseP300.rst", "generated/moabb.paradigms.ssvep.BaseSSVEP.rst", "generated/moabb.pipelines.classification.SSVEP_CCA.rst", "generated/moabb.pipelines.classification.SSVEP_MsetCCA.rst", "generated/moabb.pipelines.classification.SSVEP_TRCA.rst", "generated/moabb.pipelines.csp.TRCSP.rst", "generated/moabb.pipelines.deep_learning.KerasDeepConvNet.rst", "generated/moabb.pipelines.deep_learning.KerasEEGITNet.rst", "generated/moabb.pipelines.deep_learning.KerasEEGNeX.rst", "generated/moabb.pipelines.deep_learning.KerasEEGNet_8_2.rst", "generated/moabb.pipelines.deep_learning.KerasEEGTCNet.rst", "generated/moabb.pipelines.deep_learning.KerasShallowConvNet.rst", "generated/moabb.pipelines.features.AugmentedDataset.rst", "generated/moabb.pipelines.features.ExtendedSSVEPSignal.rst", "generated/moabb.pipelines.features.FM.rst", "generated/moabb.pipelines.features.LogVariance.rst", "generated/moabb.pipelines.features.StandardScaler_Epoch.rst", "generated/moabb.pipelines.utils.FilterBank.rst", "generated/moabb.pipelines.utils.create_pipeline_from_config.rst", "generated/moabb.pipelines.utils_deep_model.EEGNet.rst", "generated/moabb.pipelines.utils_deep_model.EEGNet_TC.rst", "generated/moabb.pipelines.utils_deep_model.TCN_block.rst", "generated/moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader.rst", "generated/moabb.pipelines.utils_pytorch.InputShapeSetterEEG.rst", "generated/moabb.set_download_dir.rst", "generated/moabb.set_log_level.rst", "generated/moabb.setup_seed.rst", "index.rst", "install/install.rst", "install/install_pip.rst", "install/install_source.rst", "install/using_docker.rst", "main_concepts.md", "overview.rst", "paper_results.rst", "paradigms.rst", "pipelines.rst", "utils.rst", "whats_new.rst"], "titles": ["Contributing", "

Mother of all BCI Benchmarks

", "Analysis", "API Reference", "Advanced examples", "FilterBank CSP versus CSP", "GridSearch within a session", "MNE Epochs-based pipelines", "Select Electrodes and Resampling", "Statistical Analysis", "Computation times", "Change Download Directory", "Benchmarking with MOABB showing the CO2 footprint", "External examples", "Within Session P300 with Learning Curve", "Computation times", "Examples", "Evaluation with learning curve", "Within Session Motor Imagery with Learning Curve", "Within Session P300 with Learning Curve", "Computation times", "Load Model (Scikit, Pytorch, Keras) with MOABB", "Convert a MOABB dataset to BIDS", "Spectral analysis of the trials", "Changing epoch size in P300 VR dataset", "Examples of how to use MOABB to benchmark pipelines.", "Benchmarking on MOABB with Tensorflow deep net architectures", "Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures", "Benchmarking with MOABB with Grid Search", "Cross-session motor imagery with deep learning EEGNet v4 model", "Cross-Session Motor Imagery", "Cross-Session on Multiple Datasets", "Cross-Subject SSVEP", "Cache on disk intermediate data processing states", "Explore Paradigm Object", "Fixed interval windows processing", "Within Session P300", "Within Session SSVEP", "Computation times", "Tutorial 4: Creating a dataset class", "Getting Started", "Tutorial 5: Creating a dataset class", "Tutorial 0: Getting Started", "Computation times", "Tutorial 1: Simple Motor Imagery", "Tutorial 2: Using multiple datasets", "Tutorial 3: Benchmarking multiple pipelines", "Citing MOABB and related publications", "Data Summary", "Datasets", "Evaluations", "moabb.analysis.meta_analysis.collapse_session_scores", "moabb.analysis.meta_analysis.combine_effects", "moabb.analysis.meta_analysis.combine_pvalues", "moabb.analysis.meta_analysis.compute_dataset_statistics", "moabb.analysis.meta_analysis.find_significant_differences", "moabb.analysis.plotting.meta_analysis_plot", "moabb.analysis.plotting.paired_plot", "moabb.analysis.plotting.score_plot", "moabb.analysis.plotting.summary_plot", "moabb.benchmark", "moabb.datasets.AlexMI", "moabb.datasets.BI2012", "moabb.datasets.BI2013a", "moabb.datasets.BI2014a", "moabb.datasets.BI2014b", "moabb.datasets.BI2015a", "moabb.datasets.BI2015b", "moabb.datasets.BNCI2014_001", "moabb.datasets.BNCI2014_002", "moabb.datasets.BNCI2014_004", "moabb.datasets.BNCI2014_008", "moabb.datasets.BNCI2014_009", "moabb.datasets.BNCI2015_001", "moabb.datasets.BNCI2015_003", "moabb.datasets.BNCI2015_004", "moabb.datasets.CastillosBurstVEP100", "moabb.datasets.CastillosBurstVEP40", "moabb.datasets.CastillosCVEP100", "moabb.datasets.CastillosCVEP40", "moabb.datasets.Cattan2019_PHMD", "moabb.datasets.Cattan2019_VR", "moabb.datasets.Cho2017", "moabb.datasets.DemonsP300", "moabb.datasets.EPFLP300", "moabb.datasets.GrosseWentrup2009", "moabb.datasets.Huebner2017", "moabb.datasets.Huebner2018", "moabb.datasets.Kalunga2016", "moabb.datasets.Lee2019_ERP", "moabb.datasets.Lee2019_MI", "moabb.datasets.Lee2019_SSVEP", "moabb.datasets.MAMEM1", "moabb.datasets.MAMEM2", "moabb.datasets.MAMEM3", "moabb.datasets.Nakanishi2015", "moabb.datasets.Ofner2017", "moabb.datasets.PhysionetMI", "moabb.datasets.Schirrmeister2017", "moabb.datasets.Shin2017A", "moabb.datasets.Shin2017B", "moabb.datasets.Sosulski2019", "moabb.datasets.Thielen2015", "moabb.datasets.Thielen2021", "moabb.datasets.Wang2016", "moabb.datasets.Weibo2014", "moabb.datasets.Zhou2016", "moabb.datasets.base.BaseDataset", "moabb.datasets.base.CacheConfig", "moabb.datasets.compound_dataset.BI2014a_Il", "moabb.datasets.compound_dataset.BI2014b_Il", "moabb.datasets.compound_dataset.BI2015a_Il", "moabb.datasets.compound_dataset.BI2015b_Il", "moabb.datasets.compound_dataset.BI_Il", "moabb.datasets.compound_dataset.Cattan2019_VR_Il", "moabb.datasets.download.data_dl", "moabb.datasets.download.data_path", "moabb.datasets.download.fs_get_file_hash", "moabb.datasets.download.fs_get_file_id", "moabb.datasets.download.fs_get_file_list", "moabb.datasets.download.fs_get_file_name", "moabb.datasets.download.fs_issue_request", "moabb.datasets.fake.FakeDataset", "moabb.datasets.fake.FakeVirtualRealityDataset", "moabb.datasets.utils.dataset_search", "moabb.datasets.utils.find_intersecting_channels", "moabb.evaluations.CrossSessionEvaluation", "moabb.evaluations.CrossSubjectEvaluation", "moabb.evaluations.WithinSessionEvaluation", "moabb.evaluations.base.BaseEvaluation", "moabb.make_process_pipelines", "moabb.paradigms.BaseFixedIntervalWindowsProcessing", "moabb.paradigms.CVEP", "moabb.paradigms.FilterBankCVEP", "moabb.paradigms.FilterBankFixedIntervalWindowsProcessing", "moabb.paradigms.FilterBankLeftRightImagery", "moabb.paradigms.FilterBankMotorImagery", "moabb.paradigms.FilterBankSSVEP", "moabb.paradigms.FixedIntervalWindowsProcessing", "moabb.paradigms.LeftRightImagery", "moabb.paradigms.MotorImagery", "moabb.paradigms.P300", "moabb.paradigms.SSVEP", "moabb.paradigms.SinglePass", "moabb.paradigms.base.BaseParadigm", "moabb.paradigms.base.BaseProcessing", "moabb.paradigms.motor_imagery.BaseMotorImagery", "moabb.paradigms.motor_imagery.FilterBank", "moabb.paradigms.motor_imagery.SinglePass", "moabb.paradigms.p300.BaseP300", "moabb.paradigms.ssvep.BaseSSVEP", "moabb.pipelines.classification.SSVEP_CCA", "moabb.pipelines.classification.SSVEP_MsetCCA", "moabb.pipelines.classification.SSVEP_TRCA", "moabb.pipelines.csp.TRCSP", "moabb.pipelines.deep_learning.KerasDeepConvNet", "moabb.pipelines.deep_learning.KerasEEGITNet", "moabb.pipelines.deep_learning.KerasEEGNeX", "moabb.pipelines.deep_learning.KerasEEGNet_8_2", "moabb.pipelines.deep_learning.KerasEEGTCNet", "moabb.pipelines.deep_learning.KerasShallowConvNet", "moabb.pipelines.features.AugmentedDataset", "moabb.pipelines.features.ExtendedSSVEPSignal", "moabb.pipelines.features.FM", "moabb.pipelines.features.LogVariance", "moabb.pipelines.features.StandardScaler_Epoch", "moabb.pipelines.utils.FilterBank", "moabb.pipelines.utils.create_pipeline_from_config", "moabb.pipelines.utils_deep_model.EEGNet", "moabb.pipelines.utils_deep_model.EEGNet_TC", "moabb.pipelines.utils_deep_model.TCN_block", "moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader", "moabb.pipelines.utils_pytorch.InputShapeSetterEEG", "moabb.set_download_dir", "moabb.set_log_level", "moabb.setup_seed", "

Mother of all BCI Benchmarks

", "Installation", "Installing from PyPI", "Installing from sources", "Moabb and docker", "Architecture and Main Concepts", "Documentation overview", "The largest EEG-based Benchmark for Open Science", "Paradigms", "Pipelines", "Utils", "What\u2019s new"], "terms": {"ar": [0, 1, 3, 5, 6, 7, 8, 9, 12, 14, 16, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 41, 42, 44, 46, 48, 49, 51, 60, 61, 63, 64, 65, 66, 67, 70, 72, 74, 75, 89, 90, 91, 92, 93, 94, 99, 100, 101, 102, 103, 104, 107, 117, 118, 120, 126, 127, 128, 129, 145, 151, 152, 153, 155, 156, 157, 158, 159, 160, 162, 166, 172, 176, 177, 178, 179, 181, 182, 183, 185, 187], "alwai": [0, 1, 63, 72, 101, 176], "welcom": [0, 48], "matter": [0, 93, 94], "small": [0, 16, 35, 70, 92, 93, 94, 101], "If": [0, 1, 6, 9, 11, 12, 16, 17, 25, 26, 27, 28, 29, 33, 34, 39, 41, 42, 47, 48, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 93, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 119, 122, 124, 126, 127, 128, 129, 131, 132, 133, 134, 136, 137, 138, 140, 142, 143, 144, 145, 146, 148, 149, 150, 153, 166, 167, 173, 176, 178, 179, 182, 183], "you": [0, 1, 7, 9, 11, 12, 13, 14, 16, 17, 18, 19, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 47, 48, 60, 99, 100, 101, 151, 152, 153, 155, 156, 157, 158, 159, 160, 172, 176, 177, 178, 179, 182, 183, 187], "think": 0, "help": [0, 1, 48, 89, 176, 182], "ani": [0, 1, 9, 11, 22, 33, 48, 63, 80, 81, 88, 96, 99, 100, 105, 107, 131, 136, 140, 145, 146, 149, 176, 179], "area": [0, 89, 99, 100], "moabb": [0, 3, 5, 6, 7, 8, 11, 14, 16, 18, 19, 23, 24, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 41, 42, 44, 45, 46, 48, 49, 177, 178, 181, 182, 183, 187], "we": [0, 3, 5, 6, 7, 9, 12, 14, 18, 19, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 47, 48, 50, 69, 71, 73, 75, 80, 81, 82, 83, 86, 92, 96, 98, 103, 107, 132, 133, 155, 156, 157, 158, 159, 160, 168, 178, 179, 180, 181, 183, 187], "bet": 0, "mani": [0, 1, 12, 25, 26, 27, 28, 32, 42, 44, 48, 74, 176, 187], "haven": [0, 182], "t": [0, 1, 7, 8, 9, 11, 26, 27, 47, 48, 61, 62, 63, 64, 65, 66, 67, 68, 73, 75, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 108, 115, 116, 122, 124, 153, 155, 159, 160, 161, 170, 176, 182], "yet": [0, 26, 27, 29, 33, 39, 48, 179], "thought": [0, 99, 100], "here": [0, 1, 5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 47, 48, 102, 103, 176, 183], "re": [0, 1, 12, 25, 26, 27, 28, 29, 33, 85, 102, 126, 127, 128, 129, 176], "sure": [0, 5, 14, 19, 179], "pleas": [0, 1, 22, 25, 27, 47, 63, 145, 146, 149, 151, 152, 153, 155, 156, 157, 158, 159, 160, 176, 179, 182, 183], "check": [0, 33, 44, 48, 82, 92, 150, 178, 179, 187], "out": [0, 1, 30, 31, 32, 62, 63, 68, 71, 72, 75, 85, 96, 176, 187], "our": [0, 1, 22, 34, 39, 41, 44, 48, 84, 92, 98, 102, 176, 177, 182], "roadmap": 0, "note": [0, 9, 24, 28, 34, 42, 44, 45, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 85, 88, 92, 93, 94, 100, 101, 102, 103, 108, 109, 110, 111, 112, 113, 114, 131, 132, 133, 145, 151, 152, 153, 155, 156, 157, 158, 159, 160, 168, 180, 183], "": [0, 1, 5, 6, 7, 8, 9, 12, 14, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 47, 48, 53, 63, 68, 69, 72, 73, 74, 75, 76, 77, 78, 79, 82, 83, 85, 86, 89, 90, 91, 92, 93, 94, 98, 99, 100, 103, 104, 106, 151, 153, 158, 168, 176, 180, 183], "veri": [0, 1, 5, 18, 30, 33, 39, 44, 55, 84, 176], "import": [0, 1, 5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 48, 92, 176, 180, 181, 187], "u": [0, 47, 48, 75, 83, 84, 92, 152], "maintain": [0, 1, 89, 90, 91, 98, 102, 103, 176], "posit": [0, 35, 63, 69, 70, 73, 75, 84, 91, 96, 104], "support": [0, 1, 22, 26, 27, 29, 48, 64, 65, 66, 67, 96, 115, 174, 176, 187], "everyon": [0, 39], "who": [0, 1, 176], "want": [0, 1, 5, 9, 12, 14, 18, 19, 21, 25, 26, 27, 28, 30, 31, 32, 33, 36, 37, 39, 42, 44, 45, 47, 48, 176, 179], "particip": [0, 48, 63, 69, 70, 71, 74, 75, 76, 77, 78, 79, 83, 85, 89, 92, 102, 103, 105], "when": [0, 1, 13, 14, 16, 18, 19, 28, 33, 34, 42, 44, 47, 71, 88, 90, 92, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 153, 172, 176, 182, 183, 187], "join": [0, 1, 6, 11, 29, 176], "ask": [0, 1, 68, 75, 76, 77, 78, 79, 82, 83, 86, 87, 88, 89, 91, 96, 99, 100, 104, 105, 176], "follow": [0, 1, 12, 21, 22, 25, 29, 33, 34, 39, 42, 44, 45, 46, 47, 48, 60, 62, 63, 70, 73, 75, 76, 77, 78, 79, 81, 84, 88, 89, 90, 91, 92, 93, 94, 97, 99, 100, 102, 103, 104, 106, 107, 123, 126, 127, 128, 129, 145, 176, 177, 178, 179, 180, 181], "all": [0, 3, 6, 7, 8, 9, 12, 14, 16, 18, 19, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 47, 48, 49, 54, 55, 56, 58, 60, 63, 68, 70, 71, 76, 77, 78, 79, 81, 83, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 98, 99, 100, 101, 102, 103, 104, 107, 119, 122, 123, 124, 125, 127, 129, 131, 132, 133, 134, 136, 137, 138, 140, 142, 143, 144, 145, 146, 148, 149, 150, 153, 177, 178, 181, 185, 187], "interact": [0, 1, 176, 182], "both": [0, 1, 9, 32, 35, 60, 61, 63, 68, 73, 82, 96, 97, 98, 100, 102, 105, 153, 176], "offlin": [0, 85, 89, 90, 91, 103], "The": [0, 5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 44, 45, 46, 47, 48, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 123, 126, 127, 128, 129, 131, 132, 133, 134, 136, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 166, 168, 170, 172, 173, 175, 177, 179, 181, 182], "set": [0, 3, 5, 8, 9, 11, 12, 14, 18, 19, 21, 25, 26, 27, 28, 29, 30, 31, 32, 33, 36, 37, 42, 45, 46, 50, 61, 62, 63, 64, 65, 66, 67, 68, 70, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 92, 95, 96, 97, 98, 101, 102, 104, 105, 106, 107, 122, 124, 125, 126, 127, 128, 129, 131, 134, 137, 138, 145, 150, 151, 152, 172, 173, 174, 175, 178, 181, 187], "guidelin": [0, 179], "project": [0, 1, 7, 176, 179, 180], "thi": [0, 1, 3, 5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 46, 47, 48, 58, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 74, 80, 81, 82, 83, 84, 85, 86, 87, 88, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 115, 116, 122, 126, 127, 128, 129, 131, 132, 133, 136, 140, 145, 146, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 166, 168, 170, 172, 176, 179, 180, 181, 182, 183, 184, 187], "adher": [0, 102, 103], "contributor": [0, 179], "coven": 0, "By": [0, 7, 12, 23, 24, 25, 26, 27, 28, 33, 60, 72, 122, 180], "expect": [0, 12, 35, 72, 93, 94, 182, 183], "report": [0, 1, 37, 80, 81, 88, 92, 176, 183], "unaccept": 0, "behavior": 0, "hi": [0, 88], "pushtheworld": 0, "new": [0, 1, 7, 9, 18, 21, 24, 30, 32, 33, 35, 36, 41, 46, 60, 62, 64, 65, 66, 67, 76, 77, 78, 79, 80, 81, 86, 87, 97, 101, 102, 103, 108, 122, 123, 131, 151, 152, 153, 155, 156, 157, 158, 159, 160, 173, 176, 177, 179, 182], "git": [0, 179], "learn": [0, 1, 3, 4, 7, 13, 15, 20, 21, 25, 26, 27, 38, 42, 50, 68, 72, 86, 87, 89, 98, 107, 126, 128, 129, 139, 140, 141, 143, 148, 152, 155, 160, 163, 174, 175, 176, 178, 181, 182, 187], "fork": 0, "repo": 0, "make": [0, 5, 6, 7, 14, 16, 17, 19, 30, 39, 42, 44, 92, 108, 153], "your": [0, 1, 11, 12, 14, 19, 25, 27, 33, 39, 42, 47, 60, 71, 83, 172, 176, 177, 180, 183], "own": [0, 5, 42, 83, 93, 94, 98], "addit": [0, 9, 33, 35, 68, 69, 70, 86, 89, 92, 94, 129, 181, 187], "includ": [0, 24, 32, 34, 39, 42, 48, 58, 60, 63, 71, 75, 76, 77, 78, 79, 80, 81, 84, 86, 89, 92, 93, 94, 99, 100, 102, 104, 107, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 177, 182, 187], "those": [0, 6, 9, 16, 42, 60, 93, 94], "master": 0, "version": [0, 1, 22, 26, 27, 29, 47, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 85, 86, 87, 88, 99, 100, 101, 102, 103, 108, 109, 110, 111, 112, 113, 114, 115, 119, 122, 123, 131, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 176, 177, 178, 179], "great": [0, 41], "tutori": [0, 1, 8, 9, 22, 33, 34, 40, 43, 48, 64, 68, 81, 106, 107, 115, 124, 126, 128, 129, 139, 141, 143, 148, 174, 176, 179, 182, 187], "neurotechx": [0, 1, 3, 47, 48, 49, 83, 176, 179], "gitter": [0, 1, 47, 176], "discuss": [0, 1, 176], "about": [0, 1, 14, 19, 36, 42, 65, 83, 105, 150, 176, 182], "take": [0, 1, 3, 12, 33, 34, 42, 44, 48, 49, 52, 53, 80, 99, 100, 101, 107, 151, 152, 153, 167, 172, 176, 182], "place": [0, 42, 62, 64, 65, 66, 67, 70, 75, 76, 77, 78, 79, 80, 84, 85, 86, 99, 100, 101, 104], "featur": [0, 14, 21, 26, 34, 42, 101, 145, 152, 166, 172, 179, 187], "d": [0, 1, 8, 12, 22, 25, 26, 27, 31, 39, 42, 45, 46, 47, 60, 61, 62, 64, 65, 66, 67, 69, 71, 72, 86, 87, 97, 99, 100, 101, 103, 104, 155, 160, 169, 176], "interest": [0, 9, 33], "build": [0, 1, 32, 62, 166, 176, 177, 187], "find": [0, 1, 6, 25, 33, 42, 176, 182], "bug": 0, "have": [0, 1, 3, 5, 7, 8, 14, 18, 19, 33, 34, 35, 36, 39, 42, 44, 46, 48, 49, 61, 80, 81, 83, 89, 90, 91, 92, 93, 94, 101, 102, 103, 104, 105, 107, 124, 125, 132, 133, 136, 137, 140, 142, 150, 176, 178, 179, 180, 181, 183, 184, 187], "suggest": [0, 1, 29, 48, 176], "improv": [0, 27, 29, 75, 76, 77, 78, 79, 187], "go": [0, 1, 3, 41, 42, 44, 45, 46, 50, 176, 181], "ahead": 0, "let": [0, 7, 24, 34, 41], "know": [0, 14, 39, 42], "open": [0, 1, 6, 21, 22, 25, 47, 48, 63, 96, 97, 99, 100, 101, 176], "an": [0, 1, 3, 5, 7, 9, 12, 22, 23, 24, 25, 26, 30, 31, 32, 33, 34, 35, 39, 41, 42, 44, 46, 47, 50, 54, 59, 60, 62, 63, 65, 68, 70, 71, 81, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 98, 99, 100, 101, 102, 104, 107, 126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 170, 172, 176, 179, 180, 181, 182, 183, 185], "issu": [0, 1, 39, 47, 48, 83, 97, 145, 176, 187], "so": [0, 5, 9, 18, 30, 32, 33, 34, 36, 48, 83, 153, 183], "other": [0, 3, 6, 8, 9, 30, 31, 35, 42, 44, 46, 48, 50, 72, 82, 85, 92, 98, 99, 100, 102, 125, 151, 152, 153, 155, 156, 157, 158, 159, 160, 181, 182], "along": [0, 1, 73, 93, 94, 99, 100, 176], "ll": 0, "much": 0, "finish": [0, 33, 99, 100], "submit": 0, "pull": [0, 70, 180], "request": [0, 75, 117, 118, 119, 120, 121, 151, 152, 153, 155, 156, 157, 158, 159, 160], "branch": 0, "referenc": [0, 71, 72, 74, 76, 77, 78, 79, 85, 86, 89, 90, 91], "specif": [0, 7, 8, 12, 18, 22, 23, 25, 26, 27, 28, 33, 34, 41, 48, 60, 88, 92, 100, 102, 126, 127, 128, 129, 132, 133, 137, 140, 142, 143, 145, 146, 148, 149, 150, 177, 182], "address": [0, 187], "look": [0, 1, 33, 42, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 176, 182], "one": [0, 1, 3, 5, 6, 7, 9, 12, 14, 19, 22, 25, 26, 27, 28, 30, 31, 33, 34, 39, 41, 44, 45, 46, 48, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 74, 75, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 115, 116, 122, 124, 127, 132, 133, 142, 143, 145, 146, 148, 149, 153, 172, 174, 176, 178, 181, 184, 187], "problem": [0, 24, 34, 45, 178, 187], "propos": [0, 1, 88, 151, 176], "solut": [0, 152, 183], "clone": 0, "local": [0, 3, 12, 44, 48, 49, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 122, 179, 181], "from": [0, 3, 5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 48, 50, 51, 52, 53, 54, 57, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 117, 118, 120, 123, 126, 127, 128, 129, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 167, 168, 170, 171, 172, 173, 177, 180, 181, 182, 187], "checkout": [0, 179], "track": [0, 12, 85, 187], "creat": [0, 7, 11, 21, 23, 24, 27, 33, 35, 40, 43, 64, 81, 92, 99, 100, 107, 108, 115, 128, 131, 134, 138, 139, 141, 161, 167, 173, 179, 187], "b": [0, 1, 12, 26, 27, 29, 34, 47, 62, 63, 64, 65, 66, 67, 70, 97, 99, 100, 106, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 151, 158, 168, 176], "my": 0, "chang": [0, 9, 16, 18, 25, 26, 28, 29, 30, 32, 33, 36, 38, 41, 151, 152, 153, 155, 156, 157, 158, 159, 160, 172, 173, 179], "commit": [0, 179, 187], "m": [0, 26, 27, 29, 48, 62, 63, 64, 65, 66, 67, 68, 70, 71, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 89, 90, 91, 97, 99, 100, 101, 102, 103, 104, 153, 155, 158, 159, 160, 168, 170, 179], "add": [0, 1, 9, 18, 30, 32, 36, 39, 47, 48, 176, 187], "some": [0, 1, 7, 9, 28, 42, 44, 70, 107, 108, 151, 152, 153, 155, 156, 157, 158, 159, 160, 176, 181, 182, 183], "don": [0, 33, 124], "forget": 0, "fix": [0, 6, 16, 22, 33, 34, 38, 42, 63, 99, 100, 102, 106, 107, 129, 131, 134, 138, 140, 143, 145, 148, 174, 187], "pre": [0, 44, 99, 100, 104, 145, 177, 179, 187], "pipelin": [0, 4, 8, 10, 16, 17, 21, 24, 26, 27, 28, 33, 34, 38, 39, 40, 41, 43, 45, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 68, 72, 106, 107, 109, 110, 111, 112, 113, 114, 126, 127, 128, 129, 139, 141, 143, 145, 148, 174, 183, 187], "either": [0, 3, 12, 25, 33, 34, 50, 68, 85, 94, 97, 98, 99, 107, 128, 129, 145, 181], "made": [0, 1, 34, 80, 81, 99, 100, 107, 129, 145, 151, 152, 176], "hook": 0, "them": [0, 3, 14, 19, 24, 25, 29, 32, 36, 42, 44, 48, 49, 63, 69, 83, 102, 153, 181, 187], "manual": [0, 25, 178], "case": [0, 1, 7, 25, 28, 33, 34, 45, 63, 108, 126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 172, 176, 178, 187], "flake8": [0, 187], "push": 0, "origin": [0, 7, 18, 22, 25, 33, 34, 35, 41, 48, 71, 89, 126, 127, 128, 129, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 168], "base": [0, 1, 4, 10, 14, 16, 19, 25, 26, 27, 29, 30, 32, 33, 34, 39, 47, 48, 57, 59, 60, 63, 64, 65, 66, 67, 68, 70, 71, 72, 74, 76, 77, 78, 79, 81, 82, 84, 87, 88, 89, 91, 92, 93, 94, 95, 96, 99, 100, 103, 104, 106, 126, 130, 131, 141, 143, 146, 149, 150, 151, 152, 153, 158, 161, 168, 174, 176, 187], "updat": [0, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 122, 151, 152, 153, 155, 156, 157, 158, 159, 160, 178, 179, 187], "what": [0, 9, 22, 107, 122, 129], "page": [0, 1, 47, 176, 182], "need": [0, 7, 9, 12, 13, 14, 16, 17, 21, 24, 25, 26, 27, 28, 29, 33, 39, 42, 63, 145, 150, 162, 172, 179, 180, 182], "instal": [0, 13, 14, 16, 19, 180, 182], "poetri": [0, 13, 16, 179, 187], "onli": [0, 5, 8, 9, 12, 14, 16, 17, 19, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 44, 46, 60, 72, 74, 84, 92, 93, 94, 98, 101, 103, 107, 124, 132, 136, 140, 142, 143, 145, 148, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 163, 172, 178, 179, 182, 183, 187], "onc": [0, 33, 39, 44, 76, 77, 78, 79, 86, 103, 107, 179, 181], "per": [0, 3, 9, 16, 17, 18, 34, 35, 48, 49, 50, 52, 53, 55, 63, 65, 67, 68, 69, 70, 72, 85, 86, 87, 89, 96, 98, 99, 106, 107, 122, 124, 145, 152, 153, 179, 181], "machin": [0, 7, 12, 22, 26, 61, 89, 159, 170, 179], "curl": [0, 179], "ssl": [0, 179], "http": [0, 22, 25, 39, 41, 44, 45, 46, 47, 48, 61, 64, 65, 66, 67, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 102, 103, 105, 106, 117, 118, 119, 120, 121, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 168, 170, 176, 179, 187], "python": [0, 5, 6, 7, 8, 9, 11, 12, 14, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 61, 62, 63, 64, 65, 66, 67, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 119, 121, 122, 174, 177, 178, 179, 182, 187], "org": [0, 22, 25, 39, 48, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 102, 103, 105, 106, 151, 152, 155, 156, 157, 158, 159, 160, 161, 168, 170, 179], "python3": [0, 14, 19, 25, 27, 28, 29, 30, 179, 187], "instruct": [0, 39, 69, 76, 77, 78, 79, 82, 85, 88, 89, 94, 96, 99, 100, 101, 106, 177, 179, 180], "conda": [0, 179], "forg": [0, 179], "option": [0, 3, 22, 34, 44, 48, 49, 107, 108, 128, 129, 144, 145, 151, 152, 153, 155, 156, 157, 158, 159, 160, 177, 178, 179, 180, 181, 187], "skip": [0, 107, 124, 125, 179], "disabl": [0, 75, 84, 179], "automat": [0, 6, 22, 25, 28, 32, 39, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 179], "creation": [0, 39, 179], "config": [0, 11, 25, 26, 29, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 167, 173, 179, 187], "virtualenv": [0, 179], "fals": [0, 5, 7, 9, 12, 21, 25, 26, 27, 28, 29, 30, 32, 33, 34, 39, 41, 42, 45, 46, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 89, 90, 91, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 115, 116, 121, 122, 124, 125, 126, 127, 128, 129, 130, 145, 151, 152, 153, 155, 156, 157, 158, 159, 160, 166, 171, 179], "depend": [0, 1, 12, 13, 16, 24, 33, 34, 63, 82, 98, 107, 129, 145, 176, 177, 178, 179, 182, 187], "command": [0, 12, 22, 25, 42, 61, 178, 179, 180, 181], "run": [0, 5, 7, 8, 9, 11, 13, 14, 16, 18, 19, 21, 22, 23, 24, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 48, 60, 63, 68, 69, 70, 71, 72, 75, 81, 82, 84, 89, 90, 91, 96, 97, 98, 101, 102, 103, 106, 107, 122, 126, 127, 128, 129, 145, 179, 180, 181, 182, 187], "thibe": 0, "directori": [0, 6, 16, 22, 25, 33, 38, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 173, 179, 187], "extra": [0, 1, 13, 16, 176, 179, 187], "deeplearn": [0, 165, 178, 179], "codecarbon": [0, 12, 187], "readi": [0, 3, 34, 181, 184], "1": [0, 1, 5, 6, 7, 8, 9, 10, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 46, 47, 48, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 123, 124, 126, 127, 128, 129, 131, 132, 133, 134, 137, 138, 139, 140, 142, 143, 145, 146, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 168, 169, 170, 172, 174, 176], "first": [0, 1, 5, 9, 12, 22, 24, 26, 27, 30, 32, 33, 34, 35, 37, 39, 41, 44, 46, 56, 70, 71, 72, 84, 86, 87, 90, 92, 93, 94, 96, 99, 101, 176, 179, 180, 187], "trigger": [0, 27, 83, 104], "download": [0, 3, 5, 6, 7, 8, 9, 12, 14, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 45, 46, 48, 49, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 92, 95, 96, 97, 98, 99, 100, 101, 104, 105, 106, 107, 108, 122, 173, 178, 180, 181, 187], "qualiti": [0, 89], "That": [0, 83], "ok": 0, "intend": [0, 9, 25, 27, 28], "done": [0, 5, 9, 18, 22, 30, 33, 44, 96, 107, 179], "2": [0, 5, 6, 7, 8, 9, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 48, 52, 53, 61, 63, 67, 68, 69, 70, 71, 73, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 122, 128, 129, 131, 132, 133, 134, 136, 137, 138, 139, 140, 142, 143, 145, 146, 148, 149, 150, 151, 155, 156, 157, 158, 159, 160, 168, 169, 174], "default": [0, 7, 11, 12, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 42, 54, 55, 58, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 119, 122, 126, 127, 128, 129, 131, 132, 133, 134, 137, 138, 140, 142, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 172, 173, 180, 187], "separ": [0, 3, 48, 49, 68, 72, 92, 93, 94, 96, 99, 100, 128, 181], "virtual": [0, 70, 81, 83], "everi": [0, 6, 9, 30, 31, 33, 35, 96, 98, 106, 132, 133, 153], "more": [0, 1, 9, 14, 18, 19, 22, 24, 25, 27, 28, 33, 34, 42, 44, 70, 74, 83, 92, 96, 124, 128, 129, 132, 133, 136, 137, 140, 142, 145, 150, 153, 172, 176, 179, 181, 183, 187], "detail": [0, 3, 12, 22, 25, 26, 27, 28, 34, 42, 48, 49, 70, 75, 92, 107, 145, 150, 179, 182], "wai": [0, 1, 22, 33, 42, 44, 83, 100, 101, 176, 177, 178, 179], "manag": [0, 1, 176, 187], "differ": [0, 1, 3, 5, 6, 7, 9, 12, 16, 17, 22, 24, 33, 34, 36, 42, 44, 45, 46, 48, 49, 52, 53, 55, 63, 68, 70, 71, 72, 75, 76, 77, 78, 79, 81, 84, 88, 91, 92, 93, 94, 96, 97, 101, 102, 104, 105, 141, 153, 176, 177, 181, 183, 184, 187], "hand": [0, 18, 30, 31, 34, 44, 45, 61, 68, 69, 70, 73, 75, 82, 84, 85, 90, 96, 98, 99, 100, 105, 106, 107, 135, 139], "also": [0, 1, 8, 12, 14, 19, 22, 32, 33, 34, 42, 48, 71, 92, 99, 100, 102, 167, 176, 178, 179, 182], "care": 0, "ha": [0, 1, 9, 11, 18, 25, 27, 28, 29, 30, 32, 33, 36, 39, 42, 44, 81, 88, 92, 93, 94, 122, 123, 128, 151, 152, 153, 155, 156, 157, 158, 159, 160, 168, 176, 180, 181, 183], "satisfi": 0, "requir": [0, 1, 3, 27, 31, 34, 37, 71, 91, 96, 98, 107, 131, 136, 140, 145, 146, 149, 173, 176, 181, 185], "state": [0, 1, 16, 22, 25, 38, 92, 93, 94, 95, 99, 100, 105, 106, 107, 139, 143, 148, 174, 176, 187], "pyproject": [0, 179], "toml": [0, 179], "In": [0, 1, 7, 8, 12, 16, 21, 22, 24, 25, 26, 27, 28, 29, 33, 34, 35, 37, 42, 44, 46, 63, 68, 70, 71, 72, 76, 77, 78, 79, 84, 86, 89, 92, 93, 94, 96, 99, 101, 102, 104, 153, 159, 170, 172, 176, 181], "charg": 0, "enabl": [0, 68, 70, 83, 178], "reproduc": [0, 1, 14, 19, 21, 25, 26, 27, 29, 47, 176, 183], "popular": [0, 1, 5, 18, 30, 176], "o": [0, 6, 11, 26, 27, 71, 83, 89, 90, 91], "linux": 0, "maco": 0, "window": [0, 16, 38, 84, 92, 93, 94, 106, 107, 131, 134, 138, 140, 143, 148, 174], "provid": [0, 1, 8, 12, 25, 34, 36, 37, 41, 44, 45, 46, 61, 68, 70, 71, 72, 75, 76, 77, 78, 79, 81, 86, 89, 99, 100, 123, 129, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 166, 176, 182], "easi": [0, 45, 172], "publish": [0, 1, 47, 70, 74, 83, 176], "anoth": [0, 5, 22, 30, 84, 85, 91, 92, 94, 108, 180], "stabl": 0, "It": [0, 6, 8, 12, 22, 25, 26, 27, 28, 33, 39, 41, 44, 48, 60, 105, 116, 152, 153, 180], "varieti": 0, "instrument": 0, "against": [0, 86], "produc": [0, 83], "For": [0, 1, 7, 9, 12, 16, 17, 22, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 39, 42, 44, 48, 63, 70, 74, 84, 85, 86, 90, 92, 93, 94, 99, 100, 103, 104, 132, 133, 153, 176, 177, 178, 179], "verif": 0, "black": [0, 68, 90, 91, 98, 99, 100, 106, 187], "format": [0, 3, 22, 25, 28, 31, 33, 37, 39, 44, 48, 49, 61, 80, 81, 171, 181, 187], "isort": [0, 187], "sort": [0, 34, 99, 100, 107, 122, 128, 136, 140], "group": [0, 88, 104, 153, 179], "style": [0, 9, 56, 187], "prettier": [0, 187], "yml": [0, 25, 42, 60, 187], "md": [0, 187], "file": [0, 6, 10, 15, 20, 22, 25, 28, 33, 34, 38, 39, 42, 43, 44, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 92, 93, 94, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 117, 118, 119, 120, 122, 126, 127, 128, 129, 145, 167, 179, 187], "To": [0, 7, 12, 16, 17, 22, 24, 25, 26, 27, 28, 29, 31, 34, 35, 37, 39, 42, 44, 60, 86, 89, 104, 107, 145, 178, 179, 180], "cd": [0, 76, 77, 78, 79, 179, 180], "doc": [0, 178, 179, 182, 187], "html": 0, "comprehens": [1, 176, 187], "brain": [1, 22, 26, 27, 29, 33, 48, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 82, 84, 85, 86, 87, 89, 90, 91, 95, 97, 98, 99, 100, 101, 102, 103, 104, 106, 151, 153, 155, 158, 159, 160, 168, 170, 176, 183], "comput": [1, 7, 8, 12, 21, 23, 25, 26, 27, 28, 29, 33, 34, 37, 39, 42, 48, 51, 52, 53, 54, 55, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 72, 74, 75, 81, 82, 84, 85, 86, 87, 95, 96, 97, 101, 102, 103, 104, 106, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 151, 152, 153, 158, 168, 176, 179, 183, 187], "interfac": [1, 22, 26, 27, 29, 48, 61, 62, 63, 64, 65, 66, 67, 69, 71, 72, 74, 75, 81, 82, 85, 86, 87, 89, 95, 97, 101, 102, 103, 104, 106, 151, 158, 159, 168, 170, 176, 183, 187], "algorithm": [1, 3, 5, 9, 24, 30, 32, 34, 35, 42, 47, 55, 56, 63, 87, 92, 129, 176, 181, 184, 185, 187], "appli": [1, 4, 5, 7, 16, 31, 32, 33, 34, 35, 37, 44, 71, 102, 104, 107, 129, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 166, 176, 187], "extens": [1, 22, 44, 96, 176, 183], "list": [1, 8, 9, 12, 14, 19, 22, 25, 26, 27, 28, 34, 39, 41, 42, 44, 48, 58, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 89, 90, 91, 92, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 117, 118, 119, 120, 122, 123, 124, 125, 126, 127, 128, 129, 131, 132, 133, 134, 136, 137, 138, 140, 142, 143, 144, 145, 146, 148, 149, 150, 151, 153, 172, 176, 179, 182, 187], "freeli": [1, 83, 88, 176], "avail": [1, 12, 14, 16, 17, 19, 25, 26, 27, 28, 29, 33, 34, 36, 39, 42, 44, 62, 64, 65, 66, 67, 70, 72, 80, 81, 84, 89, 90, 91, 92, 101, 104, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 153, 176, 177, 183], "eeg": [1, 7, 22, 26, 27, 29, 31, 32, 34, 37, 39, 46, 47, 48, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 107, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 152, 155, 156, 158, 159, 160, 161, 162, 168, 170, 176], "dataset": [1, 5, 6, 9, 14, 16, 17, 18, 19, 21, 23, 26, 27, 28, 29, 30, 33, 34, 36, 38, 40, 43, 46, 52, 53, 54, 55, 56, 58, 60, 126, 127, 128, 129, 130, 131, 132, 133, 134, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 148, 149, 150, 151, 161, 174, 176, 180, 182, 183, 187], "i": [1, 3, 5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41, 42, 44, 45, 46, 47, 48, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 71, 72, 73, 75, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 115, 116, 119, 121, 122, 123, 126, 127, 128, 129, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 167, 168, 170, 172, 173, 174, 176, 177, 178, 180, 181, 182, 183, 184, 187], "scienc": [1, 47, 83, 176], "mai": [1, 9, 14, 19, 25, 27, 28, 34, 44, 83, 107, 176, 179, 180, 182], "evolv": [1, 176], "commun": [1, 70, 84, 176], "visit": [1, 176], "document": [1, 12, 42, 48, 176, 178, 180, 187], "associ": [1, 32, 44, 60, 75, 89, 90, 91, 107, 117, 118, 119, 120, 129, 153, 176, 183], "github": [1, 41, 44, 45, 46, 47, 153, 176, 177, 187], "repositori": [1, 39, 176, 177], "hub": [1, 176, 180], "give": [1, 92, 93, 94, 176], "inform": [1, 7, 14, 24, 26, 27, 29, 31, 37, 44, 48, 63, 74, 76, 77, 78, 79, 83, 88, 104, 121, 126, 127, 128, 129, 145, 176, 179, 182, 187], "jump": [1, 14, 83, 176], "straight": [1, 41, 176], "section": [1, 98, 105, 176, 178, 179, 182, 187], "below": [1, 12, 44, 76, 77, 78, 79, 85, 86, 89, 90, 91, 99, 100, 104, 176, 178], "just": [1, 42, 45, 93, 176], "scroll": [1, 176], "down": [1, 68, 73, 85, 91, 176], "allow": [1, 6, 7, 9, 22, 24, 27, 28, 29, 31, 32, 33, 34, 37, 86, 92, 104, 145, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 176, 187], "signal": [1, 4, 7, 16, 25, 26, 31, 32, 33, 37, 39, 44, 68, 71, 82, 86, 89, 90, 91, 92, 93, 94, 97, 99, 100, 101, 151, 152, 157, 162, 176, 183, 187], "focu": [1, 29, 32, 76, 77, 78, 79, 88, 92, 94, 102, 176], "mostli": [1, 13, 16, 176], "electroencephalograph": [1, 62, 64, 65, 66, 67, 80, 81, 176], "activ": [1, 48, 64, 65, 66, 67, 69, 71, 73, 75, 76, 77, 78, 79, 82, 83, 86, 87, 98, 99, 100, 102, 168, 169, 170, 176], "research": [1, 22, 80, 81, 87, 92, 93, 94, 97, 155, 158, 160, 176], "domain": [1, 96, 176], "worldwid": [1, 176], "scientif": [1, 47, 62, 63, 64, 65, 66, 67, 80, 176], "contribut": [1, 39, 47, 48, 176, 177, 179, 182], "still": [1, 63, 92, 98, 176, 180], "long": [1, 98, 176], "while": [1, 14, 19, 32, 48, 83, 85, 86, 97, 98, 100, 102, 103, 105, 176, 182], "code": [1, 5, 6, 7, 8, 9, 11, 12, 14, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 48, 60, 76, 77, 78, 79, 94, 102, 103, 107, 122, 132, 133, 153, 155, 156, 157, 158, 159, 160, 168, 170, 176, 177, 179, 182, 187], "result": [1, 16, 17, 21, 25, 26, 27, 28, 33, 42, 51, 54, 58, 60, 70, 74, 75, 86, 92, 93, 94, 99, 100, 101, 102, 126, 127, 128, 129, 153, 176, 180, 181, 183, 187], "turn": [1, 25, 176], "trickier": [1, 176], "than": [1, 9, 14, 18, 19, 24, 25, 27, 28, 33, 56, 84, 96, 105, 124, 172, 176, 183], "should": [1, 7, 16, 39, 41, 44, 60, 87, 99, 100, 102, 107, 115, 126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 151, 152, 153, 155, 156, 157, 158, 159, 160, 162, 166, 176, 179, 183], "perform": [1, 5, 7, 9, 14, 18, 19, 23, 24, 25, 30, 31, 32, 34, 36, 37, 44, 48, 61, 63, 68, 69, 71, 72, 73, 74, 75, 81, 82, 83, 84, 85, 89, 90, 95, 96, 97, 98, 99, 100, 101, 105, 106, 126, 127, 128, 176, 183], "can": [1, 3, 9, 11, 12, 13, 14, 16, 18, 19, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 41, 42, 44, 48, 50, 55, 60, 83, 92, 96, 107, 126, 127, 128, 129, 145, 150, 153, 166, 172, 176, 177, 178, 179, 180, 181, 183, 184], "significantli": [1, 9, 59, 176], "impact": [1, 70, 153, 176], "paramet": [1, 9, 18, 22, 25, 28, 29, 30, 32, 33, 34, 35, 36, 39, 42, 46, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 126, 127, 128, 129, 131, 132, 133, 134, 136, 137, 138, 140, 142, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 166, 167, 168, 172, 173, 175, 176, 178, 187], "preprocess": [1, 3, 5, 6, 7, 8, 9, 14, 18, 19, 22, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42, 44, 129, 145, 176, 181, 184, 187], "step": [1, 3, 6, 22, 25, 29, 33, 39, 41, 44, 107, 108, 129, 176, 179, 180, 181, 185, 187], "toolbox": [1, 76, 77, 78, 79, 89, 90, 91, 176], "implement": [1, 5, 6, 9, 13, 16, 18, 26, 27, 28, 29, 30, 39, 41, 76, 77, 78, 79, 129, 153, 155, 156, 157, 158, 159, 160, 161, 168, 170, 176, 182, 187], "trick": [1, 176], "almost": [1, 176], "never": [1, 176], "literatur": [1, 5, 9, 18, 25, 30, 48, 176], "As": [1, 7, 22, 32, 33, 41, 44, 45, 46, 92, 93, 94, 101, 103, 176], "newcom": [1, 176], "spend": [1, 176], "tremend": [1, 176], "amount": [1, 14, 18, 19, 69, 176], "time": [1, 5, 6, 7, 8, 9, 11, 12, 14, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 61, 70, 76, 77, 78, 79, 83, 84, 85, 86, 89, 90, 91, 92, 96, 99, 101, 102, 104, 106, 108, 126, 127, 128, 129, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 153, 176, 180, 187], "brows": [1, 176], "work": [1, 6, 7, 8, 9, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42, 46, 63, 84, 151, 152, 153, 155, 156, 157, 158, 159, 160, 176, 178, 182, 183], "best": [1, 28, 70, 176], "which": [1, 3, 9, 14, 19, 22, 24, 25, 27, 28, 32, 36, 42, 44, 48, 49, 55, 60, 63, 70, 74, 75, 80, 81, 84, 85, 86, 87, 88, 92, 93, 94, 96, 98, 99, 100, 103, 104, 105, 106, 125, 145, 153, 172, 176, 181, 187], "serv": [1, 33, 68, 70, 176], "refer": [1, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 145, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 168, 170, 176, 182], "point": [1, 5, 30, 68, 71, 76, 77, 78, 79, 85, 88, 99, 104, 106, 176], "futur": [1, 14, 19, 36, 83, 176], "develop": [1, 176], "rank": [1, 55, 176], "promot": [1, 176], "websit": [1, 22, 39, 176, 187], "clear": [1, 176], "pictur": [1, 176], "field": [1, 44, 176, 183, 187], "success": [1, 25, 101, 176], "read": [1, 42, 76, 77, 78, 79, 83, 176, 181, 182], "abstract": [1, 3, 48, 49, 83, 107, 129, 144, 145, 176, 181], "method": [1, 9, 22, 23, 24, 29, 32, 33, 35, 42, 44, 53, 55, 63, 84, 95, 106, 121, 126, 127, 128, 129, 130, 131, 136, 140, 145, 146, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 161, 165, 172, 176, 182, 187], "obtain": [1, 3, 7, 8, 23, 31, 33, 35, 37, 44, 45, 46, 54, 57, 69, 88, 92, 97, 98, 102, 128, 153, 176, 181, 183, 185], "score": [1, 3, 5, 6, 8, 9, 14, 18, 19, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 36, 37, 39, 41, 42, 44, 45, 46, 50, 51, 58, 63, 126, 127, 128, 129, 135, 136, 139, 140, 141, 144, 146, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 176, 181, 187], "89": [1, 25, 176], "outperform": [1, 5, 9, 30, 176], "art": [1, 25, 92, 176], "5": [1, 5, 6, 7, 8, 9, 14, 18, 19, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 42, 43, 46, 48, 60, 63, 64, 68, 69, 70, 72, 73, 75, 76, 77, 78, 79, 81, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 99, 100, 101, 103, 104, 105, 106, 123, 128, 131, 132, 133, 134, 137, 138, 140, 141, 142, 143, 145, 146, 148, 149, 150, 152, 155, 156, 157, 158, 159, 160, 168, 176, 183], "could": [1, 6, 7, 11, 12, 16, 17, 25, 26, 27, 28, 31, 32, 37, 39, 42, 44, 45, 47, 58, 60, 70, 83, 88, 89, 90, 91, 92, 145, 151, 152, 176, 179, 187], "cover": [1, 25, 72, 98, 104, 176, 182], "most": [1, 5, 7, 25, 30, 48, 119, 176, 178, 179, 182], "concept": [1, 16, 176], "galleri": [1, 5, 6, 7, 8, 9, 11, 12, 14, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 176], "exampl": [1, 5, 6, 7, 8, 9, 11, 12, 14, 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 45, 46, 48, 92, 108, 132, 133, 145, 146, 149, 166, 176, 178, 180, 182, 187], "current": [1, 11, 25, 26, 28, 29, 30, 31, 48, 86, 89, 101, 107, 161, 176], "pip": [177, 178, 179], "fail": 187, "21": [25, 36, 38, 43, 44, 48, 81, 101, 187], "e": [1, 3, 22, 26, 27, 29, 32, 33, 34, 35, 44, 47, 48, 63, 64, 65, 70, 71, 74, 75, 84, 85, 87, 88, 89, 90, 91, 93, 94, 96, 97, 99, 100, 101, 103, 104, 107, 129, 132, 133, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 172, 174, 176, 179, 181, 184], "g": [27, 34, 44, 45, 46, 48, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 80, 81, 87, 96, 97, 100, 101, 132, 133, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 172], "20": [7, 8, 14, 16, 17, 18, 19, 25, 28, 31, 38, 45, 48, 54, 55, 61, 63, 69, 70, 72, 73, 75, 76, 77, 78, 79, 83, 84, 85, 86, 88, 92, 93, 94, 99, 100, 101, 103, 104, 134, 147], "0": [1, 5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48, 59, 60, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 86, 87, 96, 99, 100, 101, 102, 103, 104, 107, 108, 109, 110, 111, 112, 113, 114, 122, 123, 124, 125, 126, 129, 131, 132, 133, 134, 137, 138, 139, 140, 142, 143, 144, 145, 146, 148, 149, 150, 152, 153, 155, 156, 157, 158, 159, 160, 168, 169, 174, 176], "due": [12, 42, 84, 87, 183, 187], "idna": [], "packag": [14, 19, 25, 27, 28, 29, 30, 44, 177, 178], "conflict": [], "newer": 187, "resolv": [], "upgrad": [], "befor": [34, 45, 75, 76, 77, 78, 79, 86, 87, 89, 90, 91, 92, 93, 94, 96, 99, 101, 104, 105, 126, 150, 178, 187], "under": [1, 22, 31, 33, 37, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 92, 93, 94, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 176, 179], "umbrella": [1, 176], "intern": [1, 26, 27, 63, 73, 75, 76, 77, 78, 79, 82, 83, 84, 93, 99, 100, 102, 104, 152, 159, 170, 176], "neurotech": [1, 176], "enthusiast": [1, 176], "sylvain": [1, 7, 8, 25, 27, 30, 31, 32, 34, 37, 39, 44, 45, 46, 47, 88, 176, 187], "chevalli": [1, 7, 8, 25, 27, 30, 31, 32, 34, 37, 39, 44, 45, 46, 47, 88, 176, 187], "bruno": [1, 12, 27, 29, 47, 176, 187], "aristimunha": [1, 12, 27, 29, 47, 176, 187], "igor": [1, 12, 21, 26, 27, 28, 29, 47, 176, 187], "carrara": [1, 12, 21, 26, 27, 28, 29, 47, 161, 176, 187], "pierr": [1, 22, 33, 35, 47, 176, 187], "guetschel": [1, 22, 33, 35, 47, 176, 187], "sara": [1, 47, 176, 187], "sedlar": [1, 47, 176, 187], "wa": [1, 22, 33, 34, 35, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 94, 96, 98, 99, 100, 101, 102, 103, 104, 105, 106, 109, 110, 111, 112, 113, 114, 176, 187], "found": [1, 6, 14, 19, 22, 33, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 137, 142, 150, 176], "alexand": [1, 176], "barach": [1, 5, 18, 22, 30, 34, 47, 61, 62, 63, 176, 187], "vinai": [1, 9, 42, 47, 176, 187], "jayaram": [1, 9, 42, 47, 176, 187], "expert": [1, 176], "At": [1, 68, 69, 70, 75, 96, 99, 100, 105, 176], "moment": [1, 176], "scientist": [1, 176], "special": [1, 176], "acknowledg": [1, 176, 187], "pedro": [1, 23, 24, 36, 39, 44, 45, 46, 47, 62, 64, 65, 66, 67, 80, 176, 187], "rodrigu": [1, 23, 24, 36, 39, 44, 45, 46, 47, 62, 63, 64, 65, 66, 67, 80, 81, 176, 187], "whatev": [1, 44, 176], "expertis": [1, 176], "program": [1, 92, 176], "user": [1, 33, 39, 44, 61, 62, 63, 64, 65, 66, 67, 71, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 95, 96, 97, 98, 101, 104, 105, 106, 107, 122, 151, 152, 153, 155, 156, 157, 158, 159, 160, 176, 177, 178, 180, 182], "experi": [1, 24, 47, 48, 52, 53, 62, 63, 64, 65, 66, 67, 70, 72, 76, 77, 78, 79, 80, 81, 82, 85, 88, 89, 90, 91, 92, 93, 94, 98, 99, 100, 101, 102, 103, 104, 105, 176], "softwar": [1, 22, 47, 176], "sustain": [1, 69, 73, 96, 176], "technic": [1, 62, 63, 64, 65, 66, 67, 80, 92, 176], "write": [1, 7, 28, 33, 176], "love": [1, 176], "feedback": [1, 68, 69, 70, 71, 73, 82, 86, 89, 91, 102, 103, 176], "primari": [1, 83, 176], "goal": [1, 44, 132, 133, 176], "excit": [1, 176], "profession": [1, 176], "try": [1, 33, 106, 153, 176, 179], "collabor": [1, 65, 176], "translat": [1, 176], "skill": [1, 176], "digit": [1, 63, 71, 100, 176], "enhanc": [1, 44, 76, 77, 78, 79, 89, 153, 176], "becaus": [1, 5, 14, 19, 29, 30, 33, 34, 35, 36, 39, 63, 86, 107, 129, 145, 176], "get": [1, 12, 14, 19, 25, 36, 43, 60, 61, 62, 63, 64, 65, 66, 67, 68, 75, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 116, 121, 122, 124, 126, 129, 139, 143, 148, 150, 174, 176, 177, 182, 187], "right": [1, 9, 18, 30, 31, 34, 35, 39, 44, 45, 61, 68, 69, 70, 71, 72, 73, 74, 75, 82, 85, 86, 88, 90, 91, 96, 97, 98, 99, 100, 105, 106, 135, 139, 176, 179], "less": [1, 63, 64, 66, 84, 176], "formal": [1, 176], "exchang": [1, 176], "idea": [1, 176, 182], "reach": [1, 33, 83, 176], "channel": [1, 8, 14, 23, 29, 31, 34, 35, 37, 39, 42, 61, 70, 71, 73, 75, 82, 83, 86, 89, 90, 91, 92, 93, 94, 97, 99, 100, 101, 103, 104, 107, 122, 124, 125, 126, 127, 128, 129, 131, 132, 133, 134, 137, 138, 140, 142, 143, 144, 145, 146, 148, 149, 150, 151, 176, 187], "weekli": [1, 176], "offic": [1, 176], "hour": [1, 176], "video": [1, 62, 63, 99, 100, 176], "meet": [1, 176], "happen": [1, 176], "regular": [1, 153, 154, 176, 187], "basi": [1, 99, 176], "link": [1, 72, 80, 99, 100, 176, 187], "slack": [1, 176], "dank": [], "sch\u00f6n": [], "merci": [], "beaucoup": [], "hope": [], "amaz": [], "journei": [], "A": [1, 3, 22, 26, 27, 29, 34, 41, 42, 47, 48, 49, 56, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 75, 81, 82, 83, 85, 87, 88, 89, 93, 94, 95, 96, 97, 99, 100, 101, 104, 106, 107, 109, 110, 111, 112, 114, 129, 145, 151, 152, 153, 156, 157, 158, 168, 176, 181, 184], "handl": [3, 27, 48, 49, 56, 57, 58, 59, 101, 181, 187], "low": [3, 12, 25, 26, 27, 28, 29, 34, 48, 49, 72, 96, 101, 103, 116, 138, 140, 142, 143, 148, 181], "level": [3, 33, 42, 48, 49, 61, 62, 63, 64, 65, 66, 67, 70, 80, 81, 82, 83, 84, 85, 88, 92, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 132, 133, 174, 181, 182, 183], "access": [3, 7, 26, 31, 34, 37, 48, 49, 99, 100, 145, 156, 177, 181], "data": [3, 5, 6, 8, 9, 11, 14, 16, 18, 19, 22, 25, 26, 27, 28, 29, 30, 32, 34, 35, 36, 38, 42, 44, 45, 46, 49, 57, 58, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 88, 89, 91, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 115, 116, 121, 122, 123, 128, 129, 131, 132, 133, 134, 137, 138, 139, 140, 142, 143, 145, 146, 148, 149, 150, 151, 152, 153, 165, 166, 168, 171, 172, 174, 181, 184, 187], "store": [3, 7, 12, 22, 31, 37, 39, 44, 48, 49, 60, 61, 62, 63, 64, 65, 66, 67, 71, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 126, 127, 128, 129, 181, 187], "thei": [3, 5, 9, 29, 33, 35, 39, 42, 44, 48, 49, 60, 69, 70, 88, 99, 100, 102, 108, 151, 152, 181, 182], "been": [3, 7, 11, 33, 39, 48, 49, 61, 89, 92, 93, 94, 105, 155, 156, 157, 158, 159, 160, 168, 179, 181], "convert": [3, 16, 24, 29, 33, 34, 38, 48, 49, 61, 72, 162, 167, 174, 181, 184, 187], "mne": [3, 4, 5, 8, 9, 10, 11, 16, 18, 19, 22, 26, 27, 29, 30, 31, 33, 34, 35, 36, 37, 39, 44, 45, 46, 48, 49, 57, 59, 61, 62, 63, 64, 65, 66, 67, 72, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 126, 127, 128, 129, 131, 132, 133, 134, 137, 138, 140, 141, 142, 143, 145, 146, 148, 149, 150, 173, 174, 181, 182, 187], "raw": [3, 22, 25, 28, 33, 34, 35, 39, 44, 48, 49, 61, 81, 107, 108, 123, 126, 127, 128, 129, 131, 134, 138, 145, 165, 181, 184, 187], "object": [3, 5, 12, 16, 21, 22, 25, 33, 38, 42, 44, 46, 48, 49, 60, 68, 71, 72, 85, 107, 108, 136, 139, 140, 143, 148, 151, 152, 153, 155, 156, 157, 158, 159, 160, 181, 187], "There": [3, 8, 9, 48, 49, 61, 73, 88, 94, 177, 181], "pool": [3, 48, 49, 181], "record": [3, 33, 34, 39, 42, 45, 48, 49, 50, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 131, 134, 138, 181, 187], "session": [3, 4, 5, 7, 8, 9, 10, 13, 15, 16, 17, 20, 22, 32, 34, 35, 38, 39, 41, 42, 44, 48, 49, 50, 60, 61, 63, 64, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 122, 124, 126, 127, 128, 129, 139, 140, 141, 142, 143, 145, 148, 174, 175, 181, 182, 183, 187], "subject": [3, 4, 5, 6, 7, 8, 9, 12, 14, 16, 18, 19, 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 42, 44, 45, 46, 48, 49, 50, 52, 53, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 109, 110, 111, 112, 113, 114, 122, 123, 124, 126, 127, 128, 129, 137, 142, 145, 174, 181, 183, 187], "see": [3, 6, 22, 33, 34, 35, 42, 48, 49, 61, 62, 63, 64, 65, 66, 67, 70, 74, 80, 81, 82, 83, 84, 85, 88, 89, 90, 91, 95, 96, 97, 98, 101, 103, 104, 105, 106, 107, 108, 115, 116, 122, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 178, 179, 181], "electrod": [3, 4, 10, 16, 39, 45, 48, 49, 57, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 89, 90, 91, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 125, 128, 129, 139, 143, 148, 153], "number": [3, 9, 14, 16, 17, 18, 19, 24, 25, 28, 29, 33, 34, 35, 39, 41, 44, 45, 47, 48, 49, 52, 53, 60, 61, 62, 63, 64, 65, 66, 67, 72, 80, 81, 82, 83, 84, 85, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 104, 105, 106, 107, 122, 123, 126, 127, 128, 129, 132, 133, 136, 137, 140, 142, 145, 150, 151, 152, 153, 176, 182, 187], "trial": [3, 16, 17, 34, 38, 39, 42, 44, 45, 48, 49, 50, 61, 63, 68, 69, 70, 71, 73, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 153, 181, 184, 187], "etc": [3, 44, 45, 48, 49, 50, 63, 85, 101, 181], "defin": [3, 6, 7, 9, 14, 18, 19, 21, 22, 24, 25, 28, 29, 30, 32, 34, 36, 39, 41, 42, 44, 50, 60, 86, 87, 94, 107, 122, 129, 131, 132, 133, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145, 146, 148, 149, 150, 151, 172, 181, 184, 185, 187], "how": [3, 6, 7, 8, 9, 11, 12, 14, 16, 17, 18, 19, 21, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 45, 48, 50, 58, 60, 74, 85, 86, 106, 139, 143, 148, 151, 152, 153, 155, 156, 157, 158, 159, 160, 174, 181, 182, 183, 184], "gener": [3, 5, 6, 7, 8, 11, 12, 14, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 50, 56, 57, 63, 97, 99, 100, 104, 107, 122, 126, 127, 128, 129, 151, 174, 181, 183], "auc": [3, 5, 6, 7, 9, 14, 18, 19, 24, 30, 31, 32, 34, 36, 37, 50, 63, 109, 110, 111, 112, 113, 114, 132, 133, 135, 136, 137, 139, 140, 141, 142, 144, 146, 149, 181], "f": [3, 6, 7, 8, 9, 11, 14, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 39, 42, 50, 70, 71, 72, 74, 135, 136, 139, 140, 141, 144, 146, 149, 181], "accuraci": [3, 6, 18, 19, 21, 29, 32, 34, 37, 50, 63, 82, 132, 133, 135, 136, 137, 139, 140, 141, 142, 144, 146, 149, 150, 181, 183], "within": [3, 4, 8, 9, 10, 13, 15, 16, 17, 20, 23, 26, 27, 29, 34, 35, 38, 42, 50, 60, 68, 70, 72, 87, 94, 98, 102, 103, 104, 107, 126, 127, 128, 129, 136, 139, 140, 141, 142, 143, 148, 172, 174, 181, 183], "across": [3, 5, 7, 14, 18, 19, 25, 30, 42, 50, 55, 56, 126, 181, 183, 187], "transfer": [3, 50, 101, 181], "decod": [3, 4, 5, 7, 8, 9, 16, 18, 19, 26, 27, 30, 31, 33, 34, 36, 44, 45, 46, 86, 87, 96, 98, 132, 133, 155, 157, 160, 181, 184], "function": [3, 8, 12, 14, 18, 19, 22, 24, 25, 26, 27, 28, 32, 34, 36, 39, 42, 52, 53, 88, 101, 107, 115, 116, 129, 145, 150, 152, 165, 167, 172, 181, 182, 184, 187], "us": [3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 46, 47, 48, 53, 54, 55, 62, 63, 65, 66, 67, 71, 75, 76, 77, 78, 79, 82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 108, 116, 122, 132, 133, 144, 145, 146, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 166, 168, 172, 177, 178, 179, 181, 182, 183, 184, 187], "two": [3, 5, 6, 8, 9, 18, 19, 24, 26, 27, 30, 31, 32, 33, 34, 35, 36, 41, 42, 45, 46, 56, 63, 68, 70, 71, 72, 75, 82, 84, 85, 89, 96, 97, 98, 99, 100, 101, 102, 104, 106, 126, 145, 154, 180, 181, 184], "class": [3, 7, 14, 16, 17, 18, 19, 24, 29, 30, 32, 34, 36, 37, 40, 43, 44, 45, 48, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 122, 123, 126, 127, 128, 129, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 171, 181, 182, 184, 187], "multi": [3, 24, 34, 65, 67, 151, 181, 184], "continu": [3, 34, 42, 63, 76, 77, 78, 79, 98, 99, 104, 178, 181, 184], "similarli": [3, 34, 102, 181, 184], "necessari": [3, 9, 18, 30, 32, 33, 34, 36, 44, 129, 153, 181, 184], "v": [1, 3, 9, 18, 26, 27, 29, 34, 47, 48, 58, 64, 65, 66, 67, 83, 92, 158, 168, 176, 181, 184], "erd": [3, 34, 73, 181, 184], "predict": [3, 24, 71, 72, 83, 132, 133, 151, 152, 153, 181, 185], "typic": [3, 89, 181, 185], "chain": [3, 181, 185], "sklearn": [3, 5, 6, 7, 8, 9, 14, 18, 19, 21, 24, 25, 28, 29, 30, 31, 32, 36, 37, 39, 41, 42, 44, 45, 46, 129, 135, 136, 139, 140, 141, 144, 146, 149, 151, 152, 153, 155, 156, 157, 158, 159, 160, 166, 167, 172, 181, 185, 187], "compat": [3, 34, 35, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 122, 126, 127, 128, 129, 131, 135, 136, 139, 140, 141, 144, 145, 146, 149, 163, 171, 178, 179, 181, 185, 187], "transform": [3, 7, 9, 14, 18, 19, 24, 30, 32, 35, 36, 152, 153, 161, 162, 163, 164, 172, 181, 185, 187], "end": [3, 24, 25, 33, 34, 35, 39, 44, 45, 46, 73, 75, 85, 89, 91, 93, 94, 96, 99, 100, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 179, 181, 185], "estim": [3, 5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 83, 91, 95, 109, 110, 111, 112, 113, 114, 126, 127, 128, 129, 151, 152, 153, 155, 156, 157, 158, 159, 160, 162, 166, 181, 185], "These": [4, 13, 16, 17, 71, 76, 77, 78, 79, 89, 93, 94, 102, 103, 107, 151, 152, 153], "show": [4, 5, 7, 8, 9, 14, 16, 18, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 44, 45, 46, 56, 60, 68, 84, 86, 96, 98, 99, 100, 106, 139, 174, 187], "variou": [4, 13, 16, 101, 182], "topic": [4, 16, 182], "scikit": [4, 16, 25, 29, 37, 38, 42, 44, 163, 165, 174, 175, 187], "input": [4, 7, 12, 16, 27, 29, 34, 60, 107, 129, 145, 166, 167, 172], "select": [4, 5, 6, 9, 10, 16, 18, 23, 24, 28, 30, 31, 34, 37, 48, 57, 60, 68, 70, 71, 72, 81, 89, 92, 98, 106, 107, 109, 110, 111, 112, 114, 119, 123, 124, 125, 128, 129, 131, 132, 133, 134, 137, 138, 139, 140, 142, 143, 145, 146, 148, 149, 150, 153, 172, 187], "resampl": [4, 10, 14, 16, 19, 33, 34, 35, 36, 57, 68, 106, 107, 125, 128, 129, 131, 132, 133, 134, 137, 138, 139, 140, 142, 143, 144, 145, 146, 148, 149, 150], "filterbank": [4, 10, 16, 32, 68, 107, 126, 129, 133, 135, 139, 143, 148, 153, 162, 174], "approach": [4, 16, 25, 83, 153, 162], "motor": [4, 16, 17, 20, 22, 26, 31, 32, 34, 38, 40, 43, 61, 68, 69, 70, 73, 75, 82, 85, 96, 97, 98, 99, 100, 105, 106, 107, 124, 126, 128, 129, 131, 135, 136, 139, 140, 143, 145, 146, 148, 149, 156, 159, 170, 174, 175, 181, 187], "imageri": [4, 9, 16, 17, 20, 22, 25, 26, 31, 32, 34, 38, 39, 40, 42, 43, 61, 68, 69, 70, 73, 75, 82, 85, 90, 96, 97, 99, 105, 106, 107, 122, 124, 126, 128, 129, 131, 135, 136, 139, 140, 143, 145, 146, 148, 149, 156, 159, 170, 174, 175, 181, 187], "statist": [4, 7, 10, 16, 42, 50, 51, 52, 53, 54, 56, 57, 58, 59, 68, 101, 107, 126, 129, 139, 143, 148, 174], "meta": [4, 7, 9, 16, 31, 37, 39, 44, 52, 53, 54, 56, 151, 152, 153, 155, 156, 157, 158, 159, 160, 187], "analysi": [4, 7, 8, 10, 12, 14, 16, 18, 19, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 36, 37, 38, 44, 46, 60, 68, 71, 80, 85, 92, 95, 107, 126, 129, 139, 143, 148, 151, 152, 153, 174, 181, 182, 183, 187], "gridsearch": [4, 10, 16, 28, 68, 107, 128, 129, 140, 143, 148, 187], "csp": [4, 8, 9, 10, 12, 16, 18, 21, 25, 28, 30, 31, 44, 45, 46, 68, 107, 126, 129, 135, 139, 143, 148, 166, 174, 187], "versu": [4, 9, 10, 16, 30, 63, 65, 67, 68, 73, 83, 107, 126, 129, 135, 139, 143, 148, 174], "epoch": [4, 6, 8, 9, 10, 14, 16, 18, 19, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42, 44, 48, 57, 59, 60, 71, 72, 76, 77, 78, 81, 86, 102, 103, 104, 107, 108, 126, 127, 128, 129, 131, 132, 133, 134, 137, 138, 140, 141, 142, 143, 144, 145, 146, 148, 149, 150, 155, 156, 157, 158, 159, 160, 174, 187], "click": [5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46], "full": [5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 60, 62, 64, 65, 66, 67, 80, 81, 102, 103, 179], "comparison": [5, 7, 9, 46, 87, 95, 181, 183], "2a": [5, 18, 30, 44], "bci": [5, 18, 24, 30, 34, 39, 41, 44, 45, 46, 47, 48, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 76, 77, 78, 79, 81, 82, 83, 85, 88, 89, 90, 91, 92, 95, 97, 101, 102, 103, 104, 152, 161, 183, 187], "competit": [5, 18, 30, 34, 44, 67, 68, 70, 187], "iv": [5, 18, 30, 34, 44, 68, 187], "author": [1, 5, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 47, 80, 153, 155, 156, 157, 158, 159, 160, 168, 176], "alexandr": [1, 5, 18, 22, 30, 34, 47, 62, 63, 176, 187], "gmail": [5, 9, 11, 12, 18, 22, 23, 24, 27, 29, 30, 33, 34, 35, 36, 42], "com": [5, 9, 11, 12, 18, 22, 23, 24, 27, 29, 30, 33, 34, 35, 36, 39, 41, 42, 44, 45, 46, 47, 92, 93, 94, 153, 176, 179], "licens": [5, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 42, 99, 100, 182], "bsd": [5, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 42], "3": [5, 7, 8, 9, 10, 11, 12, 14, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 48, 60, 61, 63, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 82, 83, 84, 85, 86, 87, 88, 90, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 106, 107, 122, 128, 129, 139, 143, 148, 151, 152, 153, 155, 156, 157, 158, 159, 160, 174, 177, 178], "claus": [5, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 42], "matplotlib": [5, 6, 7, 8, 9, 14, 18, 19, 23, 25, 26, 27, 28, 29, 30, 31, 32, 35, 36, 37, 44, 45, 46], "pyplot": [5, 6, 7, 8, 9, 12, 14, 18, 19, 23, 25, 26, 27, 28, 29, 30, 31, 32, 35, 36, 37, 44, 45, 46, 56, 57, 58, 59], "plt": [5, 6, 7, 8, 9, 14, 18, 19, 23, 25, 26, 27, 28, 29, 30, 31, 32, 35, 36, 37, 44, 45, 46], "panda": [5, 7, 12, 24, 25, 26, 27, 28, 32, 42, 44, 45, 46], "pd": [5, 7, 24, 32, 34, 44, 129, 145], "seaborn": [5, 6, 14, 18, 19, 29, 30, 31, 32, 36, 37, 44, 45, 46], "sn": [5, 6, 14, 18, 19, 29, 30, 31, 32, 36, 37, 44, 45, 46], "discriminant_analysi": [5, 8, 9, 14, 18, 19, 30, 31, 36, 42, 44, 45, 46], "lineardiscriminantanalysi": [5, 8, 9, 14, 18, 19, 30, 31, 36, 42, 44, 45, 46], "lda": [5, 8, 9, 12, 14, 18, 19, 28, 30, 31, 36, 42, 44, 45, 46, 166], "make_pipelin": [5, 7, 8, 9, 14, 18, 19, 21, 24, 29, 30, 31, 32, 36, 37, 39, 41, 42, 44, 45, 46, 166], "bnci2014_001": [5, 6, 8, 9, 12, 18, 26, 27, 29, 30, 31, 34, 42, 44, 45, 46, 48, 183], "crosssessionevalu": [5, 7, 9, 29, 30, 31, 42, 44, 187], "paradigm": [5, 6, 7, 9, 12, 14, 16, 18, 19, 23, 24, 25, 26, 27, 28, 29, 30, 33, 35, 36, 38, 39, 41, 45, 46, 60, 63, 64, 65, 66, 67, 68, 70, 71, 72, 75, 81, 84, 89, 90, 91, 96, 99, 100, 101, 107, 122, 123, 124, 126, 127, 128, 129, 130, 151, 166, 183, 187], "filterbankleftrightimageri": 5, "leftrightimageri": [5, 8, 9, 12, 18, 25, 26, 27, 28, 30, 31, 33, 34, 39, 42, 44, 45, 46, 60], "util": [5, 8, 9, 11, 21, 26, 27, 29, 41, 42, 71, 86, 92, 102, 103, 107, 151, 152, 153, 155, 156, 157, 158, 159, 160, 181, 187], "set_log_level": [5, 7, 9, 12, 14, 18, 19, 21, 22, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 42, 44, 45, 46], "info": [5, 7, 9, 12, 14, 18, 19, 21, 22, 25, 26, 27, 28, 30, 31, 32, 33, 35, 36, 37, 39, 42, 44, 45, 46, 83, 174, 181], "8": [5, 6, 9, 10, 14, 18, 19, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 42, 43, 44, 45, 46, 48, 61, 63, 69, 71, 72, 73, 74, 75, 82, 83, 84, 88, 89, 90, 91, 92, 93, 94, 95, 96, 100, 103, 104, 105, 134, 140, 147, 148, 168, 169, 177, 178, 187], "compon": [5, 9, 18, 30, 31, 32, 42, 97, 98, 153], "usual": [5, 9, 18, 30, 33, 92, 172, 178], "second": [5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 56, 61, 63, 68, 69, 70, 73, 75, 88, 92, 93, 94, 96, 98, 101, 102, 103, 105, 122, 124, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 187], "filter": [5, 6, 7, 23, 24, 25, 31, 32, 34, 35, 37, 44, 63, 68, 70, 71, 72, 73, 75, 85, 101, 104, 131, 132, 133, 134, 135, 136, 137, 138, 140, 142, 143, 144, 145, 146, 147, 148, 149, 150, 152, 153, 154, 162, 166, 170, 187], "bank": [5, 32, 34, 35, 131, 133, 134, 135, 136, 137, 145, 146, 147, 149, 150, 153, 166], "up": [5, 9, 21, 26, 27, 29, 33, 42, 44, 45, 46, 48, 64, 68, 70, 71, 85, 91, 96, 182], "4": [5, 6, 8, 9, 14, 18, 19, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36, 37, 38, 40, 41, 42, 43, 44, 45, 48, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 81, 82, 84, 85, 86, 87, 88, 89, 90, 91, 92, 94, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 115, 122, 128, 139, 151, 153, 154, 181], "compens": 5, "higher": [5, 59, 92, 161, 187], "dimension": [5, 161], "dict": [5, 9, 14, 18, 19, 22, 30, 32, 33, 34, 35, 36, 58, 81, 107, 108, 117, 118, 119, 120, 121, 123, 126, 127, 128, 129, 145, 151, 152, 153, 167], "n_compon": [5, 7, 8, 9, 18, 30, 31, 44, 45, 46, 187], "pipelines_fb": [5, 32], "fbcsp": 5, "sinc": [5, 21, 27, 29, 44, 63], "match": [5, 107, 124, 126, 127, 128, 129, 145, 187], "fair": 5, "standard": [5, 9, 22, 25, 26, 29, 42, 44, 55, 56, 71, 72, 83, 84, 85, 96, 128, 165, 183, 187], "35": [5, 6, 14, 19, 23, 27, 31, 33, 34, 42, 64, 65, 66, 67, 87, 104, 145, 146, 149], "hz": [5, 8, 23, 24, 31, 32, 34, 37, 39, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 82, 83, 84, 85, 89, 90, 91, 92, 93, 94, 99, 100, 101, 102, 103, 104, 132, 138, 140, 142, 143, 145, 148], "broadband": 5, "rang": [5, 6, 39, 86, 87, 101, 104], "being": [5, 30, 44, 98], "auto": [5, 14, 18, 19, 30, 32, 36], "subject_list": [5, 6, 7, 8, 9, 12, 14, 18, 19, 24, 26, 27, 29, 30, 31, 32, 36, 37, 39, 42, 44, 45, 46, 107, 187], "overwrit": [5, 6, 7, 8, 9, 12, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 32, 33, 36, 37, 39, 41, 42, 44, 45, 46, 60, 108, 126, 127, 128, 129, 187], "true": [5, 6, 7, 8, 9, 12, 14, 18, 19, 21, 22, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 41, 44, 59, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 95, 96, 97, 98, 99, 100, 101, 104, 105, 106, 107, 108, 116, 122, 124, 126, 127, 128, 129, 145, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 166], "cach": [5, 9, 12, 14, 16, 18, 19, 22, 25, 26, 27, 28, 30, 31, 32, 34, 36, 37, 38, 44, 45, 60, 106, 107, 108, 139, 143, 145, 148, 174, 187], "fmin": [5, 6, 23, 29, 31, 32, 34, 35, 37, 42, 132, 138, 140, 142, 143, 148], "fmax": [5, 6, 23, 29, 31, 32, 34, 35, 37, 42, 132, 138, 140, 142, 143, 148], "suffix": [5, 7, 8, 9, 14, 18, 19, 29, 30, 31, 36, 37, 39, 41, 42, 126, 127, 128, 129], "process": [5, 6, 7, 8, 9, 14, 16, 18, 19, 22, 24, 25, 29, 30, 31, 32, 34, 36, 37, 38, 39, 41, 42, 44, 45, 46, 60, 83, 87, 92, 99, 105, 106, 107, 126, 127, 128, 129, 130, 131, 134, 138, 139, 140, 143, 145, 148, 150, 174, 181, 187], "24": [5, 6, 8, 9, 18, 24, 26, 27, 29, 30, 31, 34, 42, 48, 63, 82, 86, 134, 143, 147, 149, 152], "16": [5, 9, 14, 23, 27, 28, 37, 38, 46, 48, 61, 62, 63, 64, 72, 80, 81, 83, 88, 89, 90, 91, 103, 134, 147], "32": [5, 34, 48, 65, 66, 67, 76, 77, 78, 79, 84, 88, 134, 140, 147, 148], "results_fb": [5, 32], "bnci2014": [5, 6, 7, 8, 9, 14, 18, 19, 21, 25, 26, 27, 29, 30, 31, 34, 36, 42, 44, 45, 46], "001": [5, 6, 8, 9, 18, 21, 25, 26, 27, 29, 30, 31, 34, 42, 44, 45, 46, 68, 73], "crosssess": [5, 7, 9, 27, 29, 30, 31, 42, 60], "00": [5, 6, 7, 8, 9, 10, 14, 18, 19, 20, 25, 26, 27, 28, 29, 30, 31, 36, 37, 38, 42, 43, 44, 45, 46, 92, 93, 94], "alreadi": [5, 25, 28, 41, 85, 177, 182], "home": [6, 7, 8, 9, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42, 180], "runner": [6, 7, 8, 9, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42], "py": [5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 60, 81, 141], "273": [6, 7, 8, 9, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42], "userwarn": [6, 7, 8, 9, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42], "warnepoch": [6, 7, 8, 9, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42], "event": [6, 7, 8, 9, 14, 18, 19, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 39, 42, 62, 72, 81, 86, 87, 94, 104, 107, 122, 124, 131, 132, 133, 134, 136, 137, 138, 140, 142, 143, 144, 145, 146, 148, 149, 150, 187], "good": [6, 7, 8, 9, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42], "6": [1, 6, 7, 8, 9, 14, 18, 22, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 42, 44, 45, 46, 47, 48, 62, 64, 65, 66, 67, 68, 71, 72, 84, 85, 86, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 102, 103, 104, 145, 151, 176], "baselin": [6, 7, 8, 9, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42, 97, 99, 100, 131, 132, 133, 134, 137, 138, 140, 142, 143, 144, 145, 146, 148, 149, 150, 187], "off": [6, 7, 8, 9, 14, 18, 19, 23, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42, 71, 132, 133], "mb": [5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46], "load": [8, 9, 14, 16, 18, 19, 26, 27, 28, 29, 30, 33, 34, 35, 36, 38, 42, 44, 60, 89, 90, 91, 101, 103, 104, 165, 171, 174, 175, 187], "left_hand": [6, 8, 9, 18, 25, 26, 27, 28, 29, 30, 31, 33, 34, 39, 42, 107], "12": [6, 8, 9, 14, 15, 18, 24, 26, 27, 29, 30, 31, 34, 42, 45, 46, 48, 63, 68, 76, 77, 78, 79, 80, 81, 83, 86, 87, 88, 89, 91, 92, 93, 94, 95, 96, 99, 100, 102, 105, 123, 133, 134, 147], "right_hand": [6, 8, 9, 18, 25, 26, 27, 28, 29, 30, 31, 33, 34, 39, 42, 107], "warn": [6, 7, 8, 9, 14, 18, 19, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 42, 44, 45, 46, 68, 70, 173, 174, 187], "50": [8, 9, 18, 23, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 42, 48, 68, 69, 70, 73, 75, 82, 83, 91, 92, 93, 94, 99, 100, 101, 104], "05": [7, 19, 25, 31, 59, 102], "77": [27, 46, 69, 87], "100": [6, 7, 8, 9, 14, 16, 17, 18, 19, 23, 25, 26, 27, 28, 29, 30, 31, 35, 36, 37, 42, 44, 45, 46, 48, 68, 70, 73, 75, 76, 77, 78, 79, 82, 84, 86, 87, 90, 91, 92, 93, 94, 187], "11": [10, 18, 19, 25, 26, 27, 48, 72, 76, 77, 78, 79, 81, 92, 93, 94, 98, 106, 155, 160, 178, 187], "55": [8, 25, 26, 43, 46, 68], "59": [8, 25, 28, 31, 33, 48, 187], "after": [5, 23, 32, 33, 34, 60, 62, 65, 68, 76, 77, 78, 79, 81, 82, 85, 86, 87, 89, 90, 91, 99, 100, 101, 104, 105, 129, 132, 133, 137, 140, 142, 143, 145, 146, 148, 149, 150, 180], "simpli": [5, 22, 32, 33, 42], "concaten": [5, 26, 27, 29, 32, 34, 35, 127, 166], "concat": [5, 7, 32], "via": [5, 6, 42, 44, 55, 72, 177, 178, 181, 187], "displai": [5, 32, 69, 80, 81, 84, 85, 89, 96, 98, 99, 100], "pointplot": [5, 6, 14, 18, 19, 30, 32, 36], "averag": [5, 14, 23, 30, 37, 52, 53, 84, 85, 86, 153], "each": [5, 6, 7, 8, 9, 14, 16, 17, 18, 19, 21, 23, 24, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 42, 44, 46, 52, 53, 54, 55, 59, 61, 63, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 122, 123, 126, 127, 128, 129, 132, 133, 136, 137, 140, 142, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 166, 183, 187], "pair": [5, 30, 33, 55, 57, 65, 67, 99, 100], "scatter": [5, 30], "repres": [5, 30, 71], "singl": [5, 9, 18, 21, 22, 30, 31, 36, 37, 39, 41, 42, 75, 87, 89, 92, 93, 94, 99, 100, 102, 103, 107, 126, 127, 128, 129, 132, 142, 143, 148, 153], "its": [5, 16, 22, 30, 33, 44, 83, 84, 88, 93, 94, 172, 183, 187], "quadrant": [5, 30], "fig": [5, 6, 8, 9, 14, 18, 19, 23, 30, 32, 35, 36, 44, 56, 57, 58, 59, 86, 89, 90, 91, 96, 99, 100, 105], "ax": [5, 6, 7, 14, 18, 19, 23, 30, 32, 36, 37, 44], "subplot": [5, 6, 14, 18, 19, 23, 30, 32, 36, 44], "figsiz": [5, 6, 14, 18, 19, 23, 30, 32, 36, 44], "sharei": [5, 6, 30], "stripplot": [5, 6, 9, 25, 27, 28, 30, 32, 36], "y": [1, 5, 6, 7, 9, 14, 18, 19, 23, 24, 26, 29, 30, 31, 32, 34, 36, 37, 44, 45, 46, 47, 83, 89, 90, 91, 104, 151, 152, 153, 154, 157, 162, 163, 164, 176, 187], "x": [5, 6, 7, 8, 9, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 39, 42, 44, 45, 46, 59, 76, 77, 78, 79, 91, 93, 94, 102, 103, 104, 106, 145, 151, 152, 153, 154, 157, 159, 162, 163, 164, 165, 170, 172], "jitter": [5, 6, 30, 32, 36, 72], "alpha": [5, 6, 30, 32, 36, 153, 154], "zorder": [5, 6, 30, 32, 36], "palett": [5, 6, 9, 14, 18, 19, 25, 27, 28, 29, 30, 31, 32, 36, 37, 44, 45, 46], "set1": [5, 6, 14, 18, 19, 30, 32, 36], "set_ylabel": [5, 6, 14, 18, 19, 23, 30, 32, 36, 37], "roc": [5, 6, 7, 14, 18, 19, 30, 34, 36, 132, 133, 135, 136, 137, 139, 140, 141, 142, 144, 146, 149], "set_ylim": [5, 23, 30, 32, 36], "pivot_t": [5, 30], "valu": [5, 6, 9, 14, 18, 19, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 41, 42, 51, 53, 54, 55, 59, 93, 94, 104, 117, 118, 120, 126, 127, 128, 129, 132, 133, 137, 140, 142, 143, 145, 146, 148, 149, 150, 153, 172], "column": [5, 8, 18, 24, 29, 30, 31, 34, 35, 37, 42, 51, 57, 71, 72, 89, 145, 187], "index": [5, 30, 51, 82, 89, 90, 91, 104, 177], "reset_index": [5, 14, 18, 19, 30], "regplot": [5, 30], "fit_reg": [5, 30], "l": [1, 5, 26, 27, 30, 39, 44, 45, 46, 47, 62, 63, 64, 65, 66, 67, 71, 80, 81, 97, 106, 155, 159, 160, 170, 176, 187], "c": [1, 5, 8, 14, 22, 26, 27, 29, 30, 39, 42, 44, 45, 46, 47, 62, 63, 64, 65, 66, 67, 68, 70, 73, 74, 76, 77, 78, 79, 80, 81, 82, 97, 99, 100, 102, 103, 132, 133, 158, 168, 176, 187], "k": [5, 22, 26, 27, 30, 68, 84, 86, 87, 88, 89, 90, 91, 97, 99, 100, 128, 155, 160, 187], "set_xlim": [5, 23, 30], "total": [5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 63, 65, 67, 68, 69, 70, 71, 76, 77, 78, 79, 85, 86, 92, 93, 94, 101, 102, 104], "script": [5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 180, 187], "minut": [5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 82, 84, 86, 93, 94, 97, 101, 104, 105, 106], "13": [6, 8, 9, 10, 14, 25, 27, 29, 32, 44, 48, 69, 86, 87, 94, 98, 101, 187], "314": [], "memori": [5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46], "usag": [5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46, 172, 187], "359": 187, "sourc": [5, 6, 7, 8, 9, 11, 12, 14, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 177, 187], "plot_filterbank_csp_vs_csp": [5, 10], "jupyt": [5, 6, 7, 8, 9, 11, 12, 14, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 182], "notebook": [5, 6, 7, 8, 9, 11, 12, 14, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46, 182], "ipynb": [5, 6, 7, 8, 9, 11, 12, 14, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 44, 45, 46], "sphinx": [5, 6, 7, 8, 9, 11, 12, 14, 16, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 44, 45, 46], "demonstr": [6, 8, 11, 16, 17, 23, 24], "grid": [6, 12, 16, 38, 58, 60, 64, 65, 66, 67, 102, 103, 172, 174], "search": [6, 8, 16, 38, 42, 58, 60, 172, 174, 187], "compar": [6, 7, 8, 14, 18, 19, 24, 30, 32, 33, 36, 44, 56, 59, 81, 92, 153], "vanilla": 6, "tune": 6, "pickl": [6, 21], "pyriemann": [6, 7, 8, 9, 14, 18, 19, 24, 25, 30, 32, 36, 39, 41, 46], "covari": [6, 7, 8, 9, 14, 18, 19, 25, 30, 32, 33, 39, 46, 153, 161, 162], "tangentspac": [6, 7, 8, 9, 14, 18, 19, 30, 32, 36, 46], "linear_model": [6, 7, 8, 9, 18, 30, 32], "logisticregress": [6, 7, 8, 9, 18, 30, 32], "withinsessionevalu": [6, 8, 14, 18, 19, 36, 37, 39, 41, 44, 45, 46, 187], "motorimageri": [6, 29, 35, 60, 187], "initi": [1, 6, 21, 47, 63, 94, 100, 101, 102, 145, 176], "band": [6, 71, 75, 102, 145, 153, 166], "pass": [6, 7, 30, 33, 34, 63, 71, 72, 75, 83, 85, 122, 128, 138, 140, 142, 143, 148, 151, 152, 153, 155, 156, 157, 158, 159, 160, 172, 187], "tmax": [6, 24, 29, 34, 132, 133, 137, 140, 142, 143, 144, 145, 146, 148, 149, 150, 151], "none": [6, 7, 25, 28, 29, 32, 33, 34, 35, 39, 41, 44, 58, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 108, 115, 116, 119, 121, 122, 123, 124, 126, 127, 128, 129, 130, 131, 132, 133, 134, 137, 138, 140, 142, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 171, 172, 173, 175, 187], "n_class": [6, 29, 32, 34, 37, 132, 133, 136, 137, 140, 142, 150, 151, 152, 153, 187], "len": [6, 7, 14, 18, 19, 22, 26, 29, 35, 39, 61, 82, 85, 90, 96, 97, 98, 99, 100, 105, 106, 153], "path": [6, 11, 22, 33, 39, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 108, 115, 116, 122, 126, 127, 128, 129, 155, 156, 157, 158, 159, 160, 173, 180, 187], "folder": [6, 11, 12, 25, 26, 27, 28, 33, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 180], "str": [6, 34, 39, 44, 45, 46, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 119, 121, 122, 124, 126, 127, 128, 129, 131, 132, 133, 134, 136, 137, 138, 140, 142, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 172, 173], "makedir": 6, "exist_ok": 6, "elast": 6, "net": [6, 16, 38, 58, 60, 68, 70, 92, 93, 107, 174, 175], "classifi": [6, 7, 13, 14, 16, 21, 24, 29, 31, 32, 37, 44, 45, 46, 63, 69, 71, 83, 89, 90, 102, 132, 133, 151, 152, 153, 187], "l1_ratio": 6, "vanillaen": 6, "gridsearchen": 6, "cov": 6, "tangent_spac": 6, "metric": [6, 7, 8, 14, 18, 19, 24, 30, 32, 34, 36, 37, 39, 41, 46, 109, 110, 111, 112, 113, 114, 132, 133, 135, 136, 137, 139, 140, 141, 142, 144, 146, 149, 154, 187], "riemann": [6, 8, 39, 41, 46, 109, 110, 111, 112, 113, 114, 153], "logistreg": 6, "penalti": [6, 7], "elasticnet": 6, "75": [6, 9, 25, 28, 34, 39, 101, 106], "intercept_sc": 6, "1000": [6, 29, 98, 99, 100, 101, 104, 155, 156, 157, 158, 159, 160], "solver": [6, 7, 14, 18, 19, 30, 32, 36], "saga": 6, "max_it": 6, "70": [6, 9, 25, 27, 28, 70, 71, 101, 187], "space": [6, 7, 8, 9, 12, 18, 25, 30, 33, 46, 62, 76, 77, 78, 79, 89, 161, 187], "dictionari": [6, 7, 22, 31, 33, 37, 42, 46, 58, 81, 107, 123, 129], "specifi": [6, 8, 12, 16, 17, 23, 24, 25, 26, 27, 28, 29, 33, 34, 39, 42, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 92, 93, 94, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 145, 187], "name": [6, 21, 22, 25, 27, 28, 29, 35, 41, 42, 44, 48, 56, 57, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 109, 110, 111, 112, 113, 114, 120, 126, 127, 128, 129, 151, 152, 153, 155, 156, 157, 158, 159, 160, 187], "kei": [6, 22, 25, 26, 33, 42, 108, 117, 118, 120, 128, 129, 151, 152, 153, 180], "param_grid": [6, 126, 127, 128, 129], "logistreg__l1_ratio": 6, "15": [1, 6, 7, 25, 26, 27, 29, 31, 37, 38, 47, 48, 69, 70, 71, 76, 77, 78, 86, 92, 95, 96, 99, 100, 101, 103, 104, 158, 168, 176], "30": [6, 8, 14, 18, 25, 28, 31, 33, 48, 69, 71, 75, 84, 92, 93, 94, 99, 100, 103, 133], "45": [6, 7, 10, 14, 35, 37, 83, 91, 131, 132, 133, 138, 142, 150], "60": [6, 8, 18, 25, 27, 28, 31, 33, 34, 35, 48, 76, 77, 78, 79, 83, 89, 92, 96, 101, 103, 105, 122, 187], "dure": [6, 29, 33, 34, 65, 67, 69, 71, 72, 75, 80, 82, 84, 85, 88, 89, 90, 91, 92, 93, 94, 99, 100, 101, 102, 103, 104, 105, 106], "random_st": [6, 21, 29, 126, 127, 128, 129, 155, 156, 157, 158, 159, 160], "42": [6, 21, 25, 26, 27, 29, 32, 96], "hdf5_path": [6, 8, 36, 37, 44, 45, 46, 126, 127, 128, 129], "n_job": [6, 26, 27, 29, 60, 126, 127, 128, 129, 152, 187], "save_model": [6, 126, 127, 129], "withinsess": [6, 8, 12, 14, 18, 19, 25, 26, 28, 36, 37, 44, 45, 46, 60, 128], "10": [1, 6, 7, 8, 14, 16, 17, 18, 20, 22, 23, 25, 26, 27, 28, 29, 30, 32, 34, 35, 37, 38, 42, 47, 48, 63, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 89, 90, 91, 92, 93, 94, 95, 96, 99, 100, 101, 102, 103, 104, 105, 106, 122, 131, 134, 138, 151, 152, 155, 156, 157, 158, 159, 160, 161, 168, 170, 176, 178], "83": 187, "better": 6, "lead": [6, 87], "text": [6, 87], "44": [6, 7, 22, 48, 67, 98], "972222222222214": 6, "save": [6, 8, 9, 12, 18, 21, 22, 25, 26, 27, 28, 30, 32, 33, 36, 37, 39, 44, 45, 46, 60, 104, 108, 180, 187], "possibl": [6, 7, 8, 9, 12, 22, 24, 25, 26, 27, 28, 33, 48, 60, 68, 87, 92, 104, 128, 187], "models_withinsess": [6, 21], "1test": 6, "fitted_model_best": [6, 21], "pkl": [6, 21], "rb": [6, 21], "pickle_fil": [6, 21], "gridsearchen_session_": 6, "print": [6, 8, 9, 11, 12, 14, 18, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 37, 39, 41, 42, 44, 60, 187], "session_": 6, "best_params_": 6, "0train": [6, 34, 44], "gridsearchen_session_t": 6, "session_t": 6, "183": [], "204": [43, 187], "plot_grid_search_withinsess": [6, 10], "instead": [7, 33, 35, 41, 45, 55, 60, 63, 85, 92, 151, 152, 153, 155, 156, 157, 158, 159, 160, 187], "arrai": [7, 14, 18, 19, 24, 33, 34, 44, 60, 83, 103, 107, 128, 145, 153], "emb": 7, "insid": [7, 24, 48, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 122, 123, 151, 152, 153, 155, 156, 157, 158, 159, 160, 179, 187], "p300": [7, 13, 15, 16, 17, 20, 25, 38, 41, 44, 62, 63, 64, 65, 66, 67, 71, 72, 74, 81, 83, 84, 89, 101, 107, 122, 124, 128, 129, 143, 174, 187], "logist": [7, 8, 9, 18, 25, 30, 32], "regress": [7, 8, 9, 18, 25, 30, 32], "xdawn": [7, 19, 36], "lr": [7, 8, 9, 12, 18, 25, 30], "extend": [7, 32, 45, 46, 85, 86, 96, 101, 162], "tangent": [7, 8, 9, 12, 18, 25, 30, 32, 46], "sphinx_gallery_thumbnail_numb": [7, 9], "vector": [7, 14, 19, 36, 152, 153, 187], "xdawncovari": [7, 14, 19, 36], "baseestim": 7, "transformermixin": 7, "standardscal": 7, "meta_analysi": [7, 9], "noqa": [7, 9, 39, 92, 93, 94], "e501": [7, 9, 39, 92, 93, 94], "compute_dataset_statist": [7, 9, 55, 56], "find_significant_differ": [7, 9], "plot": [7, 23, 24, 25, 26, 27, 28, 35, 42, 60, 83, 107, 182, 187], "paired_plot": [7, 8, 9], "summary_plot": [7, 9], "bnci2014_009": [7, 14, 19, 36, 48, 183], "evalu": [7, 12, 25, 26, 27, 28, 34, 35, 39, 45, 46, 48, 49, 51, 54, 57, 60, 85, 88, 92, 105, 145, 182, 183, 187], "simplefilt": [7, 14, 19, 31, 32, 36, 37], "action": [7, 14, 19, 31, 32, 36, 37, 187], "ignor": [7, 14, 19, 23, 24, 31, 32, 33, 35, 36, 37, 44, 45, 46, 101, 102, 103, 108, 131, 134, 138, 145, 151, 152, 153, 155, 156, 157, 158, 159, 160], "categori": [7, 14, 19, 31, 32, 36, 37, 182], "futurewarn": [7, 14, 19, 25, 26, 28, 29, 30, 31, 32, 36, 37], "runtimewarn": [7, 14, 19, 25, 26, 27, 28, 29, 31, 32, 36, 37], "bnci": [7, 8, 14, 31, 42, 44, 68, 69, 70, 71, 72, 73, 74, 75, 187], "2014": [7, 8, 14, 31, 63, 64, 65, 68, 69, 70, 71, 72, 105, 152], "009": [7, 14, 19, 36, 72], "get_data": [7, 22, 26, 29, 31, 33, 34, 35, 37, 39, 44, 81, 107, 123, 145, 187], "subject_id": [7, 31, 37, 81, 107, 123], "label": [7, 23, 24, 31, 34, 35, 37, 39, 44, 83, 86, 89, 90, 91, 93, 94, 107, 126, 127, 128, 129, 136, 140, 145, 153], "return": [7, 8, 9, 12, 14, 18, 19, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36, 37, 39, 42, 44, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 89, 90, 91, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 108, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 145, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 167, 172, 175, 181, 187], "With": [7, 92, 151, 153, 180], "return_epoch": [7, 27, 29, 34, 126, 127, 128, 129, 130, 145], "576": [7, 14, 19, 34, 36], "800781": [7, 14, 19, 36], "14": [7, 8, 14, 19, 23, 25, 29, 30, 31, 36, 37, 38, 43, 45, 48, 94, 97, 98, 106], "target": [7, 14, 19, 24, 25, 36, 63, 64, 65, 66, 67, 72, 76, 77, 78, 79, 83, 86, 87, 89, 91, 93, 94, 97, 101, 102, 103, 104, 132, 133, 141], "96": [7, 14, 19, 34, 36, 46, 187], "nontarget": [7, 14, 19, 24, 25, 36, 141], "480": [7, 14, 19, 36, 48, 187], "design": [7, 12, 25, 26, 27, 28, 32, 69, 72, 76, 77, 78, 79, 81, 89, 90, 91, 105, 153, 182], "reshap": [7, 14, 19, 162], "rescal": 7, "basic": [7, 39, 42, 172, 181, 182, 187], "compli": 7, "convent": [7, 91, 128, 132, 133], "extract": [7, 23, 24, 44, 145, 152, 153], "2d": 7, "myvector": 7, "def": [7, 22, 39, 41], "__init__": [7, 39, 41, 172], "self": [7, 27, 39, 41, 145, 151, 152, 153, 155, 156, 157, 158, 159, 160, 169, 187], "fit": [7, 24, 29, 34, 107, 126, 127, 128, 129, 145, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 162, 163, 164], "arr": 7, "features_shape_": 7, "shape": [7, 34, 55, 153, 162, 172], "scaler": 7, "mne_ppl": 7, "l1": 7, "liblinear": 7, "mne_ev": 7, "mne_r": 7, "33": [7, 14, 27, 28, 42, 44, 45, 46, 89], "03": [7, 30, 31, 38, 42, 84], "06": [7, 9, 25, 29, 31, 42], "67": [7, 8, 44, 45, 46, 91], "venv": [14, 19, 25, 27, 28, 29, 30], "lib": [14, 19, 25, 27, 28, 29, 30], "9": [5, 8, 14, 15, 19, 25, 26, 27, 28, 29, 30, 31, 32, 33, 36, 37, 38, 42, 43, 46, 48, 68, 70, 83, 84, 86, 87, 89, 95, 98, 105, 106, 178], "site": [14, 19, 25, 27, 28, 29, 30], "urllib3": [], "connectionpool": [], "1061": [], "insecurerequestwarn": [], "unverifi": [], "host": [], "lampx": [], "tugraz": [], "ad": [9, 24, 70, 126, 127, 128, 129, 187], "certif": [], "strongli": [], "advis": [], "readthedoc": [], "io": [34, 39, 107, 129, 145, 187], "en": [12, 14, 19, 28], "26": [35, 45, 72], "18": [9, 25, 27, 48, 103], "5m": [], "8k": [], "01": [14, 15, 19, 20, 25, 26, 27, 28, 29, 30, 38, 43], "167kb": [], "150k": [], "31": [33, 48, 83, 86, 87, 101, 103], "589kb": [], "307k": [], "960kb": [], "680k": [], "09": [7, 8, 26, 36, 38, 43, 44, 45, 46], "93mb": [], "7": [7, 8, 10, 14, 19, 20, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 37, 38, 41, 43, 44, 46, 48, 63, 70, 71, 76, 77, 78, 79, 85, 86, 87, 92, 93, 94, 96, 98, 102, 105, 109, 110, 111, 112, 113, 114, 131, 138, 142, 145, 146, 149, 150, 187], "25m": [], "19mb": [], "22m": [], "29mb": [], "22": [28, 34, 48, 96, 104], "16m": [], "71mb": [], "81m": [], "5mb": [], "47": [25, 28, 46], "72m": [], "8mb": [], "62": [36, 48, 89, 90, 91, 104], "6m": [], "3mb": [], "3m": [], "4mb": [], "92": [46, 187], "17": [14, 27, 29, 32, 48, 86, 99, 100, 104], "1m": [], "2mb": [], "64": [21, 29, 36, 48, 65, 67, 82, 97, 102, 104, 155, 156, 157, 158, 159, 160, 168, 169], "8gb": [], "49": [8, 33], "One": [7, 32, 68, 69, 75, 84, 95, 101, 121], "mne_label": [7, 126, 127, 128, 129], "order": [7, 12, 27, 29, 42, 63, 73, 75, 76, 77, 78, 79, 81, 84, 85, 87, 92, 93, 94, 98, 99, 100, 101, 102, 104, 107, 161, 182, 187], "keep": [7, 12, 16, 25, 26, 27, 28, 29, 31, 33, 37, 92, 98, 145], "mne_adv": 7, "reg": 7, "ledoit_wolf": 7, "correct_overlap": 7, "adv_ev": 7, "adv_r": 7, "07": [7, 20, 25, 37, 38, 46], "52": [25, 44, 48, 82, 83], "reli": [7, 32, 46, 162, 187], "matric": [7, 8, 32, 33, 46, 55, 153, 162], "sk_ppl": 7, "rg": [7, 9, 14, 18, 19, 30, 32, 36], "nfilter": [7, 14, 19, 25, 36, 154], "lwf": [7, 14, 19, 24, 32, 36, 41, 109, 110, 111, 112, 113, 114, 153], "xdawn_estim": [7, 14, 19, 36], "scm": [7, 14, 19, 36, 153], "sk_eval": 7, "sk_re": 7, "98": [6, 74, 83], "84": 83, "85": [], "86": [69, 82, 187], "even": [7, 27, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 122, 145], "datafram": [7, 9, 12, 14, 18, 19, 24, 25, 26, 27, 28, 30, 31, 32, 34, 36, 37, 42, 44, 45, 46, 51, 52, 53, 54, 55, 56, 57, 59, 60, 129, 145, 181, 187], "analyz": [7, 44, 45, 89, 92, 99, 100, 153, 181, 187], "all_r": 7, "euclidean": [7, 153], "riemannian": [7, 9, 14, 18, 19, 24, 25, 30, 32, 36, 46, 63, 88, 162], "figur": [7, 12, 25, 26, 27, 28, 29, 35, 37, 44, 56, 57, 58, 59, 68, 75], "size": [7, 14, 16, 19, 42, 44, 48, 59, 81, 88, 128, 141], "1100x850": 7, "highlight": [7, 86, 87, 91, 102, 103], "between": [7, 8, 22, 23, 24, 33, 34, 35, 39, 55, 68, 69, 70, 71, 73, 75, 81, 82, 84, 88, 94, 96, 99, 100, 101, 102, 104, 105, 106, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150], "stat": [7, 9, 54], "p": [7, 9, 22, 26, 27, 29, 47, 48, 53, 54, 55, 59, 60, 62, 63, 64, 65, 66, 67, 68, 72, 80, 81, 83, 86, 87, 92, 96, 97, 102, 103, 152, 153, 157, 158, 168], "614": [], "282": 187, "plot_mne_and_scikit_estim": [7, 10], "restrict": [8, 12, 18, 25, 26, 27, 28, 30, 34, 60, 92, 187], "subset": [8, 12, 16, 17, 25, 34, 128], "sampl": [8, 14, 18, 19, 29, 30, 31, 33, 34, 37, 39, 42, 48, 51, 61, 63, 68, 69, 70, 73, 74, 75, 76, 77, 78, 79, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 152, 153, 163, 182], "rate": [8, 34, 48, 61, 63, 69, 75, 76, 77, 78, 79, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150], "common": [8, 31, 35, 85, 92, 104, 125, 145, 152, 178, 182, 187], "share": [8, 22, 25, 125], "uvsq": [8, 30, 31, 32, 34, 37], "fr": [8, 12, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 37, 61, 64, 65, 66, 67, 80, 81], "moabb_plt": [8, 9], "zhou2016": [8, 12, 21, 25, 28, 31, 33, 34, 35, 42, 44, 45, 46, 48, 183, 187], "find_intersecting_channel": 8, "004": [8, 25, 27, 31, 34, 70, 75], "subj": [8, 31, 37, 44, 45, 46, 48, 61, 63, 76, 77, 78, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106], "further": [8, 85, 92, 181], "c3": [8, 25, 34, 61, 69, 70, 72, 73, 75, 99, 100, 122], "c4": [8, 34, 61, 69, 70, 72, 73, 75, 99, 100, 122], "cz": [8, 23, 25, 34, 61, 63, 69, 70, 71, 72, 73, 74, 75, 83, 85, 99, 100, 122], "200": [8, 31, 48, 104, 187], "conduct": [8, 44, 82, 88, 183], "csp_lda": 8, "ts_lr": 8, "oa": [8, 25, 39, 46, 153], "head": [8, 12, 18, 29, 30, 31, 34, 37, 42, 71, 80, 81, 88, 99, 100, 179], "29": [8, 25, 28, 31, 33, 46, 48, 83, 99, 100], "25": [8, 9, 25, 28, 31, 33, 34, 48, 62, 68, 70, 73, 75, 85, 86, 91, 93, 94, 99, 100, 104, 106], "No": [8, 36, 37, 44, 45, 46, 68, 85, 162], "model": [8, 16, 27, 30, 31, 34, 36, 37, 38, 44, 45, 46, 68, 83, 107, 126, 127, 128, 129, 140, 143, 145, 148, 165, 172, 174, 175, 187], "04": [8, 25, 26, 30, 37, 38, 44, 45, 152], "40": [8, 25, 26, 28, 31, 39, 48, 75, 76, 77, 78, 79, 96, 101, 104], "51": [25, 97], "582": [8, 27], "kb": [8, 37], "99": [7, 31], "n_session": [8, 18, 29, 30, 31, 37, 42, 122], "844823": 8, "057721": [], "119": 8, "900000": 8, "049649": [], "950000": 8, "050884": [], "918000": 8, "049202": [], "817284": 8, "044027": [], "90": [8, 101, 187], "row": [8, 18, 29, 30, 31, 37, 42, 71, 72, 89], "overlap": [8, 92, 125], "discard": 8, "well": [8, 9, 82, 90, 128, 187], "valid": [8, 30, 31, 37, 42, 44, 62, 69, 125, 127, 128, 150, 183], "80": [27, 46, 48, 63, 86, 89, 98, 105], "08": [8, 9, 30, 37, 45, 46], "02": [10, 14, 19, 25, 27, 31, 37], "865657": 8, "057420": [], "916000": 8, "049100": [], "932000": 8, "051522": [], "924000": 8, "050363": [], "829630": 8, "045634": [], "588": [], "406": [], "plot_select_electrodes_resampl": [8, 10], "codebas": [9, 42, 182], "come": [9, 25, 44, 182], "conveni": [9, 42, 69], "focus": [9, 71, 72, 88, 93, 94, 104], "exactli": [9, 45, 46, 101], "vinayjayaram13": [9, 42], "__doc__": [9, 34], "explor": [9, 16, 38, 42, 68, 70, 107, 136, 139, 140, 143, 148], "choos": [9, 11, 60], "left": [9, 18, 30, 31, 34, 44, 45, 63, 68, 69, 70, 71, 72, 75, 82, 85, 88, 89, 90, 91, 97, 98, 99, 100, 105, 106, 135, 139], "bandpass": [9, 31, 32, 34, 35, 37, 42, 68, 70, 73, 131, 132, 133, 134, 137, 142, 143, 145, 146, 148, 149, 150], "without": [9, 30, 33, 34, 70, 76, 77, 78, 79, 80, 88, 89, 92, 99, 100, 103, 107, 179], "workflow": [9, 181], "must": [9, 14, 18, 19, 28, 30, 32, 34, 36, 60, 63, 92, 107, 128, 129, 132, 133, 136, 137, 140, 142, 145, 150, 178, 179], "geometri": [9, 14, 18, 19, 24, 25, 30, 32, 36, 46, 63, 88], "consist": [9, 13, 16, 18, 30, 44, 63, 68, 69, 70, 72, 75, 80, 81, 83, 84, 87, 88, 89, 90, 92, 93, 94, 97, 98, 99, 100, 101, 102, 103, 104, 105, 187], "map": [9, 18, 26, 27, 30, 98, 155, 160], "final": [9, 18, 22, 27, 30, 33, 35, 41, 101, 102, 104, 153], "classif": [9, 14, 16, 18, 19, 24, 26, 30, 34, 37, 39, 41, 44, 46, 63, 69, 76, 77, 78, 79, 81, 82, 83, 89, 90, 91, 99, 100, 135, 139, 141, 156, 161, 183, 187], "contain": [9, 12, 14, 18, 19, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 36, 37, 39, 41, 44, 45, 46, 60, 61, 62, 63, 64, 65, 66, 67, 70, 74, 80, 81, 82, 83, 84, 85, 86, 87, 88, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 115, 116, 122, 123, 126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 167], "databas": [9, 18, 30, 32, 36, 92, 93, 94], "again": [9, 18, 30, 32, 36, 99, 100], "unless": [9, 18, 30, 32, 34, 36], "overwritten": [9, 18, 30, 32, 36], "27": [14, 26, 33, 38, 96, 98, 104], "advanc": [177, 182], "23": [14, 27, 28, 34, 38, 46, 48, 83, 92, 97], "153k": [], "601kb": [], "328k": [], "03mb": [], "585k": [], "56mb": [], "19m": [], "04mb": [], "32m": [], "72mb": [], "21m": [], "85mb": [], "92m": [], "20m": [], "8m": [], "1mb": [], "2m": [], "38": [18, 26, 27, 48, 65, 98, 155, 160], "0mb": [], "43": [20, 25, 48, 66], "19": [7, 25, 36, 38, 46, 65, 82, 83, 187], "0m": [], "4m": [], "54": [48, 89, 90, 91], "7mb": [], "65": [19, 153], "28": [9, 10, 83, 88, 134, 147], "7m": [], "9mb": [], "36": [18, 20, 42, 48, 64, 65, 66, 67, 71, 72, 89, 102], "39": 29, "97": [7, 8, 31], "6mb": [], "166gb": [], "19k": [], "2kb": [], "82": [], "9k": [], "469kb": [], "188k": [], "57": [7, 25, 37, 91, 92, 93, 94, 187], "735kb": [], "352k": [], "09mb": [], "600k": [], "59mb": [], "04m": [], "54mb": [], "07m": [], "08mb": [], "94m": [], "42mb": [], "87m": [], "9m": [], "41": [8, 10, 14, 43], "163gb": [], "68": [44, 86, 87], "37": 31, "105k": [], "403kb": [], "289k": [], "939kb": [], "682k": [], "98mb": [], "10mb": [], "17m": [], "18mb": [], "08m": [], "62m": [], "01m": [], "58": [14, 15, 26], "71": [8, 27, 64], "78": [27, 33, 36], "34": [18, 28, 38, 42, 48, 67, 104], "164gb": [], "144k": [], "567kb": [], "304k": [], "954kb": [], "655k": [], "15m": [], "87mb": [], "22mb": [], "05m": [], "52mb": [], "24m": [], "97m": [], "132gb": [], "76": 187, "toolkit": 9, "score_plot": [9, 25, 26, 27, 28], "visual": [9, 26, 27, 48, 59, 62, 64, 65, 66, 67, 70, 73, 74, 76, 77, 78, 79, 81, 83, 85, 86, 87, 90, 91, 92, 93, 94, 95, 98, 99, 100, 102, 103, 104, 105, 155, 160, 187], "sea": [9, 25, 27, 28], "over": [9, 34, 55, 56, 69, 70, 82, 87, 97, 99, 166, 183], "chosen": [9, 16, 17, 42, 44, 83, 86, 92, 93, 94], "regardless": [9, 101], "signific": [9, 53, 59], "overview": 9, "mean": [9, 14, 18, 19, 23, 24, 33, 34, 39, 55, 63, 72, 82, 83, 96, 98, 104, 128, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 153, 183], "question": 9, "effect": [9, 35, 52, 54, 55, 56, 59, 87, 151, 152, 153, 155, 156, 157, 158, 159, 160, 183], "overal": 9, "meta_analysis_plot": 9, "summari": [9, 12, 25, 26, 27, 28, 33, 187], "relat": [9, 62, 72, 81, 87, 98, 153, 179, 183], "hypothesi": [9, 56], "axi": [9, 23, 166], "635": [], "278": 187, "plot_statistical_analysi": [9, 10], "334": 83, "execut": [10, 15, 16, 20, 38, 43, 70, 92, 93, 94, 96, 97, 98], "auto_examples_advanced_exampl": 10, "405": [], "277": [], "203": [], "minim": [11, 76, 77, 78, 79, 89, 92, 99], "custom": [11, 99, 100, 103], "locat": [11, 22, 25, 61, 62, 63, 64, 65, 66, 67, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 88, 89, 93, 94, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 173, 187], "divyesh": [1, 11, 47, 176, 187], "narayanan": [1, 11, 47, 176, 187], "osp": [11, 29], "get_config": [11, 22, 25, 26, 33], "set_download_dir": [11, 187], "choic": [11, 84, 85, 92], "doesn": [11, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122], "exist": [11, 33, 41, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 151, 152, 153, 155, 156, 157, 158, 159, 160, 173, 183], "original_path": 11, "mne_data": [11, 22, 25, 26, 29, 33, 44, 46, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 173, 187], "new_path": 11, "expandus": [11, 29], "mne_data_test": 11, "verifi": [11, 92, 126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 155, 156, 157, 158, 159, 160, 168, 179], "correctli": [11, 27, 179], "check_path": 11, "now": [11, 21, 22, 33, 39, 41, 72, 107, 179, 187], "back": [11, 96, 98], "000": [11, 12, 21, 22, 23, 24, 38, 39, 41, 43, 86, 87, 89, 90, 91], "changing_download_directori": [11, 38], "librari": [1, 12, 22, 45, 47, 176, 177, 179, 182], "easili": [12, 25, 26, 27, 28, 44], "scale": [12, 25, 26, 27, 28, 76, 77, 78, 79, 163, 187], "limit": [12, 25, 92, 102, 103, 182], "onlin": [12, 39, 44, 62, 63, 70, 73, 86, 87, 88, 89, 90, 91, 95, 101, 103, 151], "cluster": 12, "replic": 12, "infrastructur": 12, "inria": [12, 21, 26, 27, 28, 29], "codecarbon_plot": 12, "sever": [12, 16, 17, 33, 44, 56, 84, 93, 94, 104, 106], "ml": [12, 25], "dl": [12, 39], "kera": [12, 16, 26, 38, 155, 156, 157, 158, 159, 160, 165, 174, 175, 187], "optim": [12, 21, 29, 76, 77, 78, 79, 92, 98, 101, 102, 103, 106, 152, 155, 156, 157, 158, 159, 160, 167], "hyperparamet": [12, 21, 28, 29], "pipelines_codecarbon": 12, "include_dataset": [12, 25, 26, 27, 28, 60, 187], "exclude_dataset": [12, 25, 60], "argument": [12, 25, 26, 27, 28, 33, 107, 145, 187], "given": [12, 22, 24, 25, 33, 34, 42, 44, 61, 62, 63, 64, 65, 66, 67, 70, 80, 81, 82, 83, 84, 85, 88, 89, 95, 96, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 108, 115, 116, 119, 122, 124, 125, 126, 127, 128, 129, 135, 136, 139, 140, 141, 144, 146, 149, 151, 152, 153, 155, 156, 157, 158, 159, 160, 166], "last": [12, 22, 25, 27, 29, 32, 33, 34, 35, 39, 46, 69, 70, 73, 75, 84, 86, 87, 88, 93, 94, 98, 102, 104, 106], "zhou": [12, 25, 28, 106, 152], "2016": [12, 25, 27, 28, 69, 88, 92, 93, 94, 104, 106], "consid": [12, 16, 17, 32, 34, 44, 46, 60, 89, 92, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 153, 187], "kind": [12, 25, 26, 27, 28, 31, 45, 46, 105], "indic": [12, 25, 26, 27, 28, 31, 33, 34, 37, 39, 69, 75, 85, 88, 93, 94, 96, 101, 104, 105, 106, 145], "dataset2": [12, 27], "output": [12, 25, 26, 27, 28, 33, 34, 58, 60, 90, 102, 108, 145, 166, 180, 182], "order_list": 12, "svm": [12, 21, 25, 42, 46], "keras_eegnet_8_2": [12, 26], "countri": 12, "franc": [12, 62, 64, 65, 66, 67, 80], "imag": [12, 22, 33, 68, 83, 84, 89, 177], "vari": [12, 22, 84, 102, 106, 107], "example_codecarbon": [12, 38], "curv": [13, 15, 20, 68, 72, 107, 128, 129, 139, 141, 143, 148, 174, 187], "addition": [14, 19, 89, 90, 91, 96, 101, 102], "extern": [14, 19, 92, 182], "tdlda": [14, 19], "requirements_extern": [14, 19], "txt": [14, 19, 92, 93, 94, 99, 100, 104], "three": [14, 19, 32, 35, 36, 45, 46, 64, 65, 66, 69, 70, 71, 72, 73, 76, 77, 78, 79, 85, 86, 87, 89, 90, 91, 92, 97, 99, 100, 102, 105, 106, 182, 183], "linear": [14, 19, 25, 31, 36, 42, 44, 46, 69, 71, 152], "discrimin": [14, 19, 31, 36, 44, 71], "decoupl": 14, "jan": [1, 14, 18, 19, 47, 176, 187], "sosulski": [1, 14, 18, 19, 47, 101, 176, 187], "numpi": [14, 18, 19, 23, 24, 33, 34, 35, 39, 42, 44, 60, 107, 128, 175, 187], "np": [14, 18, 19, 22, 23, 24, 34, 35, 39, 42, 129, 145, 187], "timedecoupledlda": 14, "jumpingmeansvector": 14, "rid": [14, 19, 36], "fout": [14, 19], "processing_sampling_r": [14, 19], "128": [14, 19, 36, 48, 85, 98, 122, 145, 163, 187], "do": [14, 19, 26, 27, 29, 34, 36, 41, 42, 44, 48, 63, 81, 89, 90, 91, 92, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 179, 183], "call": [14, 19, 22, 27, 29, 33, 34, 35, 36, 107, 126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 150, 180, 187], "labelencod": [14, 19, 24, 32, 36], "labels_dict": [14, 19, 36], "lsqr": [14, 18, 19, 36], "shrinkag": [14, 18, 19, 36], "simpl": [14, 25, 40, 43, 68, 92, 105, 107, 128, 129, 139, 143, 148, 174, 182], "certain": 14, "interv": [14, 16, 32, 33, 34, 37, 38, 39, 41, 56, 70, 71, 75, 84, 86, 87, 89, 98, 101, 104, 106, 107, 124, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 151, 153, 174], "jumping_mean_iv": 14, "139": 14, "169": 14, "199": 14, "229": [14, 187], "269": 14, "299": 14, "349": 14, "409": 14, "449": [14, 187], "499": 14, "jmv": 14, "jm": 14, "n_channel": [14, 126, 127, 128, 129, 153, 162], "n_time": [14, 162], "td": 14, "preproc": 14, "permut": [14, 16, 17, 18, 19, 54, 55, 128], "remov": [14, 19, 27, 33, 34, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 85, 88, 104, 107, 109, 110, 111, 112, 113, 114, 145, 187], "slice": [14, 19], "multipl": [14, 16, 19, 34, 38, 40, 42, 43, 44, 68, 92, 101, 106, 107, 126, 128, 129, 133, 134, 137, 139, 143, 148, 152, 174], "data_s": [14, 18, 19, 128], "polici": [14, 18, 19, 128], "ratio": [14, 19, 44, 63, 128], "geomspac": [14, 18, 19], "train": [14, 18, 19, 24, 25, 30, 31, 34, 42, 44, 62, 63, 69, 70, 71, 89, 90, 91, 98, 102, 103, 107, 126, 127, 128, 129, 145, 151, 153, 154, 172], "spars": [14, 18, 19], "lot": [14, 18, 19, 153], "n_perm": [14, 18, 19, 128], "floor": [14, 18, 19], "astyp": [14, 18, 19], "int": [14, 18, 19, 34, 39, 54, 55, 60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 119, 122, 123, 124, 126, 127, 128, 129, 131, 132, 133, 134, 136, 137, 138, 140, 142, 145, 150, 151, 152, 153, 161, 175], "guarante": [14, 19, 86, 126, 127, 128, 129], "random": [14, 19, 24, 29, 39, 48, 63, 65, 69, 70, 73, 75, 76, 77, 78, 79, 84, 87, 89, 98, 100, 101, 102, 103, 104, 105, 175, 183], "seed": [14, 19, 21, 29, 122, 123, 126, 127, 128, 129, 175, 187], "7536298": [14, 19], "examples_lr": [14, 19], "_shrunk_covari": [14, 19], "327": [14, 19, 187], "_empirical_covari": [14, 19], "95": [14, 19, 26, 27], "117": [], "facecolor": [14, 18, 19, 23, 32, 36, 58], "white": [14, 18, 19, 23, 32, 36, 69, 85, 99, 100, 105, 187], "n_sub": [14, 18, 19], "r": [1, 14, 18, 19, 22, 25, 26, 27, 29, 47, 48, 63, 68, 69, 70, 73, 74, 75, 83, 86, 87, 96, 97, 99, 100, 155, 158, 160, 168, 176], "groupbi": [14, 18, 19, 24], "els": [14, 18, 19, 22, 25, 26, 27, 28, 29, 30, 48, 150], "hue": [14, 18, 19, 30, 31, 37, 44, 46, 102, 103], "errbar_mean": [14, 18, 19], "title_str": [14, 18, 19], "errorbar": [14, 18, 19], "ci": [14, 18, 19, 187], "set_xlabel": [14, 18, 19, 23], "set_titl": [14, 18, 19, 23], "tight_layout": [14, 18, 19, 35], "341": [], "plot_learning_curve_p300_extern": [14, 15], "auto_examples_extern": 15, "main": [16, 33, 92, 182], "short": [16, 68, 70, 84, 99, 100, 101, 104, 106], "practic": [16, 69, 102], "benchmark": [16, 38, 40, 43, 47, 58, 68, 70, 83, 102, 104, 106, 107, 128, 129, 139, 143, 148, 157, 174, 175, 180, 187], "co2": [16, 38, 60, 68, 106, 139, 174], "footprint": [16, 38, 60, 68, 106, 139, 174], "pytorch": [16, 29, 38, 58, 60, 68, 70, 107, 165, 172, 174, 175, 178], "bid": [16, 33, 38, 61, 174, 187], "spectral": [16, 38, 80], "sphx_glr_auto_examples_noplot_vr_pc_p300_different_epoch_s": [16, 38, 81, 141], "tensorflow": [16, 21, 27, 38, 58, 60, 68, 107, 167, 174, 175, 178, 187], "deep": [16, 38, 58, 60, 68, 70, 89, 98, 107, 126, 129, 140, 143, 148, 155, 160, 174, 175, 178, 182, 187], "architectur": [16, 29, 38, 58, 60, 68, 70, 107, 174, 175], "braindecod": [16, 21, 29, 34, 38, 58, 60, 68, 70, 107, 145, 171, 174, 175, 187], "cross": [16, 37, 38, 42, 44, 60, 68, 69, 70, 73, 75, 85, 88, 90, 96, 99, 100, 106, 107, 126, 127, 128, 129, 137, 139, 140, 142, 143, 148, 174, 175, 183], "eegnet": [16, 26, 27, 38, 68, 107, 126, 129, 140, 143, 148, 158, 175], "v4": [16, 38, 68, 107, 126, 129, 140, 143, 148, 175], "ssvep": [16, 38, 44, 60, 88, 89, 90, 91, 92, 93, 94, 95, 104, 107, 122, 124, 127, 128, 129, 137, 151, 152, 153, 162, 174, 187], "disk": [16, 22, 38, 106, 107, 108, 139, 143, 148, 174, 187], "intermedi": [16, 22, 38, 106, 107, 139, 143, 148, 174, 187], "fraction": [16, 17], "ensur": [16, 17, 29, 34, 99, 103, 145, 178, 179, 187], "robust": [16, 17, 22, 61, 153], "randomli": [16, 17, 64, 65, 66, 67, 71, 92, 99, 100, 106], "repeat": [16, 17, 92, 99], "auto_examples_python": 16, "zip": [16, 40, 179], "auto_examples_jupyt": 16, "modif": 18, "lbfg": [18, 30, 32], "per_class": [18, 128], "704762": 18, "047698": [], "885714": 18, "061936": [], "000000": 18, "094380": [], "990476": 18, "132116": [], "480952": 18, "030774": [], "plot_learning_curve_motor_imageri": [18, 20], "spatialfilt": [19, 25], "xdw": [19, 36], "66": [27, 37, 44, 87, 92, 93, 94], "884": [], "plot_learning_curve_p300": [19, 20], "519": [], "auto_examples_learning_curv": 20, "pretrain": 21, "torch": [21, 27, 29, 187], "eegclassifi": [21, 29], "eegincept": [21, 27], "scikera": [21, 187], "wrapper": [21, 101, 121], "kerasclassifi": 21, "skorch": [21, 29, 172, 187], "callback": [21, 29, 167], "earlystop": [21, 29], "epochscor": [21, 29], "validsplit": [21, 29], "standardscaler_epoch": 21, "setup_se": [21, 26, 27, 29], "plot_benchmark_": 21, "plot_benchmark_braindecode_": 21, "plot_benchmark_dl_": 21, "csp_svm_train": 21, "exact": [21, 85], "same": [21, 27, 33, 34, 44, 82, 88, 92, 93, 94, 96, 98, 99, 100, 101, 122, 126, 127, 128, 129, 182, 183, 187], "model_kera": 21, "load_model": [21, 38], "1e": 21, "keras_deepconvnet": [21, 26], "kerasdeepconvnet_fitted_model_best": 21, "h5": 21, "instanti": [21, 35, 39, 45, 46], "keras_deepconvnet_train": 21, "pipes_kera": 21, "learning_r": [21, 29], "0001": 21, "weight_decai": [21, 29], "batch_siz": [21, 29, 155, 156, 157, 158, 159, 160], "verbos": [21, 29, 39, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 108, 115, 116, 122, 125, 155, 156, 157, 158, 159, 160], "patienc": [21, 29], "clf": [21, 29, 42], "modul": [21, 27, 29, 42, 48, 66, 95, 102, 103, 172, 178, 182], "adam": [21, 29, 155, 156, 157, 158, 159, 160], "optimizer__lr": [21, 29], "max_epoch": [21, 29], "train_split": [21, 29], "monitor": [21, 29, 70, 76, 77, 78, 79, 90, 91, 105], "valid_loss": [21, 27, 29], "on_train": [21, 29], "train_acc": [21, 27, 29], "lower_is_bett": [21, 29], "valid_acc": [21, 27, 29], "Not": [21, 24, 29], "f_param": 21, "models_crosssess": 21, "braindecode_eegincept": [21, 27], "eeginception_fitted_best_model": 21, "f_optim": 21, "eeginception_fitted_best_optim": 21, "f_histori": 21, "eeginception_fitted_best_histori": 21, "json": [21, 33, 121], "load_param": 21, "pipes_pytorch": 21, "neuroimag": [22, 76, 77, 78, 79], "principl": 22, "facilit": [22, 24, 104], "alexmi": [22, 42, 48, 183], "cache_config": [22, 33, 34, 107, 126, 127, 129, 145], "temp_dir": [22, 25, 33], "save_raw": [22, 33, 108], "next": [22, 35, 39, 42, 63, 75, 85, 89, 93, 94, 104, 105], "smallest": 22, "peopl": [22, 71, 74], "quickli": [22, 35, 182], "shutil": [22, 33], "tempfil": [22, 33], "pathlib": [22, 33], "temporari": [22, 33], "mkdtemp": [22, 33], "convers": [22, 24, 126, 127, 128, 129], "compliant": [22, 33], "_": [22, 23, 24, 29, 33, 89, 153, 187], "investig": [22, 62, 63, 64, 65, 66, 67, 80, 89, 90, 91, 105], "print_tre": 22, "header": [22, 25, 28, 93, 94, 121], "elbow": [22, 96], "pipe": [22, 24, 29, 42], "tee": 22, "blank": [22, 70, 75, 90, 104], "is_dir": 22, "children": 22, "iterdir": 22, "enumer": 22, "retriev": [22, 34, 126, 127, 128, 129], "alexeeg": 22, "particular": [22, 28, 33, 60, 84, 145], "edf": 22, "organ": [22, 72], "hierarchi": 22, "start": [22, 34, 35, 39, 43, 60, 61, 68, 69, 70, 73, 75, 85, 93, 94, 96, 99, 100, 102, 103, 104, 106, 107, 124, 126, 129, 131, 132, 133, 134, 137, 138, 139, 140, 142, 143, 145, 146, 148, 149, 150, 174, 177, 182], "metadata": [22, 34, 35, 145, 151, 152, 153, 155, 156, 157, 158, 159, 160, 187], "describ": [22, 34, 39, 42, 44, 60, 71, 80, 81, 87, 89, 90, 91, 92, 98, 153, 154, 155, 156, 157, 158, 159, 160, 161, 168], "spec": 22, "hood": [22, 33], "through": [22, 42, 44, 60, 102, 103, 106, 122], "system": [22, 26, 27, 63, 70, 73, 75, 76, 77, 78, 79, 82, 84, 85, 86, 90, 91, 92, 93, 97, 99, 100, 102, 104, 152, 159, 168, 170, 178], "offici": [22, 178, 180], "howev": [22, 33, 35, 44, 63, 101], "mechan": [22, 83, 151, 152, 153, 155, 156, 157, 158, 159, 160], "offer": [22, 33, 181], "pseudo": [22, 48, 64, 65, 66, 67, 76, 77, 78, 79, 87, 98, 101, 102, 103], "ndarrai": [22, 34, 83, 107, 128, 129, 145, 153, 187], "delet": [22, 33, 121], "rmtree": [22, 33], "pernet": 22, "appelhoff": 22, "gorgolewski": 22, "j": [1, 22, 26, 27, 29, 47, 48, 68, 69, 73, 75, 76, 77, 78, 79, 84, 86, 87, 89, 90, 91, 96, 97, 99, 100, 101, 102, 103, 152, 155, 156, 158, 160, 168, 176], "et": [22, 75, 76, 77, 78, 79, 82, 84, 85, 86, 87, 89, 90, 91, 92, 96, 98, 99, 100, 102, 103, 105, 106, 187], "al": [22, 75, 76, 77, 78, 79, 80, 82, 84, 85, 86, 87, 89, 90, 91, 92, 96, 98, 99, 100, 102, 103, 105, 106, 187], "electroencephalographi": [22, 81, 183], "sci": 22, "103": [22, 30], "2019": [22, 39, 41, 44, 45, 46, 62, 63, 64, 65, 66, 67, 80, 81, 89, 90, 91, 101, 103], "doi": [1, 22, 25, 39, 47, 48, 75, 76, 77, 78, 79, 80, 81, 82, 84, 86, 87, 89, 90, 91, 96, 101, 102, 103, 104, 105, 106, 107, 151, 152, 155, 156, 157, 158, 159, 160, 161, 168, 170, 176], "1038": 22, "s41597": 22, "019": [22, 30, 38], "0104": 22, "electrophysiolog": 22, "journal": [1, 22, 26, 27, 29, 47, 48, 72, 75, 84, 86, 95, 96, 102, 103, 105, 106, 151, 152, 158, 168, 176], "1896": [22, 27], "21105": 22, "joss": 22, "01896": 22, "2012": [22, 61, 62, 68, 73], "un": [22, 33, 61], "effecteur": [22, 61], "par": [22, 61], "cerveau": [22, 61], "asynchron": [22, 61], "doctor": [22, 61], "dissert": [22, 61], "universit\u00e9": [22, 61], "de": [22, 61], "grenobl": [22, 61, 62, 63, 64, 65, 66, 67, 80], "tel": [22, 61], "archiv": [22, 61, 64, 65, 66, 67, 80, 81, 92, 93, 94, 179], "ouvert": [22, 61, 64, 65, 66, 67, 80, 81], "01196752": [22, 61], "noplot_bids_convers": [22, 38], "cattan2019_phmd": [23, 48], "rodrigues01": [23, 24, 36], "modifi": [23, 24, 180], "gregoir": [1, 23, 24, 41, 47, 176, 187], "cattan": [1, 23, 24, 41, 47, 62, 63, 64, 65, 66, 67, 80, 81, 176, 187], "gcattan": [23, 24], "hotmail": [23, 24], "restingstatetop300adapt": 23, "filterwarn": [23, 24, 44, 45, 46], "spectrum": 23, "instanc": [23, 24, 34, 125, 126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 153], "tag": [23, 180], "remain": [23, 44, 90], "welch": 23, "psd": 23, "condit": [23, 24, 65, 66, 67, 72, 75, 76, 77, 78, 79, 83, 85, 88, 89, 99, 101, 153], "begin": [23, 34, 45, 68, 70, 85, 87, 88, 93, 94, 99, 100, 105, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150], "mean_pow": 23, "flatten": [23, 166], "log10": 23, "135": [23, 89, 187], "magnitud": 23, "db": 23, "fontsiz": 23, "frequenc": [23, 32, 33, 34, 37, 39, 63, 70, 72, 74, 88, 91, 92, 93, 94, 95, 96, 98, 104, 132, 137, 138, 140, 142, 143, 145, 148, 150, 151, 152, 153, 163], "legend": 23, "noplot_phmd_ml_spectrum": [23, 38], "framework": [24, 35], "pc": [24, 81], "get_block_repetit": [24, 81, 123], "experiment": [24, 62, 75, 80, 81, 83, 85, 86, 92, 93, 94, 97, 99, 100, 101, 102, 103], "block": [24, 33, 48, 76, 77, 78, 79, 81, 87, 90, 99, 100, 101, 102, 103, 104, 123, 168], "repetit": [24, 63, 70, 76, 77, 78, 79, 81, 98, 99, 100, 102, 123], "mdm": [24, 39, 41, 46, 63, 109, 110, 111, 112, 113, 114], "erpcovari": [24, 41, 109, 110, 111, 112, 113, 114], "roc_auc_scor": 24, "model_select": [24, 42], "kfold": 24, "tqdm": [24, 187], "cattan2019_vr": [24, 41, 48, 114, 123, 183], "length": [24, 27, 29, 34, 35, 48, 61, 62, 63, 64, 65, 66, 67, 69, 76, 77, 78, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 115, 116, 122, 124, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 151], "attribut": [24, 41, 187], "encod": [24, 61, 132, 133], "categor": [24, 182], "variabl": [24, 39, 61, 62, 63, 64, 65, 66, 67, 75, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 187], "numer": [24, 126, 127, 128, 129], "le": 24, "nsubject": 24, "fold": [24, 37, 128, 183], "combin": [24, 29, 33, 52, 53, 55, 105, 153, 187], "thank": [1, 24, 81, 176, 187], "init": [24, 187], "kf": 24, "n_split": [24, 126, 127, 129], "arrang": 24, "arang": 24, "scores_subject": 24, "although": [24, 92, 93, 94], "outsid": 24, "scope": 24, "inner": [24, 96], "loop": 24, "reason": 24, "behind": 24, "rather": [24, 105], "correct": [24, 34, 42, 69, 70, 71, 72, 85, 91, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 187], "virtual_r": [24, 41, 81], "personal_comput": 24, "split": [24, 101, 127], "test": [24, 28, 42, 44, 54, 55, 62, 63, 71, 84, 89, 90, 91, 98, 101, 122, 123, 128, 129, 153, 187], "train_idx": 24, "test_idx": 24, "appropri": [24, 34, 42, 44, 63, 90, 92, 153, 178], "x_train": 24, "y_train": 24, "x_test": 24, "y_test": 24, "techniqu": [24, 69, 182], "y_pred": [24, 153], "reliabl": [24, 26, 157], "append": [24, 31], "stock": 24, "consol": 24, "df": [24, 51, 54, 55], "titl": [1, 24, 47, 176], "noplot_vr_pc_p300_different_epoch_s": [24, 38], "universit": [25, 27], "pari": [25, 27], "saclai": [25, 27], "yaml": 25, "simplifi": [25, 59, 181], "reus": [25, 46], "complet": [25, 33, 34, 48, 63, 71, 72, 76, 77, 78, 79, 84, 86, 102, 145, 187], "public": [25, 39, 99, 100], "api": [25, 48, 180, 182], "sample_pipelin": 25, "csp_svm": 25, "line": [25, 45, 46, 68, 72, 104], "readlin": 25, "citat": [25, 187], "1007": 25, "bf01129656": 25, "1109": [25, 87, 104, 156, 159], "msp": 25, "2008": [25, 70, 84, 98], "4408441": 25, "svc": [25, 42, 46], "kernel": [25, 27, 42, 46], "fake": [25, 39, 42, 187], "93": [7, 25, 29], "non": [25, 26, 29, 48, 63, 64, 65, 66, 67, 69, 81, 83, 86, 87, 92, 98, 101, 187], "type": [25, 26, 29, 34, 51, 52, 53, 54, 56, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 70, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 88, 91, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 117, 118, 119, 120, 121, 122, 123, 129, 137, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 167, 175, 182, 187], "mne_datasets_fakedataset": 25, "120": [25, 27, 34, 48, 70, 96, 98, 102, 122], "fake1": [25, 34, 122], "fake2": [25, 34, 122], "fake3": [25, 34, 122], "c4_path": 25, "set_config": [25, 26, 29, 151, 152, 153, 155, 156, 157, 158, 159, 160], "mne_datasets_fakevirtualrealitydataset": 25, "cho2017": [25, 34, 42, 44, 48, 183, 187], "grossewentrup2009": [25, 34, 42, 44, 48, 183], "lee2019": [25, 34, 42, 44, 187], "mi": [25, 31, 34, 44, 45, 69, 70, 82, 89, 90, 91, 96, 97, 99, 100, 105, 147], "physionetmotorimageri": [25, 34], "schirrmeister2017": [25, 34, 42, 44, 48, 183, 187], "shin2017a": [25, 34, 42, 44, 48, 183, 187], "weibo2014": [25, 34, 42, 44, 48, 183, 187], "2024": 25, "123": 25, "mainthread": 25, "configur": [25, 34, 60, 89, 90, 91, 92, 107, 108, 145, 187], "anyth": 25, "move": [25, 75, 85, 88, 90, 96, 99, 100, 187], "mne_datasets_zhou_path": 25, "156m": [], "2k": [], "392kb": [], "261k": [], "61mb": [], "10m": [], "95mb": [], "95m": [], "49m": [], "06m": [], "65m": [], "82mb": [], "02mb": [], "15mb": [], "40mb": [], "21mb": [], "99mb": [], "76mb": [], "49mb": [], "25mb": [], "64mb": [], "48mb": [], "32mb": [], "16mb": [], "01mb": [], "91mb": [], "90mb": [], "84mb": [], "66mb": [], "43mb": [], "30mb": [], "11mb": [], "949kb": [], "902kb": [], "862kb": [], "886kb": [], "877kb": [], "878kb": [], "895kb": [], "925kb": [], "940kb": [], "843kb": [], "887kb": [], "842kb": [], "834kb": [], "815kb": [], "827kb": [], "863kb": [], "869kb": [], "893kb": [], "783kb": [], "705kb": [], "693kb": [], "652kb": [], "606kb": [], "583kb": [], "591kb": [], "597kb": [], "607kb": [], "633kb": [], "635kb": [], "664kb": [], "684kb": [], "731kb": [], "733kb": [], "46": [], "771kb": [], "796kb": [], "810kb": [], "824kb": [], "875kb": [], "905kb": [], "884kb": [], "911kb": [], "868kb": [], "874kb": [], "935kb": [], "857kb": [], "685kb": [], "714kb": [], "725kb": [], "677kb": [], "642kb": [], "669kb": [], "688kb": [], "621kb": [], "698kb": [], "670kb": [], "622kb": [], "610kb": [], "644kb": [], "634kb": [], "683kb": [], "661kb": [], "602kb": [], "566kb": [], "456kb": [], "431kb": [], "415kb": [], "424kb": [], "442kb": [], "419kb": [], "440kb": [], "454kb": [], "500kb": [], "497kb": [], "528kb": [], "552kb": [], "569kb": [], "582kb": [], "595kb": [], "630kb": [], "660kb": [], "605kb": [], "575kb": [], "585kb": [], "587kb": [], "632kb": [], "625kb": [], "624kb": [], "564kb": [], "614kb": [], "579kb": [], "562kb": [], "586kb": [], "593kb": [], "599kb": [], "637kb": [], "663kb": [], "613kb": [], "649kb": [], "598kb": [], "647kb": [], "672kb": [], "690kb": [], "702kb": [], "711kb": [], "756kb": [], "746kb": [], "782kb": [], "804kb": [], "820kb": [], "831kb": [], "759kb": [], "798kb": [], "777kb": [], "758kb": [], "755kb": [], "786kb": [], "806kb": [], "821kb": [], "792kb": [], "738kb": [], "699kb": [], "671kb": [], "692kb": [], "56": [7, 14, 25, 85, 187], "53": [7, 25, 187], "686kb": [], "700kb": [], "706kb": [], "720kb": [], "752kb": [], "724kb": [], "762kb": [], "717kb": [], "691kb": [], "703kb": [], "712kb": [], "718kb": [], "751kb": [], "687kb": [], "721kb": [], "682kb": [], "639kb": [], "655kb": [], "631kb": [], "551kb": [], "48": [7, 28, 34, 68], "509kb": [], "465kb": [], "439kb": [], "464kb": [], "471kb": [], "476kb": [], "506kb": [], "503kb": [], "483kb": [], "502kb": [], "474kb": [], "490kb": [], "491kb": [], "516kb": [], "548kb": [], "576kb": [], "554kb": [], "572kb": [], "679kb": [], "678kb": [], "689kb": [], "704kb": [], "628kb": [], "658kb": [], "525kb": [], "494kb": [], "378kb": [], "335kb": [], "320kb": [], "332kb": [], "341kb": [], "348kb": [], "354kb": [], "380kb": [], "384kb": [], "364kb": [], "342kb": [], "337kb": [], "346kb": [], "352kb": [], "389kb": [], "385kb": [], "381kb": [], "412kb": [], "395kb": [], "423kb": [], "406kb": [], "394kb": [], "422kb": [], "430kb": [], "411kb": [], "433kb": [], "425kb": [], "391kb": [], "402kb": [], "407kb": [], "416kb": [], "438kb": [], "398kb": [], "418kb": [], "441kb": [], "432kb": [], "405kb": [], "444kb": [], "457kb": [], "467kb": [], "484kb": [], "485kb": [], "513kb": [], "543kb": [], "563kb": [], "578kb": [], "648kb": [], "708kb": [], "612kb": [], "609kb": [], "645kb": [], "665kb": [], "580kb": [], "656kb": [], "604kb": [], "570kb": [], "515kb": [], "537kb": [], "487kb": [], "472kb": [], "477kb": [], "489kb": [], "479kb": [], "482kb": [], "458kb": [], "463kb": [], "539kb": [], "559kb": [], "662kb": [], "710kb": [], "719kb": [], "742kb": [], "596kb": [], "449kb": [], "379kb": [], "373kb": [], "327kb": [], "338kb": [], "347kb": [], "414kb": [], "409kb": [], "408kb": [], "397kb": [], "393kb": [], "382kb": [], "358kb": [], "360kb": [], "362kb": [], "356kb": [], "363kb": [], "368kb": [], "401kb": [], "447kb": [], "522kb": [], "521kb": [], "673kb": [], "754kb": [], "784kb": [], "805kb": [], "668kb": [], "565kb": [], "532kb": [], "498kb": [], "426kb": [], "404kb": [], "417kb": [], "512kb": [], "541kb": [], "526kb": [], "555kb": [], "701kb": [], "768kb": [], "830kb": [], "713kb": [], "723kb": [], "620kb": [], "573kb": [], "535kb": [], "557kb": [], "534kb": [], "527kb": [], "478kb": [], "530kb": [], "460kb": [], "448kb": [], "443kb": [], "508kb": [], "507kb": [], "533kb": [], "556kb": [], "588kb": [], "450kb": [], "451kb": [], "427kb": [], "445kb": [], "505kb": [], "536kb": [], "549kb": [], "603kb": [], "748kb": [], "61": [29, 48, 69, 96], "743kb": [], "776kb": [], "799kb": [], "851kb": [], "785kb": [], "812kb": [], "772kb": [], "760kb": [], "787kb": [], "729kb": [], "737kb": [], "651kb": [], "63": [46, 83, 86], "568kb": [], "493kb": [], "434kb": [], "511kb": [], "538kb": [], "531kb": [], "707kb": [], "722kb": [], "750kb": [], "681kb": [], "627kb": [], "581kb": [], "546kb": [], "540kb": [], "550kb": [], "544kb": [], "608kb": [], "594kb": [], "636kb": [], "744kb": [], "763kb": [], "778kb": [], "859kb": [], "891kb": [], "813kb": [], "811kb": [], "775kb": [], "69": 25, "667kb": [], "675kb": [], "697kb": [], "709kb": [], "769kb": [], "794kb": [], "848kb": [], "888kb": [], "908kb": [], "928kb": [], "974kb": [], "922kb": [], "990kb": [], "919kb": [], "892kb": [], "880kb": [], "873kb": [], "72": [45, 187], "901kb": [], "923kb": [], "823kb": [], "819kb": [], "793kb": [], "73": [44, 187], "741kb": [], "524kb": [], "499kb": [], "496kb": [], "470kb": [], "74": 46, "383kb": [], "387kb": [], "429kb": [], "459kb": [], "504kb": [], "619kb": [], "574kb": [], "547kb": [], "558kb": [], "523kb": [], "560kb": [], "745kb": [], "715kb": [], "734kb": [], "740kb": [], "779kb": [], "814kb": [], "764kb": [], "825kb": [], "861kb": [], "79": [28, 46], "882kb": [], "889kb": [], "950kb": [], "959kb": [], "00mb": [], "05mb": [], "07mb": [], "979kb": [], "918kb": [], "81": 31, "780kb": [], "765kb": [], "590kb": [], "553kb": [], "584kb": [], "611kb": [], "650kb": [], "638kb": [], "600kb": [], "640kb": [], "727kb": [], "676kb": [], "653kb": [], "739kb": [], "797kb": [], "802kb": [], "852kb": [], "913kb": [], "932kb": [], "946kb": [], "953kb": [], "996kb": [], "989kb": [], "987kb": [], "897kb": [], "912kb": [], "838kb": [], "853kb": [], "890kb": [], "87": [], "999kb": [], "956kb": [], "997kb": [], "88": 8, "06mb": [], "12mb": [], "13mb": [], "17mb": [], "24mb": [], "20mb": [], "91": [], "978kb": [], "917kb": [], "871kb": [], "906kb": [], "903kb": [], "817kb": [], "894kb": [], "94": [28, 74], "818kb": [], "781kb": [], "680kb": [], "618kb": [], "571kb": [], "529kb": [], "822kb": [], "832kb": [], "791kb": [], "626kb": [], "510kb": [], "480kb": [], "486kb": [], "514kb": [], "542kb": [], "461kb": [], "100m": [], "101m": [], "695kb": [], "736kb": [], "102m": [], "826kb": [], "732kb": [], "657kb": [], "728kb": [], "103m": [], "659kb": [], "654kb": [], "104m": [], "881kb": [], "909kb": [], "930kb": [], "105m": [], "945kb": [], "986kb": [], "983kb": [], "106m": [], "985kb": [], "947kb": [], "942kb": [], "952kb": [], "981kb": [], "107m": [], "993kb": [], "108m": [], "916kb": [], "933kb": [], "109m": [], "955kb": [], "926kb": [], "110m": 66, "864kb": [], "809kb": [], "111m": [], "716kb": [], "112m": [], "623kb": [], "453kb": [], "492kb": [], "113m": [], "495kb": [], "517kb": [], "114m": [], "115m": [], "116m": [], "646kb": [], "674kb": [], "117m": [], "847kb": [], "850kb": [], "879kb": [], "118m": [], "977kb": [], "969kb": [], "883kb": [], "921kb": [], "119m": [], "924kb": [], "929kb": [], "120m": [], "910kb": [], "462kb": [], "121m": [], "592kb": [], "122m": [], "795kb": [], "757kb": [], "123m": [], "839kb": [], "841kb": [], "854kb": [], "856kb": [], "773kb": [], "124m": [], "125m": 71, "390kb": [], "400kb": [], "468kb": [], "437kb": [], "126m": [], "374kb": [], "372kb": [], "370kb": [], "369kb": [], "367kb": [], "413kb": [], "435kb": [], "488kb": [], "127m": [], "128m": [], "617kb": [], "129m": [], "616kb": [], "130m": [], "694kb": [], "766kb": [], "131m": [], "885kb": [], "132m": [], "133m": [], "446kb": [], "134m": [], "641kb": [], "135m": [], "399kb": [], "136m": [], "475kb": [], "518kb": [], "137m": [], "138m": [], "428kb": [], "139m": [], "730kb": [], "767kb": [], "140m": [], "835kb": [], "844kb": [], "931kb": [], "860kb": [], "141m": [], "840kb": [], "142m": [], "941kb": [], "951kb": [], "966kb": [], "971kb": [], "143m": [], "144m": [], "145m": [], "998kb": [], "14mb": [], "982kb": [], "146m": [], "967kb": [], "147m": [], "666kb": [], "148m": [], "629kb": [], "149m": [], "747kb": [], "150m": [], "876kb": [], "151m": [], "152m": [], "153m": [], "154m": [], "155m": [], "23mb": [], "26mb": [], "622gb": [], "111": [25, 28, 187], "pars": [25, 28], "mea": [25, 28], "date": [25, 28], "read_raw_cnt": [25, 28], "fname": [25, 28], "preload": [25, 28, 33, 108, 187], "eog": [25, 28, 70, 86, 99, 100, 101], "veou": [25, 28], "veol": [25, 28], "byte": [25, 28], "859": [], "860": 25, "365": 187, "909": 25, "769": [], "924": 25, "220": [], "926": 25, "611": [], "954": 25, "060": [], "964": 25, "210": [], "916": 25, "820": [], "910": 25, "201": 187, "753": 25, "631": [], "765": 25, "031": [], "906": 25, "472": 83, "904": 25, "972": 25, "350": 187, "994": 25, "749": [], "980": [25, 89], "208": 45, "990": [25, 48], "609": [], "992": 25, "325": 33, "993": 25, "752": [], "995": [25, 38], "143": [], "596": [], "987": [], "968": 25, "436": [], "978": [25, 83], "avg": [25, 26, 27, 28], "932315": 25, "941601": 25, "940": [], "too": 25, "similar": [25, 153, 183], "shorten": 25, "754": [], "346": [], "plot_benchmark": [25, 38], "tf": [26, 187], "absl": [26, 27], "log": [26, 27, 42, 153, 154, 174, 187], "error": [26, 27, 32, 60, 89, 126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 151, 152, 153, 155, 156, 157, 158, 159, 160, 174, 179, 187], "set_verbos": [26, 27], "avoid": [25, 26, 27, 28, 29, 30, 33, 44, 45, 70, 75, 92, 96, 104, 105, 187], "environ": [26, 27, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 92, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122, 177, 178], "tf_cpp_min_log_level": [26, 27], "__version__": [26, 27, 29], "cpu": [26, 27, 29, 178], "list_physical_devic": 26, "NOT": [26, 27, 29], "gpu": [26, 27, 29, 178], "multithread": [26, 27, 29], "pipelines_dl": 26, "mne_datasets_bnci_path": 26, "170kb": [], "113k": [], "290k": [], "937kb": [], "629k": [], "79mb": [], "09m": [], "73mb": [], "96mb": [], "98m": [], "44m": [], "185gb": [], "136k": [], "298k": [], "494k": [], "67mb": [], "00m": [], "89m": [], "82m": [], "200gb": [], "355": [26, 27, 29], "annot": [26, 27, 29, 92, 93, 94, 122, 187], "drop": [26, 27, 29, 32, 187], "concatenate_epoch": [26, 27, 29], "271": 26, "145k": [], "306k": [], "961kb": [], "705k": [], "28m": [], "31mb": [], "80m": 66, "29m": [], "143gb": [], "275k": [], "855kb": [], "583k": [], "63mb": [], "03m": [], "88mb": [], "90m": [], "76m": [], "197gb": [], "522551": [], "keras_eegtcnet": 26, "462585": [], "keras_eegnex": 26, "534371": [], "keras_shallowconvnet": 26, "612891": [], "keras_eegitnet": 26, "564524": [], "488010": [], "shallow": [26, 27, 160], "convolut": [26, 27, 29, 98, 155, 156, 158, 159, 160, 168, 170], "network": [26, 27, 29, 89, 98, 155, 156, 158, 159, 160, 168, 170], "eegtcnet": [26, 159], "eegnex": [26, 157], "eegitnet": [26, 156], "schirrmeist": [1, 26, 27, 47, 98, 155, 160, 176, 187], "springenberg": [26, 27, 155, 160], "fieder": [26, 27, 155, 160], "glasstett": [26, 27, 155, 160], "eggensperg": [26, 27, 155, 160], "tangermann": [26, 27, 68, 86, 87, 101, 155, 160], "ball": [26, 27, 70, 98, 99, 155, 160], "2017": [26, 27, 80, 82, 86, 96, 98, 99, 100, 104, 155, 160], "neural": [1, 26, 27, 29, 47, 48, 70, 72, 73, 89, 98, 99, 100, 103, 104, 151, 152, 155, 158, 160, 168, 176], "human": [26, 27, 98, 155, 160], "5391": [26, 27, 98, 155, 160], "5420": [26, 27, 98, 155, 160], "lawhern": [26, 27, 29, 158, 168], "solon": [26, 27, 29, 158, 168], "waytowich": [26, 27, 29, 158, 168], "n": [26, 27, 29, 34, 39, 63, 68, 71, 93, 94, 97, 136, 137, 140, 153, 158, 159, 168, 170], "gordon": [26, 27, 29, 158, 168], "hung": [26, 27, 29, 158, 168], "lanc": [26, 27, 29, 158, 168], "2018": [1, 26, 27, 29, 47, 80, 87, 153, 158, 168, 176], "compact": [26, 27, 29, 158, 168], "engin": [1, 26, 27, 29, 35, 47, 48, 69, 70, 72, 73, 85, 97, 99, 100, 103, 104, 151, 158, 168, 176], "056013": [26, 27, 29, 158, 168], "ingolfsson": [26, 159, 170], "hersch": [26, 159, 170], "wang": [26, 95, 104, 152, 153, 159, 170], "kobayashi": [26, 159, 170], "cavigelli": [26, 159, 170], "benini": [26, 159, 170], "2020": [26, 27, 83, 159, 170], "octob": [26, 159, 170], "tcnet": [26, 159, 168, 170], "accur": [26, 159, 170], "tempor": [26, 29, 85, 87, 156, 159, 170], "embed": [26, 83, 159, 161, 170], "ieee": [26, 27, 70, 73, 85, 87, 97, 99, 100, 104, 153, 156, 159, 170], "confer": [26, 83, 101, 159, 170], "man": [26, 159, 170], "cybernet": [26, 159, 170], "smc": [26, 159, 170], "pp": [26, 69, 74, 97, 99, 100, 104, 159, 170], "2958": [26, 159, 170], "2965": [26, 159, 170], "chen": [26, 104, 153, 157], "teng": [26, 157], "h": [26, 44, 45, 46, 58, 70, 82, 89, 90, 91, 97, 99, 100, 156, 157], "pan": [26, 157], "geyer": [26, 157], "2022": [26, 27, 156, 157], "toward": [26, 71, 73, 83, 157], "electroencephalogram": [26, 101, 157], "studi": [1, 26, 47, 70, 71, 76, 77, 78, 79, 83, 95, 99, 100, 101, 102, 103, 157, 176, 183], "arxiv": [26, 62, 63, 83, 88, 92, 101, 157, 161, 170], "preprint": [26, 62, 63, 101, 157, 161], "2207": [26, 157], "12369": [26, 157], "salami": [26, 156], "andreu": [26, 156], "perez": [26, 156], "gillmeist": [26, 156], "itnet": [26, 156], "explain": [26, 48, 63, 156], "incept": [26, 27, 156], "36672": [26, 156], "36685": [26, 156], "660": [], "855": [], "plot_benchmark_dl": [26, 38], "bnci2014_004": [27, 42, 44, 48, 183], "cuda": [27, 29, 178], "is_avail": [27, 29], "devic": [27, 29, 82], "cu117": [27, 29], "braindecode_xxx": [27, 60], "xxx": 27, "pipelines_braindecod": 27, "180": [27, 187], "logsoftmax": 27, "layer": 27, "adjust": 27, "loss": [27, 155, 156, 157, 158, 159, 160], "accordingli": 27, "crossentropyloss": 27, "nn": [27, 93, 94], "conv": 27, "459": 27, "pad": 27, "odd": 27, "dilat": 27, "zero": [27, 39, 102, 103], "copi": [25, 26, 27, 28, 29, 30, 32, 61, 62, 63, 64, 65, 66, 67, 71, 80, 81, 82, 83, 84, 85, 88, 89, 95, 96, 97, 98, 101, 102, 104, 105, 106, 107, 115, 116, 122, 183], "aten": 27, "src": [27, 177], "nativ": 27, "cpp": 27, "895": 27, "conv2d": 27, "weight": [27, 71, 153, 154], "bia": 27, "stride": [27, 35, 131, 134, 138], "train_loss": [27, 29], "dur": [27, 29], "4688": [27, 29], "8837": [], "5172": [27, 29], "7108": [], "6206": [], "4844": [27, 29], "9449": [], "7103": [], "5758": [], "6094": [29, 101], "7891": [], "7095": 27, "5601": [], "4375": [27, 29], "0690": [], "7093": 27, "5726": [], "5156": [27, 29], "8475": [], "7091": 29, "5647": 27, "9607": [], "7089": 27, "5676": [], "0614": [], "7086": [], "5635": [], "5625": 27, "8471": [], "7082": [], "5629": [], "8999": [], "7079": 27, "9013": [], "7075": 29, "5697": [], "5469": [27, 29], "9092": [], "5862": 27, "6819": [], "5699": [], "9730": [], "5517": [27, 29], "6820": [], "5397": [], "5000": [27, 29], "9071": [], "6821": [], "5413": [], "stop": [27, 29, 55, 93, 94, 99, 100, 102, 131, 134, 138], "6250": 27, "6554": [], "4138": [27, 29], "6960": [], "1083": [], "5938": [27, 29], "6640": [], "0929": 27, "7298": 27, "6959": 27, "0899": [], "6693": [], "0889": [], "6813": [], "0883": 27, "6895": 27, "6958": [], "0884": 27, "5312": [27, 29], "6986": [], "0904": 27, "6853": [], "0885": 27, "7050": 27, "6957": [], "0881": 27, "6961": [], "0895": [], "7113": 29, "3103": [], "7049": [27, 29], "4531": [27, 29], "7398": [], "7046": 27, "1019": [], "7539": [], "7044": 27, "0878": [], "7288": 27, "7042": [], "0880": 27, "6406": 27, "6908": 29, "3448": [], "7040": [27, 29], "0873": [], "7800": [], "7039": [], "6531": [], "7037": [], "0877": [], "7416": 27, "7036": [], "0886": 27, "4219": [27, 29], "7501": [], "7035": [], "7685": [], "7034": [], "9378": [], "4483": [27, 29], "9357": [], "2790": [], "3438": [], "1412": [], "9063": [], "2752": [], "9843": [], "4828": [27, 29], "8822": [], "2866": [], "9976": [], "8586": [], "2759": [], "9187": [], "8363": [], "2747": [], "8690": [], "1665": [], "2762": [], "7410": [], "1349": [], "8589": [], "1001": 34, "2768": [], "6981": [], "0683": [], "2858": [], "8577": [], "0400": [], "2761": [], "8743": [], "6963": 27, "5536": 27, "5781": [27, 29], "7499": [], "5571": [], "0817": [], "6951": [], "5548": [], "0247": [], "6948": [], "5623": [], "9465": [], "6944": 27, "5553": [], "9765": [], "6941": 27, "5704": [], "8158": [], "6207": 29, "5657": [], "9634": [], "5576": [], "9056": [], "6940": 27, "5624": [], "9748": [], "5554": [], "9456": [], "7555": [], "5677": [], "0201": [], "7557": [], "8478": [], "7553": [], "5685": [], "8190": [], "7552": [], "5662": [], "9454": 27, "7558": [], "9660": [], "5907": [], "7541": [], "7017": 27, "0911": 27, "4062": 27, "7586": [], "7010": [27, 29], "1025": [], "7198": 27, "7003": 27, "7471": [], "6998": [], "7175": [], "6993": [], "0887": 27, "6738": [], "6989": [], "7188": [], "6985": 27, "7138": [], "6982": 27, "7493": 27, "6980": [], "0890": 27, "7350": [], "6978": 27, "0879": [], "7809": [], "6870": 27, "0894": [], "6869": [], "0981": [], "8271": [], "6867": 27, "8024": [], "6866": 27, "7661": [], "6865": 29, "0888": [], "6864": 27, "7718": [], "6863": [], "0893": [], "7396": 27, "6862": 27, "0898": [], "7611": [], "6861": 27, "0882": 27, "3747": [], "9366": [], "2798": [], "3750": 27, "2758": [], "8790": [], "2760": [], "9987": [], "8315": [], "2839": [], "1600": [], "8155": [], "2756": [], "0910": [], "8107": [], "2757": [], "8983": 27, "7402": [], "2797": [], "2841": [], "7468": [], "2765": [], "7875": [], "7496": [], "2755": [], "944kb": [], "616k": [], "70mb": [], "68mb": [], "78mb": [], "77m": [], "120gb": [], "137k": [], "638k": [], "81mb": [], "14m": [], "89mb": [], "13m": [], "44mb": [], "0gb": [], "160": [26, 27, 48, 89, 98, 106], "5268": 27, "8728": [], "6000": 27, "6849": [], "0541": 27, "9240": [], "6167": 27, "6841": [], "0415": [], "5402": [], "8472": [], "6837": [], "0444": 27, "5045": 27, "9586": [], "6829": [], "0447": [], "5379": 27, "8781": [], "6823": 27, "0464": 27, "9116": [], "6083": 27, "6816": [], "0900": 27, "5201": 27, "8951": [], "6809": 27, "0458": [], "5089": 27, "8897": [], "6801": [], "0454": [], "4799": 27, "9377": [], "6792": [], "0491": [], "8595": [], "6779": [], "0515": 27, "5134": 27, "9702": [], "5417": 27, "6898": 27, "0533": 27, "5246": 27, "9658": [], "5500": 27, "6872": [], "0551": 27, "4933": 27, "9663": [], "6850": [], "0470": [], "5223": 27, "9169": [], "6828": [], "0432": [], "0141": [], "6806": [], "0389": [], "9173": [], "6783": [], "0490": 27, "9557": [], "6333": [], "6759": [], "0511": [], "4955": 27, "9721": [], "6732": [], "0542": [], "8938": [], "6703": [], "0528": [], "9590": [], "6673": [], "0535": [], "9674": [], "5357": 27, "6901": 29, "0512": [], "4643": 27, "0456": [], "5179": 27, "6896": 27, "0448": [], "9567": [], "6892": [], "0509": [], "5112": 27, "9992": [], "6888": 27, "8963": 27, "6885": [], "0562": [], "5067": 27, "9243": [], "6880": [], "0572": [], "5446": 27, "6875": [], "9621": [], "6871": [], "0545": [], "4777": 27, "9535": [], "0459": [], "4710": 27, "9677": [], "9475": [], "6931": 27, "0496": [], "0016": [], "6928": 27, "0513": 27, "4888": 27, "9268": [], "6925": [27, 29], "0467": [], "6922": 27, "0506": [], "9517": [], "6918": [], "0425": [], "9222": [], "6912": 27, "0442": [], "9051": 27, "6905": 29, "0324": [], "9531": [], "0401": [], "9489": 27, "6891": [], "0424": [], "4978": 27, "9368": [], "6886": 27, "0381": [], "9003": [], "0417": [], "9302": [], "6771": 27, "0504": [], "6760": [], "0476": [], "4821": 27, "9575": [], "6750": 27, "9342": [], "6741": [], "9132": [], "6731": [], "0532": [], "6721": [], "0544": [], "5424": [], "8900": [], "5714": 27, "6710": [], "9138": [], "5804": 27, "6700": [], "0604": [], "9628": [], "5893": 27, "6690": [], "0554": [], "7355": [], "5333": 27, "1920": [76, 77, 78, 79], "7237": 27, "5167": 27, "6937": 27, "1859": 27, "7347": [], "4917": 27, "1950": [], "7321": 27, "6929": 27, "1918": 27, "4866": 27, "7287": [], "5250": 27, "6930": 27, "7390": [], "1887": [], "4732": 27, "7831": [], "6934": [27, 29], "1986": [], "7372": 27, "1878": 27, "7595": [], "4911": 27, "1870": [], "7389": [], "6946": 27, "1881": [], "7284": [], "6945": [], "1869": [], "7520": [], "1852": [], "7335": [], "6943": 27, "1846": [], "7312": [], "1867": [], "1936": [], "5737": 27, "7014": 29, "1842": [], "5580": [], "7129": [], "6924": 27, "6921": 27, "1908": [], "5290": 27, "7084": 27, "1895": [], "7209": 27, "6916": 27, "1856": 27, "5558": [], "6838": 27, "6914": 27, "1837": [], "7132": [], "1958": [], "7013": [], "6911": [], "6887": [], "6909": 27, "5759": 27, "6969": [], "1851": 27, "6907": 29, "8867": [], "5833": [], "7748": [], "7551": [], "8407": [], "5583": [], "9758": [], "7607": [], "8136": [], "8091": [], "7668": [], "5513": 27, "7877": [], "7888": [], "5670": [], "5750": 27, "6761": [], "7630": [], "9496": [], "4833": 27, "9299": [], "7588": [], "8457": [], "7850": [], "7544": [], "8245": [], "7341": 27, "7594": 27, "7769": [], "7109": [], "7518": 27, "5826": [], "8032": [], "7575": 27, "9490": [], "9558": [], "7561": 27, "8375": [], "9280": [], "7556": [], "5871": [], "7990": 27, "7928": [], "7466": [], "6071": 27, "8078": [], "6746": [], "7519": [], "5603": [], "7828": [], "5999": [], "7569": [], "9390": [], "8534": [], "7613": 27, "8981": [], "7521": [], "7477": [], "8441": [], "7348": [], "8036": [], "7023": [], "5982": [], "6742": [], "7657": [], "8681": [], "6518": [], "6613": [], "7667": [], "7723": 27, "6607": 27, "6204": [], "7452": 27, "7529": [], "7054": [], "5836": [], "7670": 27, "6994": [], "7232": [], "5675": [], "7570": [], "296k": [], "604k": [], "45mb": [], "38m": [], "56m": [], "665k": [], "12m": [], "62mb": [], "1gb": [], "9867": [], "6962": 27, "9637": [], "0465": [], "9875": [], "0364": [], "9360": [], "0403": [], "9903": [], "0446": 27, "9762": [], "9155": [], "6897": [27, 29], "0502": 27, "9850": [], "0489": [], "9809": [], "6879": [], "0439": [], "9432": [], "0436": [], "4554": 27, "0125": [], "3571": [], "0517": [], "0102": [], "3929": 27, "0374": [], "0082": [], "4018": 27, "7155": 27, "5286": 27, "9036": [], "5673": 27, "6935": 27, "9065": [], "5208": 27, "8991": [], "4808": [], "9010": 27, "5052": [], "9895": [], "4904": 27, "9081": [], "4576": 27, "9355": [], "0553": [], "9823": [], "6882": [], "0369": [], "8910": [], "6878": 27, "0327": [], "9600": [], "6874": [27, 29], "0365": [], "9251": [], "0355": [], "8774": [], "0370": [], "9521": 27, "0390": [], "9585": [], "6858": [], "0371": [], "8971": [], "6855": 27, "0483": [], "9494": [], "0507": [], "4818": [], "9675": [], "5288": 27, "6932": [27, 29], "9032": [], "8960": [], "5192": 27, "9038": [], "8389": [], "8970": [], "5234": 27, "9498": [], "9109": [], "5182": 27, "8601": [], "5096": 27, "8935": [], "4948": 27, "9401": [], "6927": 27, "8949": [], "9359": [], "6926": 27, "9286": [], "5130": 27, "8834": [], "8880": [], "9651": [], "8930": [], "5026": [], "9493": [], "6923": 27, "8948": [], "5022": 27, "7134": 27, "1845": [], "5491": 27, "7009": [], "6938": 27, "1844": [], "1840": [], "7329": [], "6936": 27, "1841": [], "7167": 29, "1855": [], "7371": [], "5385": 27, "1614": [], "7511": [], "1595": [], "4922": 27, "1594": [], "7633": [], "6933": 27, "4665": 27, "7590": [], "7394": [], "1582": [], "4712": 27, "1602": 92, "7024": 27, "1578": [], "9050": [], "4286": 27, "8069": [], "7490": [], "8636": [], "9869": [], "7459": [], "8161": [], "7560": [], "7906": [], "7716": [], "5335": 27, "7790": [], "7497": [], "7510": [], "8833": [], "1230": [], "7514": [], "8304": [], "7775": [], "7632": 27, "8444": [], "8547": [], "8049": [], "4107": 27, "8532": [], "7536": [], "4609": 27, "9349": [], "6462": [], "8608": [], "6707": [], "6541": [], "8657": [], "1806": 29, "6393": [], "5260": 27, "8144": [], "9011": [], "6481": [], "8213": [], "8225": [], "6483": [], "8460": [], "8518": [], "7383": [], "7566": [], "8623": [], "7679": 27, "8279": [], "7980": [], "7426": [], "5104": [], "8633": [], "2202": [], "6408": [], "5078": 27, "7995": [], "6535": [], "4792": 27, "8832": [], "7899": [], "6373": [], "8430": [], "8064": [], "6457": [], "5443": [], "8118": [], "7916": [], "6463": [], "529755": [], "braindecode_shallowfbcspnet": 27, "506535": [], "braindecode_eegnetv4_resampl": 27, "505883": [], "566102": [], "599238": [], "516589": [], "eegnetv4": [27, 29], "santamaria": [27, 48], "vazquez": [27, 48], "martinez": 27, "cagig": [27, 48], "vaquerizo": 27, "villar": 27, "hornero": [27, 48], "novel": [27, 182], "assist": 27, "erp": [27, 34, 86, 87, 89, 90, 91, 131, 136, 140, 145, 146, 149, 181, 184, 187], "transact": [27, 70, 73, 85, 97, 99, 100, 104], "rehabilit": [27, 70, 73, 99, 100, 104], "573": 187, "590": [], "plot_benchmark_braindecod": [27, 38], "ylm": 28, "name__estim": 28, "name_paramet": 28, "lower": [28, 59, 96, 99, 100], "capit": [28, 187], "letter": [28, 74, 86, 93, 94], "previou": [28, 33, 39, 45, 46, 72, 100, 103], "pipelines_grid": 28, "943531": 28, "937954": 28, "943619": 28, "829": [], "plot_benchmark_grid_search": [28, 38], "procedur": [29, 44, 80, 81, 83, 92, 99, 100, 102, 183, 187], "reduc": [29, 33, 44, 87, 128], "real": [29, 89, 90, 99, 102], "situat": 29, "300": [29, 35, 48, 84, 92, 93], "abl": [29, 74, 84], "oper": [29, 63, 88, 102, 103, 129], "determinist": 29, "backend": [29, 187], "cudnn": 29, "0625": 29, "taken": [29, 69, 152, 155, 156, 157, 158, 159, 160, 168, 170], "tmin": [29, 34, 132, 133, 137, 140, 142, 143, 144, 145, 146, 148, 149, 150, 151], "mandatori": [29, 172], "dynam": [29, 102], "braindecode_exampl": 29, "moabb_result": 29, "7659": 29, "2023": [1, 47, 76, 77, 78, 79, 102, 103, 161, 176], "7363": [27, 29], "1773": [], "7591": [27, 29], "6919": [27, 29], "1779": [], "6669": 29, "6913": 29, "6621": 29, "1925": [], "7085": 29, "6903": [27, 29], "1760": [], "7184": 29, "6900": [29, 48, 89], "1750": [], "1819": 29, "6647": 29, "6894": [27, 29], "6890": 29, "1745": [99, 100], "7365": [27, 29], "1775": [], "6883": 29, "6824": [27, 29], "7060": 29, "1799": 29, "7151": 29, "1754": [], "7221": 29, "1945": [], "7016": [27, 29], "7032": 29, "1748": [], "6593": 29, "7025": 29, "1756": [], "7019": [27, 29], "6745": 29, "1759": [], "7449": 29, "6832": 29, "1725": [], "7881": 29, "1717": [], "7344": 29, "1746": 104, "1724": [], "7438": 29, "1721": [], "521026": 29, "037027": [], "144": [29, 30, 42, 48], "494985": 29, "012517": [], "493441": 29, "883710": [], "544367": 29, "859620": [], "barplot": [29, 37, 44], "viridi": [29, 31, 37, 44, 45, 46], "261": [5, 10, 187], "plot_braindecod": [29, 38], "context": [30, 31, 60, 92, 126, 127, 128, 129], "leav": [30, 31, 187], "950424": 30, "261370": [], "962963": 30, "247730": [], "574846": 30, "299307": [], "585648": 30, "263763": [], "931713": 30, "303308": [], "plot_cross_session_motor_imageri": [30, 38], "assign": [30, 126, 127, 128, 129, 187], "deprec": [30, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 116, 122, 187], "871": [], "285": [], "spatial": [31, 72, 75, 101, 152, 153, 154], "pattern": [31, 89, 102, 103, 105], "otherwis": [31, 37, 44, 93, 108, 151, 152, 153, 155, 156, 157, 158, 159, 160], "accord": [31, 37, 63, 71, 73, 75, 85, 86, 90, 99, 100, 101, 103, 104, 106, 107, 153], "x_all": 31, "labels_al": 31, "meta_al": 31, "851412": 31, "386326": [], "935200": 31, "239445": [], "219": 31, "939200": 31, "270044": [], "908000": 31, "245108": [], "190": 31, "770370": 31, "217779": [], "catplot": [31, 45, 46], "col": [31, 45, 46], "bar": [31, 32, 45, 46, 69, 76, 77, 78, 79, 187], "292": 187, "254": [], "plot_cross_session_multiple_dataset": [31, 38], "four": [32, 67, 68, 69, 70, 71, 76, 77, 78, 79, 84, 85, 91, 97, 98, 101, 102, 104, 182], "cca": [32, 37, 151, 152, 153, 187], "trca": [32, 153, 187], "msetcca": [32, 152, 187], "kalunga2016": [32, 48, 183], "crosssubjectevalu": 32, "filterbankssvep": [32, 60], "ssvep_cca": [32, 37], "ssvep_trca": 32, "extendedssvepsign": 32, "ssvep_msetcca": 32, "ssvep_exo": 32, "stimul": [32, 37, 61, 62, 65, 72, 76, 77, 78, 79, 81, 83, 92, 93, 94, 101, 102, 104, 132, 133, 137, 142, 150, 151, 152, 187], "thu": [32, 71, 104], "rest": [32, 39, 61, 69, 88, 89, 90, 91, 92, 93, 94, 96, 98, 99, 100, 101, 104, 105, 107, 182, 187], "pick": [32, 128], "n_subject": [32, 122], "stimuli": [32, 48, 71, 76, 77, 78, 79, 83, 89, 91, 92, 98, 104], "harmon": [32, 151], "wide": 32, "center": [32, 69, 70, 73, 90, 91, 99, 100, 105, 137], "paradigm_trca": 32, "paradigm_mset_cca": 32, "paradigm_fb": 32, "freq": [32, 34, 37, 48, 92, 137, 151, 152, 153, 163, 187], "used_ev": [32, 35, 37, 150], "around": [32, 69, 73, 86, 99, 100, 101, 137], "plane": 32, "abov": [32, 39, 47, 86, 92, 99, 100, 176, 177, 178], "third": 32, "fourth": 32, "logreg": 32, "multi_class": 32, "n_harmon": [32, 37, 151], "pipelines_trca": 32, "pipelines_mset_cca": 32, "mset_cca": 32, "zenodo": [1, 39, 44, 47, 76, 77, 78, 79, 80, 81, 176], "265kb": [], "156k": [], "312k": [], "493k": [], "737k": [], "934k": [], "991kb": [], "34m": [], "38mb": [], "64m": [], "93m": [], "5gb": [], "3k": [], "122kb": [], "108k": [], "295k": [], "461k": [], "641k": [], "853k": [], "26m": [], "47m": [], "85m": [], "46m": [], "85gb": [], "784": [], "58m": [], "132kb": [], "100k": [], "455kb": [], "223k": [], "411k": [], "656k": [], "967k": [], "23m": [], "51m": [], "36mb": [], "37mb": [], "27mb": [], "28mb": [], "117kb": [], "104k": [], "208k": [], "358k": [], "522k": [], "751k": [], "898kb": [], "980k": [], "18m": [], "39m": [], "59m": [], "83m": [], "09gb": [], "crosssubject": 60, "05it": [], "determin": [32, 60, 71, 128, 129], "evaluation_fb": 32, "25it": [], "17it": [], "18it": [], "evaluation_trca": 32, "results_trca": 32, "15it": [], "evaluation_mset_cca": 32, "results_mset_cca": 32, "54it": [], "55it": [], "830": [], "plot_cross_subject_ssvep": [32, 38], "speed": [33, 86, 101, 153, 182, 187], "subsequ": [33, 71, 99, 102, 104], "raw_pipelin": [33, 107], "Then": [33, 35, 97, 105], "epochs_pipelin": [33, 107], "eventu": [33, 187], "array_pipelin": [33, 107], "cacheconfig": [33, 34, 107, 145], "save_epoch": [33, 108], "save_arrai": [33, 108], "overwrite_raw": [33, 108], "overwrite_epoch": [33, 108], "overwrite_arrai": [33, 108], "directli": [33, 39, 46, 179], "save_": [33, 108], "overwrite_": [33, 108], "until": [33, 68, 69, 97], "empti": [33, 187], "correspond": [33, 34, 60, 68, 70, 81, 86, 89, 90, 91, 93, 94, 97, 102, 104, 107, 108, 145, 151, 152, 153, 167, 187], "eras": 33, "miss": [33, 187], "compromis": 33, "whole": [33, 72, 84, 99, 104, 187], "except": [33, 80, 81, 96, 98], "default_cache_config": 33, "ones": [33, 102, 103], "And": [33, 35, 37], "desir": [33, 34, 68, 136, 140], "increas": [1, 33, 47, 82, 128, 176, 187], "t0": 33, "t_arrai": 33, "t_epoch": 33, "t_raw": 33, "t_nocach": 33, "2f": 33, "faster": 33, "littl": [33, 98], "would": [33, 34, 42, 44, 86, 132, 133, 137, 140, 142, 143, 145, 146, 148, 149, 150, 180], "greater": 33, "inde": [33, 35], "proport": [33, 86], "observ": [33, 76, 77, 78, 79, 93, 94, 153], "computation": [33, 55, 153], "heavi": 33, "postprocess_pipelin": [33, 34, 126, 127, 128, 129, 130, 145], "structur": [33, 81, 86, 107, 123], "plot_bids_convers": 33, "aspect": [33, 46, 81], "descript": [33, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 89, 90, 91, 96, 101, 102, 103, 107, 182, 187], "hash": [33, 117], "uniqu": [33, 34, 35, 107, 153, 187], "identifi": [33, 89, 107, 151, 152, 153], "were": [33, 35, 45, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 180], "_lockfil": 33, "root": [33, 179, 180], "purpos": [33, 85, 97, 102, 116, 122, 123], "present": [33, 48, 68, 69, 70, 72, 75, 76, 77, 78, 79, 82, 83, 84, 85, 89, 91, 93, 94, 96, 98, 101, 102, 103, 105, 106, 151, 152, 183], "someth": [33, 48], "went": [33, 70, 106], "wrong": [33, 187], "incomplet": 33, "string": [33, 44, 93, 94, 107, 124, 135, 136, 139, 140, 141, 144, 145, 146, 149, 187], "represent": 33, "therefor": [33, 34, 35, 89, 91, 102, 107], "901": [], "234": [], "plot_disk_cach": [33, 38], "binari": [34, 102, 103, 121, 132, 133], "multiclass": [34, 83], "kappa": 34, "coeffici": [34, 71, 151, 152, 153], "filterbankmotorimageri": [34, 60], "float": [34, 52, 53, 104, 122, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 153], "cutoff": [34, 72, 132, 138, 140, 142, 143, 148], "high": [34, 48, 72, 85, 91, 93, 94, 98, 101, 138, 140, 142, 143, 148, 153], "rel": [34, 35, 84, 86, 87, 132, 133, 137, 140, 142, 143, 145, 146, 148, 149, 150], "task": [34, 44, 61, 68, 69, 73, 74, 75, 76, 77, 78, 79, 87, 89, 90, 91, 96, 97, 99, 100, 105, 106, 132, 133, 137, 140, 142, 143, 145, 146, 148, 149, 150, 153, 182, 183], "tupl": [34, 41, 107, 122, 128, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150], "endpoint": [34, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150], "period": [34, 48, 69, 70, 73, 75, 76, 77, 78, 79, 92, 93, 94, 99, 100, 104, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150], "subtract": [34, 75, 100, 107, 131, 132, 133, 134, 137, 138, 140, 142, 143, 145, 146, 148, 149, 150, 187], "least": [34, 42, 70, 86, 101, 107, 126, 145], "boolean": [34, 145], "flag": [34, 108, 145], "whether": [34, 44, 107, 108, 121, 145], "return_raw": [34, 126, 127, 128, 129, 130, 145], "mutual": [34, 145], "exclus": [34, 145], "receiv": [34, 60, 69, 73, 107, 129, 145, 187], "baseraw": [34, 107, 129, 145], "func": [25, 28, 29, 30, 34], "union": [34, 108, 128, 145, 151, 152, 153, 155, 156, 157, 158, 159, 160], "known": [34, 69, 172], "iia": [34, 68], "supersed": 34, "feet": [34, 61, 68, 69, 73, 75, 97, 98, 105, 106, 107], "tongu": [34, 68, 107], "3d": [34, 44], "dimens": [34, 44, 85, 104, 172], "id": [34, 62, 64, 65, 66, 67, 80, 82, 95, 107, 117, 118, 119, 120, 126, 127, 128, 129], "denot": [34, 82], "cap": [34, 99, 100, 101, 107], "individu": [34, 75, 92, 93, 94, 102], "dai": [34, 42, 63, 68, 70, 75, 84, 88, 96, 106, 107], "count": [34, 89, 103], "nan": 34, "top": [34, 42, 71, 89, 97, 107], "288": [34, 48, 68], "std": [34, 98], "min": [34, 99, 100], "max": [34, 151], "compatible_dataset": 34, "alexandremotorimageri": 34, "002": [34, 69], "bnci2015": 34, "fakedataset": [34, 42, 187], "ofner2017": [34, 42, 48, 187], "4d": 34, "variat": [34, 92, 93, 94, 153, 183], "basemotorimageri": 34, "roc_auc": [34, 135, 139, 141, 150], "imagin": [34, 61, 70, 82, 85, 96, 97, 99, 106, 183], "760": [], "plot_explore_paradigm": [34, 38], "fixedintervalwindowsprocess": [35, 187], "stim": [35, 39, 92, 107, 122, 131, 134, 138, 145, 187], "unfortun": 35, "unsupervis": [35, 86, 87], "start_offset": [35, 131, 134, 138], "stop_offset": [35, 131, 134, 138], "parametris": [35, 187], "onset": [35, 62, 65, 71, 76, 77, 78, 79, 81, 86, 87, 101, 104], "consecut": [35, 101, 104, 106], "offset": [35, 39, 86, 87, 104, 131, 134, 138], "900": 35, "filterbankfixedintervalwindowsprocess": [35, 187], "recov": 35, "_get_events_pipelin": 35, "events_pipeline_dataset": 35, "events_pipeline_fix": 35, "events_dataset": 35, "events_fix": 35, "event_id": [35, 187], "artifici": 35, "viz": 35, "plot_ev": 35, "sfreq": [35, 39, 122, 153], "subplots_adjust": 35, "122": 35, "plot_fixed_interval_window": [35, 38], "309k": [], "608k": [], "11m": [], "96m": [], "35mb": [], "148k": [], "637k": [], "97mb": [], "77mb": [], "6gb": [], "783": [], "plot_within_session_p300": [36, 38], "mamem": [37, 92, 93, 94], "assess": [37, 44, 46, 153, 183], "mamem3": [37, 48, 183, 187], "canon": [37, 95, 151, 152], "correl": [37, 95, 151, 152, 153], "236": 37, "194": 37, "688889": 37, "048510": [], "266667": 37, "047818": [], "xlabel": 37, "ylabel": 37, "red": [37, 59, 91, 104, 105, 106], "605": [], "plot_within_session_ssvep": [37, 38], "312": [25, 28, 29, 30], "auto_exampl": 38, "102": [], "233": [], "759": [], "253": [], "plcrodrigu": [39, 41, 44, 45, 46], "workshop": [39, 41, 44, 45, 46, 187], "graz": [39, 41, 44, 45, 46, 63, 73, 75, 101, 187], "scipi": 39, "loadmat": 39, "savemat": 39, "basedataset": [39, 81, 123, 130, 145, 150, 187], "illustr": [39, 41, 182], "mat": [39, 44, 80, 81, 104], "150": [39, 48, 76, 77, 78, 79, 85, 87, 98, 187], "256": [39, 48, 71, 72, 74, 75, 92, 93, 187], "upload": 39, "create_example_dataset": 39, "t_record": 39, "t_trial": 39, "durat": [39, 61, 66, 75, 84, 86, 87, 92, 101, 102, 103, 104, 122, 126, 127, 128, 129], "intertri": 39, "n_chan": 39, "stimulu": [39, 62, 71, 76, 77, 78, 79, 81, 83, 84, 86, 87, 89, 91, 92, 93, 94, 101, 104, 137, 142, 150, 152], "t_offset": 39, "where": [39, 42, 44, 45, 46, 48, 59, 61, 62, 63, 64, 65, 66, 67, 73, 80, 81, 82, 83, 84, 85, 88, 91, 92, 93, 94, 95, 96, 97, 98, 101, 102, 104, 105, 106, 107, 108, 115, 116, 122, 132, 133, 162, 183, 187], "n_trial": [39, 153, 162], "rep": 39, "linspac": 39, "sin": 39, "pi": 39, "altern": [39, 99, 100], "tn": 39, "nois": [39, 44, 48, 68, 92, 102, 103, 104], "randn": 39, "filenam": [39, 83, 118, 120], "subject_": 39, "zfill": [39, 45, 46], "mdict": 39, "simul": 39, "global": 39, "tell": 39, "url": [1, 39, 47, 115, 116, 121, 176, 187], "fetch": 39, "overload": [39, 145], "exampledataset_url": 39, "sandbox": 39, "369543": 39, "_get_single_subject_data": 39, "data_path": [39, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 115, 122, 187], "exemplifi": 39, "physiolog": [39, 81, 97, 99, 100], "whatsoev": 39, "super": 39, "sessions_per_subject": [39, 107], "file_path_list": 39, "ch_name": [39, 187], "ch": 39, "ch_type": 39, "create_info": 39, "rawarrai": 39, "force_upd": [39, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 115, 116, 122], "update_path": [39, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 102, 103, 104, 105, 106, 107, 116, 122, 187], "rais": [39, 60, 126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 151, 152, 153, 155, 156, 157, 158, 159, 160, 173], "valueerror": 39, "invalid": 39, "subject_0": 39, "data_dl": [39, 116, 187], "newdataset": [39, 41], "server": [39, 187], "like": [39, 42, 44], "figshar": [39, 92, 93, 94, 117, 118, 119, 120, 121, 187], "dedic": [1, 39, 47, 176], "4_adding_a_dataset": [39, 43], "auto_tutorials_python": 40, "auto_tutorials_jupyt": 40, "braininvad": [41, 113, 187], "bi2014a": [41, 48, 109, 183], "compound_dataset": [41, 187], "compounddataset": [41, 187], "blocks_rep": 41, "few": [41, 153], "customdataset1": 41, "accept": [41, 44, 99, 100, 107, 145, 187], "subjects_list": 41, "bivr": 41, "screen_displai": [41, 81], "n_repetit": 41, "0vr": 41, "customdataset2": 41, "bi2014": 41, "forward": 41, "customdataset3": 41, "noth": [41, 145], "normal": [41, 70, 187], "noplot_tutorial_5_build_a_custom_dataset": [41, 43], "submodul": [42, 178], "gridsearchcv": [42, 187], "logvari": 42, "coupl": 42, "wise": 42, "varianc": 42, "cannot": [42, 101], "later": [42, 69, 70, 71, 98], "am": [42, 99, 100], "logspac": 42, "properti": [42, 131, 135, 136, 139, 140, 141, 144, 145, 146, 149, 150], "0x7f7388e47ac0": [], "0x7f7388e472e0": [], "gigadb": [42, 44, 187], "0x7f7388e47dc0": [], "mpi_mi": [42, 44], "0x7f7388e47370": [], "lee2019_mi": [42, 44, 48, 183], "0x7f7388e47c70": [], "physionet_mi": [42, 44], "physionetmi": [42, 44, 48, 183, 187], "0x7f7388e47100": [], "0x7f7388e47940": [], "bbci_eeg_fnir": [42, 44], "0x7f7388e473a0": [], "0x7f7388e47160": [], "0x7f7388e47c10": [], "Or": 42, "dataset_search": [42, 187], "min_subject": [42, 124], "alex_mi": 42, "0x7f7388e47670": [], "0x7f7388e475e0": [], "bnci2014_002": [42, 48, 183], "0x7f7388e47730": [], "0x7f7388e47df0": [], "bnci2015_001": [42, 48, 183], "0x7f7388e47a30": [], "bnci2015_004": [42, 48, 183], "0x7f7388e477f0": [], "0x7f7388e47610": [], "upper_limb": 42, "0x7f7388e47f70": [], "0x7f7388e47e50": [], "0x7f7388e47070": [], "0x7f7388e47790": [], "0x7f7388e471f0": [], "constraint": [42, 86, 101], "thread": [42, 60], "797068": 42, "148652": [], "773920": 42, "141344": [], "550733": 42, "249985": [], "471451": 42, "169281": [], "786458": 42, "022494": [], "828": [], "258": 187, "plot_getting_start": [42, 43], "033": [], "auto_tutori": 43, "tutorial_3_benchmarking_multiple_pipelin": [43, 46], "289": 25, "tutorial_1_simple_example_motor_imageri": [43, 44], "224": [], "559": [], "tutorial_2_using_mulitple_dataset": [43, 45], "055": [], "156": 187, "257": [6, 10, 18, 20, 187], "thing": [44, 179], "might": 44, "gdf": [44, 187], "manipul": [44, 94], "enough": [44, 92, 98, 126, 127, 128, 129], "session_nam": 44, "run_nam": 44, "respons": [44, 64, 65, 66, 67, 83, 86, 87, 89, 92, 117, 118, 119, 120, 121], "sens": 44, "0x7f73887a3be0": [], "0x7f746f20abe0": [], "0x7f746f20abb0": [], "0x7f738882bac0": [], "0x7f746f20a790": [], "0x7f746f20a400": [], "0x7f746f20a130": [], "0x7f746f3a8f70": [], "0x7f746f3a8550": [], "0x7f746f3a8610": [], "regard": [44, 183], "previous": [44, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 80, 81, 85, 88, 92, 109, 110, 111, 112, 113, 114, 153], "sai": 44, "recalcul": 44, "partit": 44, "form": [44, 68, 69, 88, 93, 94, 151], "recomput": [44, 46], "export": 44, "csv": [44, 80, 81], "to_csv": 44, "results_part2": 44, "read_csv": 44, "term": [44, 99, 100, 107], "integ": [44, 92], "why": [44, 84], "orient": [44, 45, 46, 58], "560": [], "relev": [45, 151, 152, 153, 155, 156, 157, 158, 159, 160, 187], "critic": [45, 46, 174], "restart": 45, "scratch": [45, 180], "occur": [45, 75, 86, 101, 126, 127, 128, 129], "resi": [45, 46], "part": [46, 70, 82, 83, 92, 99, 100, 101, 187], "classici": 46, "gather": [46, 48, 104], "seen": [46, 48], "tgsp": 46, "height": 46, "paper": [1, 47, 82, 84, 89, 90, 91, 96, 150, 153, 155, 156, 157, 158, 159, 160, 168, 176, 183, 187], "visibl": [1, 47, 72, 176], "bjareholt": [1, 47, 176], "quentin": [1, 47, 88, 176, 187], "kalunga": [1, 47, 88, 176, 187], "darmet": [1, 47, 76, 77, 78, 79, 176, 187], "abdul": [1, 47, 176, 187], "hussain": [1, 47, 176, 187], "gatti": [1, 47, 176, 187], "goncharenko": [1, 47, 83, 176, 187], "thielen": [1, 47, 48, 102, 103, 176, 187], "moreau": [1, 47, 176, 187], "roi": [1, 47, 176], "mother": 47, "5281": [1, 47, 76, 77, 78, 79, 80, 81, 176], "10034223": [1, 47, 176], "bibtex": [1, 47, 176], "aristimunha_mother_of_all_2023": [1, 47, 176], "erik": [1, 47, 176, 187], "barthelemi": [1, 47, 88, 176, 187], "robin": [1, 47, 98, 176, 187], "tibor": [1, 47, 98, 176], "emmanuel": [1, 47, 88, 176, 187], "ludov": [1, 47, 76, 77, 78, 79, 176, 187], "ali": [1, 47, 176, 187], "ramiro": [1, 47, 176, 187], "vladislav": [1, 47, 176, 187], "jordi": [1, 47, 102, 103, 176, 187], "thoma": [1, 47, 176, 187], "yannick": [1, 47, 176], "year": [1, 47, 69, 82, 83, 85, 88, 96, 104, 176], "trustworthi": [1, 47, 176], "066011": [1, 47, 176], "1088": [47, 48, 103, 151, 158, 168, 176], "1741": [47, 48, 103, 151, 158, 168, 176], "2552": [47, 48, 103, 158, 168, 176], "entri": [47, 60, 107, 176], "articl": [47, 92, 93, 94, 95, 105, 106, 119, 121, 176], "moabb2018": [47, 176], "volum": [47, 76, 77, 78, 79, 97, 176], "iop": [47, 176], "contact": [47, 99, 100], "wiki": [1, 47, 83, 176], "summar": [48, 75], "hesit": 48, "warmli": 48, "supplementari": 48, "licenc": [48, 99, 100, 107, 187], "chan": [48, 61, 63, 76, 77, 78, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106], "total_tri": 48, "512hz": [48, 61, 63, 82, 96, 103], "250hz": [48, 92, 93, 104, 106, 153], "62208": 48, "17920": 48, "360": 48, "32400": 48, "14400": 48, "256hz": [48, 88, 95], "7200": [27, 48], "9800": 48, "1000hz": [48, 86, 87, 89, 90, 91, 101], "11000": 48, "500hz": [48, 76, 77, 78, 83, 85, 98], "3000": 48, "13440": 48, "63000": 48, "109": [48, 97], "160hz": [48, 97], "69760": 48, "200hz": [48, 99, 100, 105], "5220": 48, "shin2017b": [48, 187], "5600": 48, "11496": 48, "bnci2014_008": [48, 183], "3500": 48, "nt": [48, 63, 83, 84, 86, 87, 89, 101, 102, 103], "700": 48, "1440": 48, "bnci2015_003": [48, 183], "1500": [48, 97, 101, 104], "bi2012": [48, 183], "640": [48, 63], "128hz": [48, 94], "bi2013a": [48, 183], "3200": [48, 63], "198": [48, 187], "bi2014b": [48, 110, 183], "bi2015a": [48, 67, 111, 183], "4131": 48, "825": 48, "bi2015b": [48, 112, 183], "2160": 48, "600": [48, 62, 81, 101], "huebner2017": [48, 183, 187], "364": [48, 86, 87, 187], "112": [48, 86, 87, 153, 187], "huebner2018": [48, 183, 187], "sosulski2019": [48, 183, 187], "7500": [48, 101], "epflp300": [48, 183], "2753": [48, 84], "551": [48, 84], "2048hz": [48, 84, 102], "lee2019_erp": [48, 183], "1380": [48, 89], "lee2019_ssvep": [48, 183, 187], "mamem1": [48, 183, 187], "mamem2": [48, 183, 187], "nakanishi2015": [48, 183, 187], "wang2016": [48, 183, 187], "neuro": 48, "psuedo": 48, "sequenc": [48, 76, 77, 78, 79, 84, 88, 89, 94, 96, 103, 105, 132, 133, 178], "gold": [48, 102, 103], "arbitrari": 48, "review": [48, 68, 87, 187], "mart\u00ednez": 48, "p\u00e9rez": 48, "velasco": 48, "desain": [48, 102, 103], "2021": [48, 101, 103], "evok": [48, 65, 71, 72, 92, 93, 94, 95, 101, 102, 103], "potenti": [48, 62, 65, 71, 72, 81, 83, 87, 92, 93, 94, 95, 101, 102, 103, 178], "061002": 48, "ac38cf": 48, "thielen2015": 48, "27216": [48, 102], "120hz": [48, 102], "thielen2021": [48, 187], "18900": 48, "60hz": [48, 76, 77, 78, 103], "castilloscvep100": [48, 187], "3525": 48, "3495": 48, "castilloscvep40": 48, "castillosburstvep40": 48, "5820": 48, "1200": [48, 92], "burst": [48, 76, 77, 78, 79], "cvep": [48, 76, 77, 124, 187], "castillosburstvep100": 48, "recod": 48, "he": 48, "ey": [48, 70, 75, 86, 93, 94, 97, 99, 100, 101, 104], "close": [48, 96, 97, 99, 101], "merg": 48, "bi2014a_il": 48, "bi2014b_il": 48, "bi2015a_il": 48, "bi2015b_il": 48, "cattan2019_vr_il": 48, "bi_il": 48, "mention": [48, 60], "radar": 48, "inclus": 48, "prepar": [51, 90, 101, 105, 106, 145, 150, 162], "aggreg": 51, "nsub": [52, 53], "estimat": [52, 53], "pval": 53, "stouffer": 53, "perm_cutoff": [54, 55], "threshold": [54, 55], "wilcoxon": [54, 55], "tabl": [54, 55, 72, 183, 187], "expens": [55, 182], "sum": 55, "dfp": 55, "n_pipelin": 55, "dft": 55, "sign": [55, 76, 77, 78, 79, 83, 88, 100, 115, 116], "stats_df": 56, "alg1": [56, 57], "alg2": [56, 57], "confid": [56, 83], "larger": 56, "member": 57, "vertic": [58, 86, 99, 100, 187], "to_datafram": 58, "horizont": [58, 99, 100], "color_dict": 58, "sig_df": 59, "effect_df": 59, "p_threshold": 59, "matrix": [59, 71, 72, 86, 87, 104, 161], "heatmap": 59, "green": [59, 102, 103], "grei": 59, "n_jobs_evalu": [60, 126, 127, 128, 129], "exclud": [60, 92], "select_paradigm": 60, "recogn": [60, 69], "element": [60, 107], "bool": [60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 89, 90, 91, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 121, 122, 124, 126, 127, 128, 129, 130, 151, 152, 153, 155, 156, 157, 158, 159, 160, 166], "forc": [60, 61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 122], "parallel": [60, 126, 127, 128, 129, 187], "job": [60, 126, 127, 128, 129], "assum": [60, 86], "suitabl": 60, "eval_result": 60, "alex": 61, "phd": [61, 84, 88], "wet": [61, 63, 65, 66, 67, 76, 77, 78, 79], "fpz": [61, 76, 77, 78, 79, 99, 100, 104], "f7": [61, 75, 99, 100], "f3": [61, 72, 75, 99, 100], "fz": [61, 70, 71, 72, 74, 75, 99, 100, 103, 104], "f4": [61, 72, 75, 99, 100], "f8": [61, 75, 99, 100], "t7": [61, 63, 99, 100, 103], "t8": [61, 63, 99, 100, 103], "p7": [61, 63, 75, 99, 100], "p3": [61, 63, 71, 72, 74, 75, 83, 99, 100], "pz": [61, 63, 71, 72, 74, 75, 99, 100], "p4": [61, 63, 71, 72, 74, 75, 83, 99, 100], "p8": [61, 63, 75, 99, 100], "tec": [61, 71, 73, 75], "usbamp": [61, 69, 73, 75], "amplifi": [61, 63, 68, 69, 73, 75, 85, 86, 89, 90, 91, 99, 100, 101, 102, 103, 104], "actual": [61, 82, 92, 93, 94, 99, 101, 128], "movement": [61, 68, 70, 73, 75, 82, 84, 85, 86, 91, 96, 98, 99, 100, 105, 106, 183], "mne_datasets_": [61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122], "_path": [61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 108, 115, 116, 122], "prompt": [61, 62, 63, 64, 65, 66, 67, 68, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 122], "overrid": [61, 62, 63, 64, 65, 66, 67, 80, 81, 82, 83, 84, 85, 88, 95, 96, 97, 98, 101, 104, 105, 106, 107, 115, 116, 122], "invad": [62, 63, 64, 65, 66, 67], "setup": [62, 63, 76, 77, 78, 79, 84, 92, 102, 177], "carri": [62, 63, 68, 85], "univers": [62, 63, 88, 98, 102, 103], "alp": [62, 63], "inspir": 62, "famou": 62, "vintag": 62, "game": [62, 63, 64, 83], "taito": 62, "tokyo": 62, "japan": 62, "elicit": [62, 64, 65, 66, 67, 81, 89], "peak": [62, 81], "240": [62, 81], "took": [62, 64, 65, 66, 67, 82, 83, 86], "gipsa": [62, 63, 64, 65, 66, 67, 80, 81], "lab": [62, 63, 64, 65, 66, 67, 80, 81, 98, 187], "princip": [62, 63, 80], "sc": [62, 64, 65, 66, 67], "gijsbrecht": 62, "franciscu": 62, "petru": 62, "van": [62, 102], "veen": 62, "supervisor": [62, 63, 64, 65, 66, 67, 80], "ph": [62, 64, 65, 66, 67], "eng": [62, 64, 65, 66, 67, 80, 153], "anton": [62, 63, 64, 65, 66, 67, 187], "andreev": [62, 63, 64, 65, 66, 67, 81, 187], "gr\u00e9goir": [62, 64, 65, 66, 67, 80], "marco": [62, 63, 64, 65, 66, 67, 80], "congedo": [62, 63, 64, 65, 66, 67, 80, 81], "bi": 62, "1905": [27, 62], "05182": 62, "nonadapt": 63, "adapt": [63, 70, 73, 75, 92, 93, 94], "concern": [63, 81], "cnr": 63, "inp": 63, "2013": [27, 63, 71, 72], "eight": [63, 69, 71, 85, 92, 104], "classic": 63, "calibr": [63, 64, 66, 71, 76, 77, 78, 79, 102, 103, 153], "mode": [63, 179], "phase": [63, 76, 77, 78, 79, 89, 90, 91, 95, 102, 103, 104], "geometr": [63, 153], "incom": 63, "blind": 63, "appear": [63, 65, 68, 69, 71, 90, 97, 99, 100, 104, 105], "ident": [63, 166], "compos": [63, 69], "flash": [63, 64, 65, 66, 67, 84, 89, 93, 94, 102, 103], "symbol": [63, 64, 65, 66, 67, 75, 86, 87, 89, 102, 103], "400": [63, 84, 187], "destroi": 63, "henc": 63, "proce": 63, "unbalanc": 63, "quantifi": 63, "balanc": [63, 90, 102, 103], "acquir": [63, 72, 73, 95, 98, 103, 104], "nexu": 63, "tmsi": 63, "netherland": 63, "512": [26, 38, 63, 69, 73, 82, 103], "silver": 63, "chlorid": 63, "fp1": [63, 99, 100], "fp2": [63, 86, 99, 100], "f5": 63, "afz": [63, 75, 89, 90, 91], "f6": 63, "o1": [63, 75, 83, 103], "oz": [63, 71, 72, 74, 99, 100, 103], "o2": [63, 75, 83, 103], "ear": 63, "lobe": 63, "ground": [63, 68, 69, 70, 71, 72, 75, 76, 77, 78, 79, 86, 89, 90, 91, 98, 99, 100, 104], "erwan": 63, "vaineau": 63, "dr": [63, 80], "1904": [29, 63], "09111": 63, "plug": [63, 73], "plai": [63, 64, 65, 66, 67, 73, 83, 99, 100, 101], "1409": 63, "0107": 63, "goyat": 63, "tarrin": 63, "ionescu": 63, "rivet": 63, "varnet": 63, "phlypo": 63, "jrad": 63, "acquadro": 63, "jutten": 63, "2011": [63, 154], "prototyp": 63, "openvib": 63, "platform": 63, "proc": 63, "ibci": 63, "conf": 63, "austria": [63, 69, 71, 73, 75], "280": 63, "283": [18, 20, 63, 187], "videogam": [64, 66], "oddbal": [64, 65, 66, 67, 101], "dry": 64, "loui": [64, 65, 66, 67], "korczowski": [64, 65, 66, 67], "ekaterina": [64, 65], "ostaschenko": [64, 65], "violett": [64, 65, 66, 67], "gautheret": [64, 65, 66, 67], "hal": [1, 47, 64, 65, 66, 67, 80, 81, 176], "02171575": 64, "300m": 65, "solo1": 65, "solo2": 65, "solo": 65, "02173958": 65, "50m": 66, "2015": [66, 67, 73, 74, 75, 95, 102, 187], "martin": [66, 67], "cederhout": [66, 67], "02172347": [66, 67], "randomis": 67, "cooper": 67, "cue": [68, 69, 70, 72, 73, 75, 76, 77, 78, 79, 86, 88, 90, 96, 98, 102, 103, 104, 105, 106], "inat": 68, "compris": [68, 84, 96, 99, 100, 102, 103, 106], "break": [68, 70, 75, 82, 84, 101, 104, 105, 106, 107], "yield": [68, 71], "sit": [68, 70, 88], "comfort": [68, 76, 77, 78, 79, 88, 99, 100], "armchair": [68, 70, 99, 100], "front": [68, 71, 96, 99, 100], "screen": [68, 69, 70, 72, 75, 84, 86, 89, 90, 91, 92, 96, 97, 99, 100, 104, 105, 106], "fixat": [68, 70, 72, 75, 85, 88, 90, 91, 96, 99, 100, 102, 103, 104], "acoust": [68, 70], "tone": [68, 70, 101], "arrow": [68, 73, 85, 90, 93, 94, 98, 99, 106], "foot": [68, 105, 106], "stai": [68, 96], "disappear": [68, 69, 75, 97, 99, 100, 105], "twenti": [68, 70, 99], "ag": [68, 69, 72, 82, 83, 84, 85, 86, 88, 89, 90, 91, 96, 98, 102, 103, 104], "agcl": [68, 69, 72, 82, 86, 89, 90, 91, 102, 103], "inter": [68, 71, 75, 76, 77, 78, 79, 89, 98, 99, 100, 106], "distanc": [68, 69, 70, 86, 88, 99, 100], "cm": [68, 69, 73, 86, 88], "montag": [68, 82, 103], "shown": [68, 98, 99, 102, 182], "monopolarli": 68, "mastoid": [68, 69, 71, 72, 75, 99, 100], "250": [68, 70, 71, 86, 87, 92, 93, 99, 100, 104], "sensit": [68, 92], "\u03bcv": 68, "notch": [68, 70, 73, 75, 104], "suppress": 68, "m\u00fcller": [68, 69, 86, 96, 99, 100], "aertsen": 68, "birbaum": [68, 97], "braun": 68, "brunner": 68, "leeb": [68, 70], "mehr": 68, "miller": 68, "mueller": [68, 87], "putz": [68, 69, 96], "nolt": 68, "frontier": [68, 87], "neurosci": [68, 71, 74, 84], "bnci2014001": 68, "five": [69, 71, 75, 82, 84, 89, 92, 93, 94, 99, 100, 101, 103, 104], "togeth": [69, 166], "had": [69, 70, 76, 77, 78, 79, 84, 85, 89, 90, 91, 93, 94, 98], "kinaesthet": 69, "color": [69, 91, 102], "beep": [69, 70, 75, 96, 99, 100, 106], "sound": [69, 75, 96, 99, 100], "catch": 69, "attent": [69, 71, 72, 75, 105], "soon": [69, 104], "did": [69, 99, 100], "colour": 69, "graph": 69, "reflect": 69, "measur": [69, 72, 85, 96, 99, 100], "biosign": [69, 75], "ladybird": [69, 71, 75], "guger": [69, 73, 74, 75], "technologi": [69, 75], "og": 69, "schiedlberg": 69, "placement": [69, 70, 73, 102], "laplacian": [69, 73], "deriv": [69, 73, 99, 100, 102, 103, 172], "mount": [69, 80, 81], "naiv": [69, 83, 85, 99, 104], "medic": 69, "neurolog": 69, "diseas": 69, "steyrl": 69, "scherer": [69, 70, 73, 75], "faller": [69, 73, 75], "forest": [69, 83], "invas": [69, 98], "sensorimotor": 69, "rhythm": 69, "biomed": [69, 85, 97], "biomedizinisch": 69, "bnci2014002": 69, "vision": 70, "paid": 70, "volunt": [70, 71, 76, 77, 78, 79, 97], "watch": 70, "flat": [70, 86, 187], "approxim": [70, 84, 86, 93, 94], "awai": 70, "wherebi": 70, "bipolar": 70, "larg": [70, 84, 162], "anterior": 70, "posterior": 70, "slightli": 70, "electrooculogram": [70, 99, 100], "monopolar": 70, "week": [70, 84, 96], "six": [70, 72, 82, 84, 89, 96, 99, 100, 101, 102, 104, 105, 187], "ten": [70, 72, 85, 93, 94, 99], "person": [70, 81], "prior": [70, 76, 77, 78, 79, 93, 94, 145], "im": [70, 84, 86, 87], "ageri": 70, "bodi": [70, 84, 99, 100], "squeez": 70, "brake": 70, "khz": [70, 86], "afterward": [70, 90, 96], "smilei": 70, "grai": [70, 98], "lee": [70, 89, 90, 91], "keinrath": 70, "bischof": 70, "pfurtschel": 70, "motiv": [70, 82], "aim": [70, 183], "apart": 70, "473": [70, 187], "482": 70, "2007": [70, 84], "bnci2014004": 70, "008": 71, "farwel": 71, "donchin": 71, "amyotroph": 71, "sclerosi": 71, "charact": [71, 72, 86, 87, 89, 104, 105], "contest": 71, "na\u00efv": 71, "scalp": [71, 72, 75, 99, 100, 101, 104], "mobilab": 71, "po7": [71, 72, 74], "po8": [71, 72, 74], "earlob": [71, 72, 74], "spell": [71, 74, 86, 87, 89, 102], "seven": [71, 105], "predefin": 71, "word": [71, 75, 107], "control": [71, 74, 84, 86], "speller": [71, 72, 86, 87, 89, 102, 103, 153], "intensifi": 71, "isi": [71, 87, 89, 91], "lag": [71, 161], "asynchroni": [71, 86, 87, 101], "soa": [71, 86, 87, 101], "stepwis": 71, "swlda": 71, "riccio": 71, "simion": 71, "schettini": [71, 72], "pizzimenti": 71, "inghilleri": 71, "belardinelli": 71, "mattia": [71, 72], "cincotti": [71, 72], "hum": 71, "vol": [71, 72, 74, 95, 104], "pag": 71, "732": 71, "talk": 71, "mental": [71, 75, 100, 105], "prosthesi": 71, "eventrel": 71, "electroencephalogr": 71, "clin": 71, "neurophysiol": 71, "pagg": 71, "510": 71, "523": 71, "1988": 71, "bnci2014008": 71, "overt": 72, "healthi": [72, 83, 84, 85, 96, 98, 101, 104], "gaze": [72, 89, 91, 96, 99, 102, 103, 104], "intensif": 72, "femal": [72, 82, 85, 88, 96, 98, 104], "attend": [72, 87, 89, 101, 103], "central": [72, 85], "fcz": [72, 73, 75, 76, 77, 78, 79, 86], "cpz": [72, 73, 75], "cp3": [72, 73, 75], "cp4": [72, 73, 75], "respect": [72, 75, 89, 91, 94, 99, 100, 103, 106, 153], "aric\u00f2": 72, "alois": 72, "salinari": 72, "influenc": 72, "latenc": 72, "bnci2014009": 72, "fc3": [73, 75], "c5": 73, "c1": 73, "c2": 73, "fc4": [73, 75], "c6": 73, "acquisit": [73, 92, 99, 100], "hardwar": [73, 83, 88], "gammasi": [73, 75], "tech": 73, "nologi": 73, "oeg": 73, "sec": 73, "brisk": 73, "audibl": 73, "paus": [73, 76, 77, 78, 79, 88], "vidaurr": 73, "soli": 73, "escalant": 73, "neuper": 73, "autocalibr": 73, "recurr": 73, "313": 73, "319": [73, 187], "bnci2015001": 73, "003": 74, "daban": 74, "seller": 74, "holzner": 74, "krausz": 74, "carabalona": 74, "gramatica": 74, "edling": 74, "2009": [74, 85, 151], "462": 74, "bnci2015003": 74, "nine": [75, 96, 99, 100], "spinal": 75, "cord": 75, "injuri": 75, "stroke": 75, "ing": 75, "guid": [75, 151, 152, 153, 155, 156, 157, 158, 159, 160, 178, 182], "distinct": [75, 102, 103], "mt": 75, "sub": [75, 151, 152, 153, 155, 156, 157, 158, 159, 160], "navig": [75, 107, 182], "nav": 75, "t3": 75, "t4": 75, "p5": 75, "p1": 75, "p2": 75, "p6": 75, "po3": [75, 83], "po4": [75, 83], "middl": 75, "relax": [75, 97, 98, 106], "graphic": 75, "iti": 75, "blink": [75, 86, 88, 93, 94, 104], "began": [75, 90, 93, 94, 104], "friedrich": 75, "evc": 75, "opisso": 75, "costa": 75, "k\u00fcbler": 75, "plo": [75, 86, 95, 96, 102, 105, 106], "ONE": [75, 86, 102, 106], "1371": [75, 86, 95, 96, 102, 105, 106], "pone": [75, 86, 95, 96, 102, 105, 106], "0123727": 75, "bnci2015004": 75, "vep": [76, 77, 78, 79, 102, 103, 132, 133, 187], "castillo": [76, 77, 78, 79, 187], "5820nt": [76, 77], "1200t": [76, 77], "seat": [76, 77, 78, 79], "consent": [76, 77, 78, 79, 83, 88], "brainproduct": [76, 77, 78, 79], "liveamp": [76, 77, 78, 79], "500": [76, 77, 78, 79, 83, 85, 101, 104], "surfac": [76, 77, 78, 79], "acticap": [76, 77, 78, 79], "imped": [76, 77, 78, 79, 85, 86, 89, 90, 91, 101, 104], "brought": [76, 77, 78, 79], "25kohm": [76, 77, 78, 79], "equip": [76, 77, 78, 79], "cu": [76, 77, 78, 79], "sequenti": [76, 77, 78, 79, 98, 182], "press": [76, 77, 78, 79], "fifteen": [76, 77, 78, 79], "msequenc": [76, 77, 78, 79], "psychopi": [76, 77, 78, 79], "disc": [76, 77, 78, 79], "pixel": [76, 77, 78, 79], "border": [76, 77, 78, 79, 91], "lcd": [76, 77, 78, 79, 86, 92], "dell": [76, 77, 78, 79], "p2419hc": [76, 77, 78, 79], "1080": [76, 77, 78, 79], "265": [76, 77, 78, 79, 187], "m2": [76, 77, 78, 79], "refresh": [76, 77, 78, 79, 92], "amplitud": [76, 77, 78, 79, 132, 133], "tired": [76, 77, 78, 79], "intrus": [76, 77, 78, 79], "mous": [76, 77, 78, 79], "kalou": [76, 77, 78, 79], "cabrera": [76, 77, 78, 79], "8255618": [76, 77, 78, 79], "simon": [76, 77, 78, 79], "ladouc": [76, 77, 78, 79], "fr\u00e9d\u00e9ric": [76, 77, 78, 79], "dehai": [76, 77, 78, 79], "284": [76, 77, 78, 79, 187], "120446": [76, 77, 78, 79], "issn": [76, 77, 78, 79], "1053": [76, 77, 78, 79], "8119": [27, 76, 77, 78, 79], "1016": [76, 77, 78, 79, 84], "3525nt": 78, "3495t": 78, "passiv": [80, 81, 86, 101, 103], "music": 80, "listen": 80, "publicli": [80, 81], "2617084": 80, "mathwork": [80, 81], "natick": [80, 81], "usa": [80, 81], "doe": [80, 81, 126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 173], "electron": [80, 81], "smartphon": [80, 81], "headset": [80, 81, 83, 94], "pilot": 80, "phmdml": 80, "02085118": 80, "headmounteddisplai": 80, "coelho": 80, "ihmtek": [80, 81], "mar": 80, "realiti": [81, 83], "2605204": 81, "vr": [81, 83], "02078533": 81, "plot_vr_pc_p300_different_epoch_s": 81, "virtualr": [81, 187], "block_list": [81, 123], "repetition_list": [81, 123], "session_id": [81, 107, 123], "run_id": [81, 107, 123], "cho": [82, 187], "sd": 82, "s1": [82, 85, 96], "s2": 82, "s52": 82, "s20": 82, "s33": 82, "collect": [82, 89, 90, 91, 98, 99, 100, 103], "biosemi": [82, 102, 103], "activetwo": [82, 102, 103], "bci2000": [82, 97, 98], "furthermor": [82, 92], "emg": [82, 89, 90, 91], "simultan": [82, 92, 93, 94], "attach": [82, 88], "flexor": [82, 89, 90, 91], "digitorum": [82, 89, 90, 91], "profundu": [82, 89, 90, 91], "extensor": 82, "arm": [82, 84, 96], "calcul": [82, 89, 153], "gave": 82, "maximum": [82, 86, 89, 102, 103, 151, 152], "demand": 82, "ahn": 82, "kwon": [82, 89, 90, 91], "jun": 82, "gigasci": [82, 89, 90, 91], "1093": [82, 89, 90, 91], "gix034": 82, "raccoon": 83, "demon": [83, 187], "935": 83, "major": [83, 187], "unresolv": 83, "risk": 83, "216": 83, "rvd": 83, "incorpor": [83, 89], "stage": 83, "mult_target": 83, "male": [83, 84, 88], "prerequisit": 83, "health": 83, "nvx": 83, "encephalograph": 83, "mc": 83, "zelenograd": 83, "russia": 83, "spong": 83, "poz": [83, 103], "htc": 83, "vive": 83, "pro": 83, "ttl": 83, "sync": [83, 102], "player": 83, "pose": 83, "warden": 83, "suppos": 83, "feed": 83, "anim": 83, "protect": 83, "concentr": 83, "daemon": 83, "firebal": 83, "grigoryan": 83, "samokhina": 83, "ab": [83, 88, 92], "2005": 83, "02251": 83, "intellig": [83, 87], "theori": 83, "applic": [83, 102, 161], "book": 83, "13th": [83, 94], "moscow": 83, "russian": 83, "academi": [83, 182], "isbn": 83, "907366": 83, "www": [83, 97, 99, 100], "machinelearn": 83, "ru": 83, "idp20": 83, "pdf": [83, 92, 93, 94], "\u0442\u0440\u0443\u0434\u044b": 83, "\u0439": 83, "\u0432\u0441\u0435\u0440\u043e\u0441\u0441\u0438\u0439\u0441\u043a\u043e\u0439": 83, "\u043d\u0430\u0443\u0447\u043d\u043e\u0439": 83, "\u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438": 83, "\u043c\u0444\u0442\u0438": 83, "\u043d\u043e\u044f\u0431\u0440\u044f": 83, "\u0433\u043e\u0434\u0430": 83, "\u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u044b\u0435": 83, "\u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0430": 83, "\u0438": 83, "\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u043a\u0430": 83, "\u043c\u043e\u0441\u043a\u0432\u0430": 83, "\u0441": 83, "7417": 83, "0757": 83, "mipt": 83, "5top100": 83, "educ": 83, "coursepropos": 83, "d0": 83, "a4": 83, "9f": 83, "9c": 83, "d1": 83, "b8": 83, "bd": 83, "b0": 83, "bb": 83, "compressed2": 83, "classmethod": [83, 108], "read_hdf": 83, "hdf": 83, "_act_dtyp": 83, "hoffmann": 84, "popul": 84, "face": [84, 89], "laptop": 84, "televis": 84, "telephon": 84, "lamp": 84, "door": 84, "radio": 84, "interstimulu": [84, 87], "2048": [84, 102], "wheelchair": [84, 88], "bound": 84, "limb": [84, 88, 96, 105], "muscl": [84, 89, 90, 91, 105], "abil": 84, "extrem": 84, "slow": 84, "uncontrol": 84, "hypophoni": 84, "fluctuat": 84, "alert": 84, "difficult": 84, "student": 84, "recruit": [84, 96], "laboratori": [84, 155, 158, 160, 168, 170], "810": 84, "3240": 84, "vesin": 84, "ebrahimi": 84, "diseren": 84, "effici": 84, "interfacefor": 84, "jneumeth": 84, "005": 84, "munich": [85, 89, 90, 91], "gross": 85, "wentrup": 85, "superimpos": 85, "haptic": [85, 99], "direct": [85, 91, 98, 106], "explicitli": [25, 26, 28, 29, 30, 85], "feel": [85, 99], "imaginari": 85, "finger": [85, 98], "grip": [85, 99], "unspecifi": 85, "pseudorandom": 85, "s10": 85, "Of": 85, "deviat": [85, 96, 183], "s3": 85, "twice": [85, 87], "brainamp": [85, 86, 89, 90, 91, 99, 100, 101], "analog": 85, "constant": 85, "k\u03c9": [85, 86, 104], "reject": [85, 88], "artifact": [85, 93, 94, 99, 100], "zebri": 85, "ultrasound": 85, "moritz": 85, "beamform": 85, "noninvas": 85, "1209": 85, "1219": 85, "munichmi": 85, "raw_slice_offset": [86, 87], "use_blocks_as_sess": [86, 87], "h\u00fcbner": [86, 87, 101], "sentenc": [86, 87, 89], "franzi": [86, 87], "jagt": [86, 87], "komplett": 86, "verwahrlosten": 86, "taxi": [86, 87], "quer": [86, 87], "durch": [86, 87], "freiburg": [86, 98], "german": 86, "frame": 86, "12852": 86, "perfect": 86, "llp": [86, 87], "reconstruct": 86, "chair": [86, 88], "inch": [86, 99, 100], "easycap": [86, 99, 100, 101], "equidistantli": 86, "whose": 86, "kept": [86, 104, 116], "nose": [86, 101], "regist": 86, "multichannel": [86, 99, 100], "dc": [86, 101], "product": [86, 89, 90, 91, 99, 100], "ocular": 86, "puls": 86, "breath": [86, 99, 100], "array_lik": [86, 87], "millisecond": [86, 87], "li": [86, 87], "crop": [86, 87, 187], "targeet": [86, 87], "verhoeven": [86, 87], "schmid": 86, "kinderman": [86, 87], "e0175856": 86, "0175856": 86, "mixtur": 87, "em": 87, "da": 87, "mix": 87, "guess": 87, "systemat": [87, 187], "bias": 87, "fatigu": [87, 104], "huebner": 87, "magazin": 87, "mci": 87, "2807039": 87, "exo": 88, "versail": 88, "attest": 88, "her": 88, "electr": 88, "upper": [88, 96], "exoskeleton": 88, "panel": 88, "20x30": 88, "side": [88, 96, 97, 99], "led": 88, "auditori": [88, 101, 187], "audio": 88, "equal": [88, 89, 93, 94, 127, 128], "13hz": 88, "17hz": 88, "21hz": 88, "neurocomput": 88, "1501": 88, "03227": 88, "ssvepexo": [88, 187], "train_run": [89, 90, 91], "test_run": [89, 90, 91], "resting_st": [89, 90, 91], "bmi": [89, 90, 91], "openbmi": [89, 90, 91], "germani": [89, 90, 91, 99, 100], "nasion": [89, 90, 91], "olecranon": [89, 90, 91], "entir": [89, 90, 91], "layout": [35, 89, 92, 101], "z": [89, 106, 151], "stronger": 89, "adjac": [89, 99, 100], "distract": [89, 92], "familiar": [89, 177], "iter": 89, "allot": 89, "prolong": 89, "AND": 89, "recognit": [89, 152], "bewar": [89, 90, 91], "kim": [89, 90, 91, 99, 100], "williamson": [89, 90, 91], "w": [89, 90, 91, 99, 100, 102, 103], "illiteraci": [89, 90, 91], "giz002": [89, 90, 91], "establish": [90, 183], "protocol": [90, 92, 93, 94], "grasp": 90, "flicker": [91, 92, 93, 94, 104], "partici": 91, "pant": 91, "light": [91, 92, 93, 94, 99, 100], "captur": [92, 93, 94], "egi": [92, 93], "geodes": [92, 93, 153], "hydrocel": [92, 93], "sensor": [92, 93, 98, 103], "hcgsn": [92, 93], "expos": [92, 93, 94, 187], "magenta": [92, 94], "box": [92, 93, 94], "66hz": [92, 93, 94], "5hz": [92, 93, 94], "57hz": [92, 93, 94], "10hz": [92, 93, 94], "12hz": [92, 93, 94], "isol": 92, "frequencies1": 92, "ascend": 92, "moder": [92, 93, 94], "precis": [92, 104], "unlik": [92, 93, 94], "undergo": [92, 93, 94], "elig": 92, "factor": [92, 104, 153], "stuff": [92, 93], "elimin": 92, "faulti": 92, "s003": 92, "crash": 92, "s004": 92, "s008": 92, "tracker": [92, 178], "detun": 92, "s001": 92, "nb": 92, "fact": 92, "1104": 92, "divid": [92, 98, 104, 105, 153, 182], "quotient": 92, "frequendi": 92, "857": [25, 92], "00hz": 92, "prohibit": 92, "mhz": 92, "mind": 92, "effort": 92, "nevertheless": 92, "conclud": 92, "concurr": [92, 104], "adequ": [92, 107], "occipit": 92, "bran": 92, "mimic": 92, "steadi": [92, 93, 94, 95], "physionet": [92, 93, 94, 97], "physiobank": [92, 93, 94, 97], "mssvepdb": [92, 93, 94], "oikonom": 92, "00904": 92, "nikolopoulo": [92, 93, 94], "dataacquisitiondetail": [92, 93, 94], "mamem_eeg_ssvep_dataset_i_256_channels_11_subjects_5_frequencies_": 92, "2068677": 92, "3793738": 92, "violet": 93, "flick": [93, 94], "mark": [93, 94, 97], "yellow": [93, 94], "underw": [93, 94, 102, 103], "frequencies2": 93, "preced": [93, 94], "seri": [93, 94], "5th": [93, 94], "waveform": [93, 94], "t0nnn": 93, "dat": [93, 94], "hea": [93, 94], "win": [93, 94], "auxiliari": [93, 94], "focal": [93, 94], "s007": [93, 94], "tendenc": [93, 94], "interfer": [93, 94], "mamem_eeg_ssvep_dataset_ii_256_channels_11_subjects_5_frequencies_presented_simultaneously_": 93, "3153409": 93, "4911931": 93, "emotiv": 94, "epoc": 94, "wireless": 94, "frequencies3": 94, "12th": 94, "u0nnn": 94, "ii": [94, 99, 100, 159, 168, 170], "half": [94, 96], "32779": 94, "32780": 94, "staff": 94, "mamem_eeg_ssvep_dataset_iii_14_channels_11_subjects_5_frequencies_presented_simultaneously_": 94, "3413851": 94, "nakanishi": [95, 153], "joint": 95, "masaki": 95, "yijun": 95, "yu": 95, "te": 95, "tzyi": 95, "ping": 95, "jung": [95, 153], "detect": [95, 98, 153, 187], "e140703": 95, "ploson": 95, "0140703": 95, "ataset": 96, "ofner": 96, "me": 96, "flexion": 96, "forearm": 96, "supin": 96, "pronat": 96, "neutral": 96, "degre": 96, "rotat": 96, "thumb": 96, "kinesthet": [96, 105], "immedi": [96, 102, 106], "pop": 96, "schwarz": 96, "pereira": 96, "e0182578": 96, "0182578": 96, "pn4": 97, "eegmmidb": 97, "fist": 97, "bottom": [97, 106], "schalk": [97, 98], "mcfarland": 97, "hinterberg": 97, "wolpaw": 97, "2004": [97, 98], "1034": 97, "1043": 97, "goldberg": 97, "amar": 97, "glass": 97, "hausdorff": 97, "ivanov": 97, "mietu": 97, "moodi": 97, "peng": 97, "stanlei": 97, "resourc": [97, 182], "complex": [97, 98, 172], "circul": 97, "2000": 97, "101": [97, 187], "e215": 97, "e220": 97, "gamma": 98, "cortex": 98, "roughli": 98, "963": 98, "approx": 98, "880": 98, "darva": 98, "2010": 98, "clench": 98, "toe": 98, "downward": 98, "tap": 98, "leftward": 98, "rightward": 98, "upward": 98, "proxim": 98, "muscular": 98, "volv": 98, "pace": [98, 99], "ideal": 98, "260": [98, 187], "approv": 98, "ethic": 98, "committe": 98, "imagei": 99, "shin": [99, 100], "nir": [99, 100], "ordinari": [99, 100], "bright": [99, 100], "room": [99, 100], "thirti": [99, 100], "gmbh": [99, 100], "gilch": [99, 100], "electrocardiogram": [99, 100], "ecg": [99, 100], "respir": [99, 100], "piezo": [99, 100], "belt": [99, 100], "stretchi": [99, 100], "fabric": [99, 100], "herrsch": [99, 100], "ammerse": [99, 100], "afp1": [99, 100], "afp2": [99, 100], "aff1h": [99, 100], "aff2h": [99, 100], "aff5h": [99, 100], "aff6h": [99, 100], "fcc3h": [99, 100], "fcc4h": [99, 100], "fcc5h": [99, 100], "fcc6h": [99, 100], "ccp3h": [99, 100], "ccp4h": [99, 100], "ccp5h": [99, 100], "ccp6h": [99, 100], "ppo1h": [99, 100], "ppo2h": [99, 100], "poo1": [99, 100], "poo2": [99, 100], "nirscout": [99, 100], "nirx": [99, 100], "berlin": [99, 100], "detector": [99, 100], "fourteen": [99, 100], "sixteen": [99, 100], "frontal": [99, 100], "twelv": [99, 100], "optod": [99, 100], "mm": [99, 100], "ambient": [99, 100], "suffici": [99, 100], "firm": [99, 100], "opaqu": [99, 100], "outer": [99, 100], "canthu": [99, 100], "einthoven": [99, 100], "triangl": [99, 100, 104], "chest": [99, 100], "sat": [99, 100], "ma": [99, 100], "post": [99, 100, 104, 121], "introduct": [99, 100], "projector": [99, 100], "schemat": [99, 100], "diagram": [99, 100], "motion": [99, 100], "induc": [99, 100], "grab": 99, "vice": 99, "versa": 99, "von": [99, 100], "l\u00fchmann": [99, 100], "blankertz": [99, 100], "jeong": [99, 100], "hwang": [99, 100], "1735": [99, 100], "gnu": [99, 100], "gpl": [99, 100], "arithmet": 100, "minu": [100, 145], "384": 100, "memor": 100, "repeatedli": 100, "use_soas_as_sess": 101, "load_soa_60": 101, "reject_non_iid": 101, "spot": 101, "sinusoid": [101, 151], "pitch": 101, "opportun": 101, "drink": 101, "brainvis": 101, "kohm": 101, "miscellan": 101, "marker": [101, 131, 134, 138], "achiev": [101, 102], "unifr": 101, "154576": 101, "klein": 101, "reconvolut": 102, "encompass": [102, 103], "cell": [102, 103], "lumin": [102, 103], "contrast": [102, 103], "distribut": [102, 103, 177], "bit": [102, 103], "cycl": [102, 103], "126": [102, 103], "span": [102, 103], "throughout": 102, "engag": [102, 103], "free": 102, "tailor": 102, "among": 102, "equival": 102, "blue": 102, "sole": 102, "character": 102, "render": [102, 182], "unsuit": 102, "108": [102, 187], "jason": [102, 103], "farquhar": [102, 103], "peter": [102, 103], "broad": 102, "con": 102, "volut": 102, "radboud": [102, 103], "34973": [102, 103], "1ecz": 102, "1232": 102, "den": 102, "broek": 102, "e0133797": 102, "0133797": 102, "94500": 103, "emploi": 103, "iz": 103, "connect": 103, "exg": 103, "accomplish": 103, "therebi": 103, "pieter": 103, "marsman": 103, "9txv": 103, "z787": 103, "056007": 103, "abecef": 103, "ahmadi": 103, "borhanazad": 103, "tump": 103, "ty": 103, "066038": 103, "ab4057": 103, "squar": 104, "shift": [104, 145], "synamps2": 104, "neuroscan": 104, "inc": 104, "passband": 104, "sixti": 104, "align": [104, 187], "midwai": 104, "vertex": 104, "power": 104, "synchron": 104, "segment": 104, "downsampl": [104, 153], "doubl": 104, "matlab": [104, 153], "s01": 104, "s35": 104, "loc": 104, "freq_phas": 104, "sub_info": 104, "gender": 104, "handed": 104, "experienc": 104, "s08": 104, "s09": 104, "gao": [104, 151, 153], "1752": 104, "tnsre": 104, "2627556": 104, "weibo": [105, 187], "oscillatori": 105, "cognit": 105, "compound": [105, 187], "involv": 105, "circl": 105, "remind": 105, "pai": 105, "intersect": [105, 145], "yi": 105, "0114853": 105, "fulli": 106, "autom": [106, 187], "month": 106, "wu": 106, "lv": 106, "zhang": [106, 152], "guo": 106, "0162657": 106, "unit_factor": [107, 187], "1000000": 107, "minimum": [107, 124, 145, 187], "left_hand_right_foot": 107, "right_hand_left_foot": 107, "word_ass": 107, "camelcas": 107, "process_pipelin": [107, 126, 127, 128, 129], "constitu": 107, "contigu": 107, "_pipelin": 107, "recommend": [107, 178, 179, 180], "make_process_pipelin": [107, 145], "steptyp": 107, "signifi": [108, 115, 116], "__hash__": 108, "dic": 108, "biilliteraci": 113, "virtualreality_il": 114, "replac": [115, 187], "anymor": 115, "pooch": [115, 187], "remot": [115, 116], "favor": 116, "unus": [116, 187], "filelist": [117, 118, 120], "md5": 117, "fs_get_file_list": [117, 118, 120], "file_id": [117, 118, 120], "article_id": 119, "recent": 119, "put": 121, "response_data": 121, "event_list": 122, "n_run": 122, "n_event": 122, "multi_sess": 124, "has_all_ev": 124, "criteria": 124, "error_scor": [126, 127, 128, 129, 187], "additional_column": [126, 127, 128, 129], "randomst": [126, 127, 128, 129], "shuffl": [126, 127, 128, 129], "item": [126, 127, 128, 129], "n_sampl": [126, 127, 128, 129, 153], "is_valid": [126, 127, 128, 129, 131, 136, 140, 145, 146, 149, 150, 187], "constructor": [126, 127, 128, 129], "eval": [126, 127, 128, 129], "kwarg": [128, 132, 133, 135, 136, 137, 139, 140, 141, 142, 143, 147, 148, 155, 156, 157, 158, 159, 160], "cross_valid": 128, "monoton": 128, "decreas": 128, "datas": 128, "strictli": 128, "complic": 129, "baseprocess": [130, 187], "shortcut": 130, "meant": [132, 133], "maxim": [132, 133, 153], "highpass": 132, "lowpass": 132, "stick": [132, 133], "intens": [132, 133], "narrow": [134, 137], "scorer": [135, 136, 139, 140, 141, 144, 146, 149], "param": [137, 150], "f_n": 137, "child": [145, 146, 149], "make_labels_pipelin": [145, 187], "match_al": [145, 187], "channel_merge_strategi": 145, "129": 145, "solv": 145, "127": [145, 187], "duplic": [145, 187], "versionad": 145, "prepare_process": [145, 150], "process_raw": [145, 187], "mainli": 145, "pure": 151, "act": 151, "bin": 151, "yan": 151, "hong": 151, "046002": 151, "2560": 151, "sample_weight": [151, 152, 153, 155, 156, 157, 158, 159, 160], "predict_proba": [151, 152, 153], "probabl": [151, 152, 153], "set_fit_request": [151, 152, 155, 156, 157, 158, 159, 160], "unchang": [151, 152, 153, 155, 156, 157, 158, 159, 160], "enable_metadata_rout": [151, 152, 153, 155, 156, 157, 158, 159, 160], "rout": [151, 152, 153, 155, 156, 157, 158, 159, 160], "alia": [151, 152, 153, 155, 156, 157, 158, 159, 160], "metadata_rout": [151, 152, 153, 155, 156, 157, 158, 159, 160], "retain": [151, 152, 153, 155, 156, 157, 158, 159, 160], "set_score_request": [151, 152, 153, 155, 156, 157, 158, 159, 160], "n_filter": 152, "multiset": 152, "eigen": 152, "maxvar": 152, "formul": 152, "eq": 152, "jin": 152, "cichocki": 152, "1450013": 152, "1142": 152, "s0129065714500130": 152, "is_ensembl": 153, "ensembl": 153, "outlier": 153, "neg": 153, "ill": 153, "logeuclid": 153, "affin": 153, "invari": 153, "noisi": 153, "schaefer": 153, "regul": 153, "fb_coef": 153, "fusion": 153, "n_fband": 153, "classes_": 153, "templates_": 153, "templat": 153, "n_band": 153, "weights_": 153, "tran": 153, "biom": 153, "104": [153, 187], "mnakanishi": 153, "unseen": 153, "euclid": 154, "tikhonov": [154, 187], "lott": 154, "guan": 154, "deal": 154, "validation_split": [155, 156, 157, 158, 159, 160], "history_plot": [155, 156, 157, 158, 159, 160], "armi": [155, 158, 160], "arl": [155, 158, 160], "vlawhern": [155, 158, 160], "eegmodel": [155, 158, 160], "1002": [155, 160], "hbm": [155, 160], "23730": [155, 160], "set_partial_fit_request": [155, 156, 157, 158, 159, 160], "partial_fit": [155, 156, 157, 158, 159, 160], "abbassalami": 156, "3161489": 156, "chenxiachan": 157, "48550": [157, 161, 170], "aace8c": [158, 168], "eth": [159, 168, 170], "zurich": [159, 168, 170], "smc42975": 159, "9283028": 159, "augment": [161, 187], "papadopoulo": 161, "2302": 161, "04508": 161, "conten": 162, "n_freq": 162, "transpos": 162, "covmat": 162, "constrictor": 166, "appield": 166, "4th": 166, "sklean": 166, "stack": 166, "input_lay": [168, 169, 170], "filters_1": 168, "kernel_s": [168, 170], "depth": [168, 170], "dropout": [168, 169, 170], "elu": [168, 169], "integr": [168, 170], "f1": 169, "kernlength": 169, "input_dimens": 170, "tcn": 170, "2006": 170, "00622": 170, "drop_last_window": 171, "kw_arg": [25, 28, 29, 30, 171], "params_list": 172, "input_dim_fn": 172, "get_shape_from_baseconcat": 172, "module_nam": 172, "beforehand": 172, "callabl": 172, "gan": 172, "storag": [173, 187], "debug": 174, "written": 177, "pypi": 177, "built": 177, "docker": 177, "core": 177, "dockerhub": 177, "beginn": 177, "standalon": 177, "everyth": 177, "dev": 177, "env": 177, "bash": [178, 180], "carbon": [178, 182], "emiss": [178, 187], "deeplean": 178, "carbonemiss": [178, 179], "variant": 178, "latest": [178, 179], "nvidia": 178, "driver": 178, "cuda_path": 178, "troubleshoot": [178, 187], "tool": 179, "releas": 179, "enter": 179, "ref": 179, "edit": 179, "itself": [179, 187], "proper": 179, "becom": 179, "explan": [179, 182], "unittest": 179, "login": 180, "essenti": 180, "baristimunha": 180, "renam": [180, 187], "ngc": 180, "catalog": 180, "create_dock": 180, "sh": 180, "rebuilt": 180, "mkdir": 180, "run_dock": 180, "path_to_root_fold": 180, "absolut": 180, "beyond": 180, "pipeline_dict": 181, "kindli": 182, "learn_python": 182, "neuromatch": 182, "emphasi": 182, "thorough": 182, "exhibit": 182, "benefici": 182, "discov": 182, "moreov": 182, "function_nam": 182, "ipython": 182, "menu": 182, "cite": [182, 183], "backward": 187, "incompat": [35, 187], "517": 187, "interpol": 187, "470": 187, "542": 187, "augmenteddataset": 187, "541": 187, "564": 187, "557": 187, "562": 187, "566": 187, "gh": 187, "522": 187, "530": 187, "batchnorm": 187, "544": 187, "brian": 187, "irvin": 187, "548": 187, "547": 187, "546": 187, "castillos2023": 187, "561": 187, "incorrect": 187, "arg": 187, "563": 187, "565": 187, "567": 187, "390": 187, "389": 187, "398": 187, "deploy": 187, "374": 187, "393": 187, "401": 187, "419": 187, "plu": 187, "pr": 187, "408": 187, "391": 187, "385": 187, "restructur": 187, "424": 187, "parent": 187, "baseparadigm": 187, "basefixedintervalwindowsprocess": 187, "367": 187, "bot": 187, "435": 187, "make_processing_pipelin": 187, "447": 187, "digest": 187, "underscor": 187, "448": 187, "depreciated_alia": 187, "decor": 187, "455": [25, 187], "old": 187, "compound_dataset_list": 187, "463": 187, "417": 187, "scheme": 187, "471": 187, "data_origin": 187, "475": 187, "489": 187, "burstvep": 187, "toulous": 187, "531": 187, "sebastien": 187, "velut": [1, 47, 176, 187], "restor": 187, "392": 187, "397": 187, "403": 187, "sslerror": 187, "404": 187, "mnebnci": 187, "412": [43, 46, 187], "414": [43, 45, 187], "421": 187, "396": 187, "423": 187, "utils_pytorch": 187, "braindecodedatasetload": 187, "426": 187, "gabriel": 187, "schwartz": 187, "425": 187, "fakeimageryparadigm": 187, "fakep300paradigm": 187, "fakessvepparadigm": 187, "dataset_list": 187, "construct": 187, "bad": 187, "433": 187, "464": [25, 187], "get_string_rep": 187, "0x__0a": 187, "468": 187, "evual": 187, "grid_search": 187, "487": [36, 38, 187], "joblib": 187, "488": 187, "491": 187, "493": 187, "502": 187, "mistak": 187, "hardcod": 187, "358": 187, "switch": 187, "coverag": 187, "315": [25, 38, 187], "264": 187, "317": 187, "323": 187, "326": [43, 46, 187], "340": 187, "googl": 187, "analyt": 187, "335": 187, "328": 187, "co\u2082": 187, "356": 187, "371": 187, "372": 187, "circular": 187, "363": 187, "332": [30, 38, 187], "330": 187, "329": 187, "324": [38, 187], "290": 187, "298": 187, "simplif": 187, "306": [42, 187], "numi": 187, "demonsp300": 187, "unzip": 187, "318": 187, "337": 187, "344": 187, "redund": 187, "explicit": 187, "lambda": 187, "parametr": 187, "279": 187, "progress": 187, "249": 187, "266": 187, "saniti": 187, "255": 187, "doctstr": 187, "lee2017": 187, "238": 187, "243": [28, 38, 187], "_fetch_dataset": 187, "_fetch_fil": 187, "235": 187, "232": 187, "rewrit": 187, "217": 187, "leakag": 187, "222": 187, "225": 187, "212": 187, "launch": 187, "205": 187, "207": [32, 38, 43, 187], "155": 187, "neiri": 187, "coloredlog": 187, "163": 187, "readm": 187, "164": 187, "167": 187, "170": 187, "deploi": 187, "124": 187, "bj\u00e4reholt": 187, "wfdb": 187, "pyunpack": 187, "188": 187, "ftp": 187, "rework": 187, "badg": 187, "189": 187, "192": 187, "196": 187, "broaden": 187, "177": 187, "base_paradigm": 187, "hdf5": 187, "115": 187, "118": 187, "130": [25, 187], "137": 187, "luca": 187, "cust\u00f3dio": 187, "140": 187, "147": 187, "151": 187, "stim_channel": 187, "epfl": 187, "105": 187, "106": 187, "upperlimb": 187, "110": [25, 187], "events_from_annot": 187, "h5py": 187, "138": 187, "mohammad": 187, "mostafa": 187, "farzan": 187, "148": 187, "travi": 187, "149": 187, "read_montag": 187, "make_standard_montag": 187, "flake": 187, "pep8": 187, "bruna": [1, 47, 176], "junqueira": [1, 47, 176], "lope": [1, 47, 176], "s\u00e9bastien": [1, 47, 176], "salim": [1, 47, 176], "khazem": [1, 47, 176], "largest": [1, 47, 176], "04537061": [1, 47, 176], "381": [6, 10], "979": [7, 10], "339": [7, 10], "058944": 8, "049391": 8, "049339": 8, "049579": 8, "045368": 8, "058112": 8, "049458": 8, "050020": 8, "050490": 8, "045536": 8, "373": [8, 10], "429": [8, 10], "585": [9, 10], "308": 9, "578": 10, "307": 10, "116": 14, "646": [14, 15], "052010": 18, "057023": 18, "102005": 18, "191809": 18, "043582": 18, "230": [19, 20], "513": 20, "545": 25, "_function_transform": [25, 28, 29, 30], "361": 25, "863": 25, "268": 25, "718": 25, "553": 25, "852": 25, "692": 25, "514": 25, "953": 25, "897": 25, "739": 25, "579": 25, "276": 25, "676": 25, "131": 25, "526": 25, "819": [25, 38], "352": [25, 38], "267": 26, "270": 26, "583231": 26, "499898": 26, "569677": 26, "517636": 26, "521548": 26, "619575": 26, "996": 26, "7963": 27, "7777": 27, "3289": 27, "9597": 27, "7741": 27, "2913": 27, "8870": 27, "7706": 27, "2847": 27, "7234": 27, "2986": 27, "9164": 27, "7637": 27, "2815": 27, "9508": 27, "2877": 27, "9827": 27, "8552": 27, "2886": 27, "8892": 27, "8198": 27, "2824": 27, "8186": 27, "7930": 27, "2816": 27, "7252": 27, "7710": 27, "2898": 27, "9143": 27, "6988": 27, "6026": 27, "0801": 27, "6990": 27, "5695": 27, "1433": 27, "6992": 27, "5854": 27, "0006": 27, "6848": 27, "5691": 27, "9168": 27, "6847": 27, "5687": 27, "9807": 27, "5680": 27, "9120": 27, "5803": 27, "0957": 27, "6834": 27, "7498": 27, "7524": 27, "6968": 27, "0901": 27, "6984": 27, "6967": 27, "1030": 27, "7751": 27, "0897": 27, "1032": 27, "8907": 27, "2792": 27, "2419": 27, "2806": 27, "2040": [27, 29], "9284": 27, "2770": 27, "9918": 27, "7643": 27, "2766": 27, "0123": 27, "7699": 27, "8275": 27, "7746": 27, "2780": 27, "3906": 27, "9882": 27, "7055": 27, "5708": 27, "0244": 27, "7052": 27, "5534": 27, "8173": 27, "7051": 27, "6719": 27, "7267": 27, "5526": 27, "7883": 27, "5652": 27, "8663": 27, "7473": 27, "5671": 27, "0788": 27, "5506": 27, "7047": 27, "5509": 27, "7057": 27, "5478": 27, "9530": 27, "7191": 27, "5642": 27, "9635": 27, "7196": 27, "5586": 27, "0339": 27, "5706": 27, "6845": 27, "6805": 27, "7011": 27, "7353": 27, "7266": 27, "6996": 27, "7256": 27, "0915": 27, "7391": 27, "6977": 27, "1010": 27, "6975": 27, "0908": 27, "7241": 27, "7714": 27, "7377": 27, "7001": 27, "7378": 27, "7472": 27, "6552": 27, "7408": 27, "6808": 27, "0963": 27, "9412": 27, "7847": 27, "8727": 27, "7642": 27, "8113": 27, "7199": 27, "7664": 27, "8205": 27, "7703": 27, "7918": 27, "6812": 27, "7616": 27, "9524": 27, "4500": 27, "8850": 27, "7658": 27, "8934": 27, "9415": 27, "7567": 27, "7919": 27, "5083": 27, "8066": 27, "7593": 27, "6027": 27, "7941": 27, "7251": 27, "7494": 27, "8269": 27, "5917": 27, "6804": 27, "0705": 27, "9701": 27, "7582": 27, "7768": 27, "7647": 27, "9376": 27, "7491": 27, "7131": 27, "7483": 27, "9043": 27, "6777": 27, "9724": 27, "0812": 27, "7603": 27, "9542": 27, "0143": 27, "7495": 27, "8730": 27, "8869": 27, "8111": 27, "7505": 27, "7631": 27, "6161": 27, "9824": 27, "8263": 27, "7640": 27, "8853": 27, "7731": 27, "8878": 27, "7244": 27, "6183": 27, "7720": 27, "6973": 27, "7621": 27, "7895": 27, "9862": 27, "4167": 27, "0668": 27, "9458": 27, "6997": 27, "0587": 27, "9007": 27, "6956": 27, "0566": 27, "8895": 27, "0588": 27, "8896": 27, "0523": 27, "4754": 27, "0003": 27, "8909": 27, "6796": 27, "0576": 27, "8969": 27, "0559": 27, "9135": 27, "0518": 27, "0360": 27, "7294": 27, "0609": 27, "9948": 27, "4083": 27, "7211": 27, "0557": 27, "0685": 27, "3083": 27, "7159": 27, "0047": 27, "4250": 27, "7137": 27, "0481": 27, "0780": 27, "0867": 27, "4509": 27, "0808": 27, "7148": 27, "0493": 27, "0492": 27, "7170": 27, "0534": 27, "9803": 27, "0641": 27, "4621": 27, "0309": 27, "0644": 27, "9047": 27, "9089": 27, "6851": 27, "0524": 27, "9684": 27, "0460": 27, "0081": 27, "9537": 27, "0828": 27, "9676": 27, "6793": 27, "0421": 27, "0062": 27, "6775": 27, "8202": 27, "6786": 27, "0581": 27, "9291": 27, "6790": 27, "0485": 27, "8798": 27, "6799": 27, "0450": 27, "9420": 27, "9857": 27, "8255": 27, "9507": 27, "4464": 27, "9066": 27, "7081": 27, "0445": 27, "9766": 27, "7078": 27, "9108": 27, "7076": 27, "0477": 27, "9700": 27, "7073": 27, "0593": 27, "9619": 27, "7067": 27, "7894": 27, "4667": 27, "2001": 27, "7780": 27, "4750": 27, "1877": 27, "4598": 27, "7743": 27, "1879": 27, "1917": 27, "7537": 27, "1921": 27, "7361": 27, "1901": 27, "7248": 27, "7457": 27, "1997": 27, "7283": 27, "1907": 27, "7461": 27, "7176": 27, "7074": 27, "1956": 27, "1899": 27, "1894": 27, "7165": 27, "6920": 27, "1893": 27, "7056": 27, "1980": 27, "6917": 27, "7238": 27, "1885": 27, "7045": 27, "7187": 27, "1874": 27, "6910": 27, "1991": 27, "7005": 27, "7409": 27, "1924": 27, "1967": 27, "7291": 27, "7749": 27, "6947": 27, "7734": 27, "1891": 27, "7534": 27, "1865": 27, "7502": 27, "1868": 27, "7324": 27, "1864": 27, "7374": 27, "7315": 27, "7206": 27, "1861": 27, "9212": 27, "1639": 27, "7525": 27, "8720": 27, "7823": 27, "7507": 27, "8371": 27, "7264": 27, "7602": 27, "8292": 27, "7742": 27, "8260": 27, "7208": 27, "7589": 27, "9150": 27, "2350": 27, "7655": 27, "9059": 27, "7855": 27, "7651": 27, "8017": 27, "7626": 27, "7547": 27, "7903": 27, "7513": 27, "7653": 27, "9001": 27, "2544": 27, "8694": 27, "8166": 27, "6558": 27, "8114": 27, "6476": 27, "7868": 27, "5481": 27, "7339": 27, "6540": 27, "5651": 27, "7282": 27, "6464": 27, "4442": 27, "9124": 27, "2664": 27, "8408": 27, "9500": 27, "7614": 27, "8736": 27, "7983": 27, "7596": 27, "8417": 27, "7571": 27, "8451": 27, "7253": 27, "8927": 27, "4327": 27, "9024": 27, "6672": 27, "9090": 27, "6508": 27, "8309": 27, "9290": 27, "6442": 27, "8563": 27, "8682": 27, "6592": 27, "8604": 27, "7945": 27, "6484": 27, "9233": 27, "0451": 27, "9082": 27, "9327": 27, "4196": 27, "7006": 27, "0472": 27, "9779": 27, "0024": 27, "0564": 27, "0652": 27, "0578": 27, "0139": 27, "9484": 27, "0537": 27, "9618": 27, "0519": 27, "9147": 27, "4519": 27, "9077": 27, "4740": 27, "9491": 27, "8936": 27, "9069": 27, "4766": 27, "9165": 27, "9356": 27, "0479": 27, "0194": 27, "9080": 27, "3482": 27, "7033": 27, "0452": 27, "8844": 27, "3839": 27, "7028": 27, "9085": 27, "7021": 27, "0495": 27, "8773": 27, "0488": 27, "0628": 27, "8976": 27, "0610": 27, "9441": 27, "0582": 27, "9229": 27, "6999": 27, "9699": 27, "6884": 27, "9182": 27, "9294": 27, "9062": 27, "9464": 27, "9093": 27, "8568": 27, "5865": 27, "9119": 27, "9270": 27, "5577": 27, "9131": 27, "4974": 27, "9287": 27, "9078": 27, "4714": 27, "5769": 27, "9123": 27, "6857": 27, "9354": 27, "5962": 27, "6854": 27, "9079": 27, "9492": 27, "6852": 27, "8993": 27, "1947": 27, "7116": 27, "1931": 27, "7059": 27, "2039": 27, "7080": 27, "1961": 27, "1932": 27, "7296": 27, "6906": 27, "2034": 27, "1939": 27, "1934": 27, "7088": 27, "6881": 27, "1927": 27, "7038": 27, "1898": 27, "6860": 27, "1923": 27, "1761": 27, "4870": 27, "7672": 27, "1667": 27, "7538": 27, "1676": 27, "7197": 27, "2031": 27, "7331": 27, "7136": 27, "6942": 27, "1914": 27, "7352": 27, "1916": 27, "7145": 27, "7101": 27, "6939": 27, "1903": 27, "7293": 27, "4038": 27, "1678": 27, "4135": 27, "1643": 27, "7340": 27, "1641": 27, "508102": 27, "508005": 27, "485629": 27, "551979": 27, "489484": 27, "519427": 27, "175": [27, 38], "763": [28, 38], "2121": 29, "1820": 29, "1808": 29, "1797": 29, "1813": 29, "1812": 29, "1984": 29, "1826": 29, "1827": 29, "1975": 29, "1793": 29, "1804": 29, "1805": 29, "1794": 29, "2066": 29, "1823": 29, "1811": 29, "1803": 29, "118917": 29, "049863": 29, "926365": 29, "923720": 29, "669": [29, 38], "354": [29, 38], "257004": 30, "260381": 30, "241112": 30, "241607": 30, "326427": 30, "375433": 31, "263264": 31, "212352": 31, "195292": 31, "174092": 31, "440": [31, 38], "316": 31, "185": [33, 38], "021": [34, 38], "799": 34, "223": [35, 38], "304": 35, "048859": 37, "048093": 37, "174": [37, 38], "695": 38, "581": [38, 44], "798": 38, "303": 38, "0x7fce0463cf40": 42, "0x7fce0463ce80": 42, "0x7fce0463c1c0": 42, "0x7fce0463c190": 42, "0x7fce0463cd00": 42, "0x7fce0463c700": 42, "0x7fce0463cfd0": 42, "0x7fce0463c5e0": 42, "0x7fce0463c370": 42, "0x7fce0463ca90": 42, "0x7fce0463c7f0": 42, "0x7fce0463cf10": 42, "0x7fce0463c9a0": 42, "0x7fce0463c9d0": 42, "0x7fce0463c310": 42, "0x7fce0463cbb0": 42, "0x7fce0463ce20": 42, "0x7fce0463c850": 42, "0x7fce0463c100": 42, "0x7fce0463c970": 42, "0x7fce0463c5b0": 42, "0x7fce0463c280": 42, "0x7fce0463c940": 42, "149245": 42, "139139": 42, "247906": 42, "168360": 42, "024171": 42, "886": [42, 43], "492": [43, 44], "580": 43, "305": 43, "0x7fcdfc9c0fa0": 44, "0x7fcdfc9c0070": 44, "0x7fcdfc9c0130": 44, "0x7fcdf4d4aa30": 44, "0x7fcdfc9c0340": 44, "0x7fcdfc9c09d0": 44, "0x7fcdfc9c0d00": 44, "0x7fcdfc9c0310": 44, "0x7fcdfc9c05b0": 44, "0x7fcdfc9c04c0": 44, "minor": 183, "difficulti": 183, "scenario": 183, "556": 187}, "objects": {"": [[186, 0, 0, "-", "moabb"]], "moabb": [[3, 0, 0, "-", "analysis"], [60, 1, 1, "", "benchmark"], [49, 0, 0, "-", "datasets"], [50, 0, 0, "-", "evaluations"], [130, 1, 1, "", "make_process_pipelines"], [184, 0, 0, "-", "paradigms"], [185, 0, 0, "-", "pipelines"], [173, 1, 1, "", "set_download_dir"], [174, 1, 1, "", "set_log_level"], [175, 1, 1, "", "setup_seed"]], "moabb.analysis.meta_analysis": [[51, 1, 1, "", "collapse_session_scores"], [52, 1, 1, "", "combine_effects"], [53, 1, 1, "", "combine_pvalues"], [54, 1, 1, "", "compute_dataset_statistics"], [55, 1, 1, "", "find_significant_differences"]], "moabb.analysis.plotting": [[56, 1, 1, "", "meta_analysis_plot"], [57, 1, 1, "", "paired_plot"], [58, 1, 1, "", "score_plot"], [59, 1, 1, "", "summary_plot"]], "moabb.datasets": [[61, 2, 1, "", "AlexMI"], [62, 2, 1, "", "BI2012"], [63, 2, 1, "", "BI2013a"], [64, 2, 1, "", "BI2014a"], [65, 2, 1, "", "BI2014b"], [66, 2, 1, "", "BI2015a"], [67, 2, 1, "", "BI2015b"], [68, 2, 1, "", "BNCI2014_001"], [69, 2, 1, "", "BNCI2014_002"], [70, 2, 1, "", "BNCI2014_004"], [71, 2, 1, "", "BNCI2014_008"], [72, 2, 1, "", "BNCI2014_009"], [73, 2, 1, "", "BNCI2015_001"], [74, 2, 1, "", "BNCI2015_003"], [75, 2, 1, "", "BNCI2015_004"], [76, 2, 1, "", "CastillosBurstVEP100"], [77, 2, 1, "", "CastillosBurstVEP40"], [78, 2, 1, "", "CastillosCVEP100"], [79, 2, 1, "", "CastillosCVEP40"], [80, 2, 1, "", "Cattan2019_PHMD"], [81, 2, 1, "", "Cattan2019_VR"], [82, 2, 1, "", "Cho2017"], [83, 2, 1, "", "DemonsP300"], [84, 2, 1, "", "EPFLP300"], [85, 2, 1, "", "GrosseWentrup2009"], [86, 2, 1, "", "Huebner2017"], [87, 2, 1, "", "Huebner2018"], [88, 2, 1, "", "Kalunga2016"], [89, 2, 1, "", "Lee2019_ERP"], [90, 2, 1, "", "Lee2019_MI"], [91, 2, 1, "", "Lee2019_SSVEP"], [92, 2, 1, "", "MAMEM1"], [93, 2, 1, "", "MAMEM2"], [94, 2, 1, "", "MAMEM3"], [95, 2, 1, "", "Nakanishi2015"], [96, 2, 1, "", "Ofner2017"], [97, 2, 1, "", "PhysionetMI"], [98, 2, 1, "", "Schirrmeister2017"], [99, 2, 1, "", "Shin2017A"], [100, 2, 1, "", "Shin2017B"], [101, 2, 1, "", "Sosulski2019"], [102, 2, 1, "", "Thielen2015"], [103, 2, 1, "", "Thielen2021"], [104, 2, 1, "", "Wang2016"], [105, 2, 1, "", "Weibo2014"], [106, 2, 1, "", "Zhou2016"], [49, 0, 0, "-", "compound_dataset"]], "moabb.datasets.AlexMI": [[61, 3, 1, "", "data_path"]], "moabb.datasets.BI2012": [[62, 3, 1, "", "data_path"]], "moabb.datasets.BI2013a": [[63, 3, 1, "", "data_path"]], "moabb.datasets.BI2014a": [[64, 3, 1, "", "data_path"]], "moabb.datasets.BI2014b": [[65, 3, 1, "", "data_path"]], "moabb.datasets.BI2015a": [[66, 3, 1, "", "data_path"]], "moabb.datasets.BI2015b": [[67, 3, 1, "", "data_path"]], "moabb.datasets.Cattan2019_PHMD": [[80, 3, 1, "", "data_path"]], "moabb.datasets.Cattan2019_VR": [[81, 3, 1, "", "data_path"], [81, 3, 1, "", "get_block_repetition"]], "moabb.datasets.Cho2017": [[82, 3, 1, "", "data_path"]], "moabb.datasets.DemonsP300": [[83, 3, 1, "", "data_path"], [83, 3, 1, "", "read_hdf"]], "moabb.datasets.EPFLP300": [[84, 3, 1, "", "data_path"]], "moabb.datasets.GrosseWentrup2009": [[85, 3, 1, "", "data_path"]], "moabb.datasets.Kalunga2016": [[88, 3, 1, "", "data_path"]], "moabb.datasets.Nakanishi2015": [[95, 3, 1, "", "data_path"]], "moabb.datasets.Ofner2017": [[96, 3, 1, "", "data_path"]], "moabb.datasets.PhysionetMI": [[97, 3, 1, "", "data_path"]], "moabb.datasets.Schirrmeister2017": [[98, 3, 1, "", "data_path"]], "moabb.datasets.Sosulski2019": [[101, 3, 1, "", "data_path"]], "moabb.datasets.Thielen2015": [[102, 3, 1, "", "data_path"]], "moabb.datasets.Thielen2021": [[103, 3, 1, "", "data_path"]], "moabb.datasets.Wang2016": [[104, 3, 1, "", "data_path"]], "moabb.datasets.Weibo2014": [[105, 3, 1, "", "data_path"]], "moabb.datasets.Zhou2016": [[106, 3, 1, "", "data_path"]], "moabb.datasets.base": [[107, 2, 1, "", "BaseDataset"], [108, 2, 1, "", "CacheConfig"]], "moabb.datasets.base.BaseDataset": [[107, 3, 1, "", "data_path"], [107, 3, 1, "", "download"], [107, 3, 1, "", "get_data"]], "moabb.datasets.base.CacheConfig": [[108, 4, 1, "", "__hash__"], [108, 3, 1, "", "make"]], "moabb.datasets.compound_dataset": [[109, 2, 1, "", "BI2014a_Il"], [110, 2, 1, "", "BI2014b_Il"], [111, 2, 1, "", "BI2015a_Il"], [112, 2, 1, "", "BI2015b_Il"], [113, 2, 1, "", "BI_Il"], [114, 2, 1, "", "Cattan2019_VR_Il"]], "moabb.datasets.download": [[115, 1, 1, "", "data_dl"], [116, 1, 1, "", "data_path"], [117, 1, 1, "", "fs_get_file_hash"], [118, 1, 1, "", "fs_get_file_id"], [119, 1, 1, "", "fs_get_file_list"], [120, 1, 1, "", "fs_get_file_name"], [121, 1, 1, "", "fs_issue_request"]], "moabb.datasets.fake": [[122, 2, 1, "", "FakeDataset"], [123, 2, 1, "", "FakeVirtualRealityDataset"]], "moabb.datasets.fake.FakeDataset": [[122, 3, 1, "", "data_path"]], "moabb.datasets.fake.FakeVirtualRealityDataset": [[123, 3, 1, "", "get_block_repetition"]], "moabb.datasets.utils": [[124, 1, 1, "", "dataset_search"], [125, 1, 1, "", "find_intersecting_channels"]], "moabb.evaluations": [[126, 2, 1, "", "CrossSessionEvaluation"], [127, 2, 1, "", "CrossSubjectEvaluation"], [128, 2, 1, "", "WithinSessionEvaluation"]], "moabb.evaluations.CrossSessionEvaluation": [[126, 3, 1, "", "evaluate"], [126, 3, 1, "", "is_valid"]], "moabb.evaluations.CrossSubjectEvaluation": [[127, 3, 1, "", "evaluate"], [127, 3, 1, "", "is_valid"]], "moabb.evaluations.WithinSessionEvaluation": [[128, 3, 1, "", "evaluate"], [128, 3, 1, "", "is_valid"]], "moabb.evaluations.base": [[129, 2, 1, "", "BaseEvaluation"]], "moabb.evaluations.base.BaseEvaluation": [[129, 3, 1, "", "evaluate"], [129, 3, 1, "", "is_valid"], [129, 3, 1, "", "process"]], "moabb.paradigms": [[131, 2, 1, "", "BaseFixedIntervalWindowsProcessing"], [132, 2, 1, "", "CVEP"], [133, 2, 1, "", "FilterBankCVEP"], [134, 2, 1, "", "FilterBankFixedIntervalWindowsProcessing"], [135, 2, 1, "", "FilterBankLeftRightImagery"], [136, 2, 1, "", "FilterBankMotorImagery"], [137, 2, 1, "", "FilterBankSSVEP"], [138, 2, 1, "", "FixedIntervalWindowsProcessing"], [139, 2, 1, "", "LeftRightImagery"], [140, 2, 1, "", "MotorImagery"], [141, 2, 1, "", "P300"], [142, 2, 1, "", "SSVEP"], [143, 2, 1, "", "SinglePass"]], "moabb.paradigms.BaseFixedIntervalWindowsProcessing": [[131, 5, 1, "", "datasets"], [131, 3, 1, "", "is_valid"]], "moabb.paradigms.FilterBankLeftRightImagery": [[135, 5, 1, "", "scoring"]], "moabb.paradigms.FilterBankMotorImagery": [[136, 5, 1, "", "datasets"], [136, 3, 1, "", "is_valid"], [136, 5, 1, "", "scoring"]], "moabb.paradigms.LeftRightImagery": [[139, 5, 1, "", "scoring"]], "moabb.paradigms.MotorImagery": [[140, 5, 1, "", "datasets"], [140, 3, 1, "", "is_valid"], [140, 5, 1, "", "scoring"]], "moabb.paradigms.P300": [[141, 5, 1, "", "scoring"]], "moabb.paradigms.base": [[144, 2, 1, "", "BaseParadigm"], [145, 2, 1, "", "BaseProcessing"]], "moabb.paradigms.base.BaseParadigm": [[144, 5, 1, "", "scoring"]], "moabb.paradigms.base.BaseProcessing": [[145, 5, 1, "", "datasets"], [145, 3, 1, "", "get_data"], [145, 3, 1, "", "is_valid"], [145, 3, 1, "", "make_labels_pipeline"], [145, 3, 1, "", "make_process_pipelines"], [145, 3, 1, "", "match_all"], [145, 3, 1, "", "prepare_process"]], "moabb.paradigms.motor_imagery": [[146, 2, 1, "", "BaseMotorImagery"], [147, 2, 1, "", "FilterBank"], [148, 2, 1, "", "SinglePass"]], "moabb.paradigms.motor_imagery.BaseMotorImagery": [[146, 5, 1, "", "datasets"], [146, 3, 1, "", "is_valid"], [146, 5, 1, "", "scoring"]], "moabb.paradigms.p300": [[149, 2, 1, "", "BaseP300"]], "moabb.paradigms.p300.BaseP300": [[149, 5, 1, "", "datasets"], [149, 3, 1, "", "is_valid"], [149, 5, 1, "", "scoring"]], "moabb.paradigms.ssvep": [[150, 2, 1, "", "BaseSSVEP"]], "moabb.paradigms.ssvep.BaseSSVEP": [[150, 5, 1, "", "datasets"], [150, 3, 1, "", "is_valid"], [150, 3, 1, "", "prepare_process"], [150, 5, 1, "", "scoring"], [150, 3, 1, "", "used_events"]], "moabb.pipelines.classification": [[151, 2, 1, "", "SSVEP_CCA"], [152, 2, 1, "", "SSVEP_MsetCCA"], [153, 2, 1, "", "SSVEP_TRCA"]], "moabb.pipelines.classification.SSVEP_CCA": [[151, 3, 1, "", "fit"], [151, 3, 1, "", "predict"], [151, 3, 1, "", "predict_proba"], [151, 3, 1, "", "set_fit_request"], [151, 3, 1, "", "set_score_request"]], "moabb.pipelines.classification.SSVEP_MsetCCA": [[152, 3, 1, "", "fit"], [152, 3, 1, "", "predict"], [152, 3, 1, "", "predict_proba"], [152, 3, 1, "", "set_fit_request"], [152, 3, 1, "", "set_score_request"]], "moabb.pipelines.classification.SSVEP_TRCA": [[153, 4, 1, "", "Reference"], [153, 4, 1, "", "classes_"], [153, 4, 1, "", "fb_coefs"], [153, 3, 1, "", "fit"], [153, 4, 1, "", "n_classes"], [153, 3, 1, "", "predict"], [153, 3, 1, "", "predict_proba"], [153, 3, 1, "", "set_score_request"], [153, 4, 1, "", "templates_"], [153, 4, 1, "", "weights_"]], "moabb.pipelines.csp": [[154, 2, 1, "", "TRCSP"]], "moabb.pipelines.csp.TRCSP": [[154, 3, 1, "", "fit"]], "moabb.pipelines.deep_learning": [[155, 2, 1, "", "KerasDeepConvNet"], [156, 2, 1, "", "KerasEEGITNet"], [157, 2, 1, "", "KerasEEGNeX"], [158, 2, 1, "", "KerasEEGNet_8_2"], [159, 2, 1, "", "KerasEEGTCNet"], [160, 2, 1, "", "KerasShallowConvNet"]], "moabb.pipelines.deep_learning.KerasDeepConvNet": [[155, 3, 1, "", "set_fit_request"], [155, 3, 1, "", "set_partial_fit_request"], [155, 3, 1, "", "set_score_request"]], "moabb.pipelines.deep_learning.KerasEEGITNet": [[156, 3, 1, "", "set_fit_request"], [156, 3, 1, "", "set_partial_fit_request"], [156, 3, 1, "", "set_score_request"]], "moabb.pipelines.deep_learning.KerasEEGNeX": [[157, 3, 1, "", "set_fit_request"], [157, 3, 1, "", "set_partial_fit_request"], [157, 3, 1, "", "set_score_request"]], "moabb.pipelines.deep_learning.KerasEEGNet_8_2": [[158, 3, 1, "", "set_fit_request"], [158, 3, 1, "", "set_partial_fit_request"], [158, 3, 1, "", "set_score_request"]], "moabb.pipelines.deep_learning.KerasEEGTCNet": [[159, 3, 1, "", "set_fit_request"], [159, 3, 1, "", "set_partial_fit_request"], [159, 3, 1, "", "set_score_request"]], "moabb.pipelines.deep_learning.KerasShallowConvNet": [[160, 3, 1, "", "set_fit_request"], [160, 3, 1, "", "set_partial_fit_request"], [160, 3, 1, "", "set_score_request"]], "moabb.pipelines.features": [[161, 2, 1, "", "AugmentedDataset"], [162, 2, 1, "", "ExtendedSSVEPSignal"], [163, 2, 1, "", "FM"], [164, 2, 1, "", "LogVariance"], [165, 2, 1, "", "StandardScaler_Epoch"]], "moabb.pipelines.features.ExtendedSSVEPSignal": [[162, 3, 1, "", "fit"], [162, 3, 1, "", "transform"]], "moabb.pipelines.features.FM": [[163, 3, 1, "", "fit"], [163, 3, 1, "", "transform"]], "moabb.pipelines.features.LogVariance": [[164, 3, 1, "", "fit"], [164, 3, 1, "", "transform"]], "moabb.pipelines.utils": [[166, 1, 1, "", "FilterBank"], [167, 1, 1, "", "create_pipeline_from_config"]], "moabb.pipelines.utils_deep_model": [[168, 1, 1, "", "EEGNet"], [169, 1, 1, "", "EEGNet_TC"], [170, 1, 1, "", "TCN_block"]], "moabb.pipelines.utils_pytorch": [[171, 1, 1, "", "BraindecodeDatasetLoader"], [172, 1, 1, "", "InputShapeSetterEEG"]]}, "objtypes": {"0": "py:module", "1": "py:function", "2": "py:class", "3": "py:method", "4": "py:attribute", "5": "py:property"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"], "2": ["py", "class", "Python class"], "3": ["py", "method", "Python method"], "4": ["py", "attribute", "Python attribute"], "5": ["py", "property", "Python property"]}, "titleterms": {"contribut": 0, "where": 0, "start": [0, 40, 42], "code": 0, "conduct": 0, "github": [0, 39, 179], "commun": 0, "how": [0, 25], "can": 0, "i": [0, 179], "step": 0, "setup": 0, "develop": [0, 179, 187], "environ": [0, 179], "tool": 0, "us": [0, 1, 25, 39, 45, 56, 57, 58, 59, 60, 61, 64, 68, 70, 72, 80, 81, 88, 94, 106, 107, 115, 124, 125, 126, 127, 128, 129, 131, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 148, 165, 173, 174, 175, 176, 180], "gener": [0, 9], "document": [0, 182], "p": [1, 176], "align": [1, 176], "center": [1, 176], "mother": [1, 176], "all": [1, 176, 183], "bci": [1, 176], "benchmark": [1, 3, 12, 25, 26, 27, 28, 29, 46, 60, 176, 183, 186], "disclaim": [1, 176], "welcom": [1, 176], "The": [1, 176, 183], "problem": [1, 176], "solut": [1, 176], "moabb": [1, 9, 12, 21, 22, 25, 26, 27, 28, 39, 47, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 179, 180], "troubleshoot": [], "core": [1, 176], "team": [1, 176], "contributor": [1, 176], "what": [1, 176, 187], "do": [1, 176], "we": [1, 176], "need": [1, 176], "contact": [1, 176], "u": [1, 176], "thank": [], "you": 180, "analysi": [2, 3, 9, 23, 51, 52, 53, 54, 55, 56, 57, 58, 59], "plot": [2, 3, 5, 6, 8, 9, 12, 14, 18, 19, 29, 30, 31, 32, 36, 37, 44, 45, 46, 56, 57, 58, 59], "statist": [2, 3, 9, 181], "api": [3, 187], "refer": [3, 22, 26, 27, 29], "dataset": [3, 7, 8, 12, 22, 24, 25, 31, 32, 35, 37, 39, 41, 42, 44, 45, 48, 49, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 181], "motor": [3, 18, 29, 30, 44, 48, 49, 183, 184], "imageri": [3, 18, 29, 30, 44, 48, 49, 183, 184], "erp": [3, 48, 49, 183], "ssvep": [3, 32, 37, 48, 49, 142, 150, 183, 184], "c": [3, 48, 49, 184], "vep": [3, 48, 49, 184], "rest": [3, 48, 49], "state": [3, 33, 48, 49], "base": [3, 7, 49, 50, 107, 108, 129, 144, 145, 183, 184, 185], "util": [3, 49, 50, 124, 125, 166, 167, 184, 185, 186], "compound": [3, 48, 49], "evalu": [3, 5, 6, 8, 9, 14, 16, 17, 18, 19, 29, 30, 31, 32, 36, 37, 41, 42, 44, 50, 126, 127, 128, 129, 181], "paradigm": [3, 8, 31, 32, 34, 37, 42, 44, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 181, 184], "p300": [3, 14, 19, 24, 36, 48, 141, 149, 183, 184], "fix": [3, 35, 184], "interv": [3, 35, 184], "window": [3, 35, 184], "process": [3, 33, 35, 184], "pipelin": [3, 5, 6, 7, 9, 12, 14, 18, 19, 25, 29, 30, 31, 32, 36, 37, 42, 44, 46, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 181, 185], "advanc": [4, 7, 16], "exampl": [4, 13, 16, 25, 56, 57, 58, 59, 60, 61, 64, 68, 70, 72, 80, 81, 88, 94, 106, 107, 115, 124, 125, 126, 127, 128, 129, 131, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 148, 165, 173, 174, 175], "filterbank": [5, 34, 147, 166], "csp": [5, 154], "versu": 5, "creat": [5, 6, 9, 14, 18, 19, 29, 30, 31, 32, 36, 37, 39, 41, 42, 44, 46], "result": [5, 6, 7, 8, 9, 12, 14, 18, 19, 29, 30, 31, 32, 36, 37, 44, 45, 46], "gridsearch": 6, "within": [6, 14, 18, 19, 36, 37], "session": [6, 14, 18, 19, 29, 30, 31, 36, 37], "run": [6, 12, 25, 26, 27, 28, 29], "load": [6, 7, 12, 21, 25, 31, 32, 37], "best": 6, "model": [6, 21, 29], "paramet": 6, "mne": 7, "epoch": [7, 24], "get": [7, 31, 37, 40, 42], "data": [7, 23, 24, 31, 33, 37, 39, 48], "option": [7, 12, 25, 31, 37], "A": 7, "simpl": [7, 44], "numpi": 7, "combin": 7, "select": [8, 12, 25, 41], "electrod": 8, "resampl": 8, "test": [9, 179], "further": 9, "comput": [10, 15, 20, 38, 43], "time": [10, 15, 20, 33, 38, 43], "chang": [11, 24, 187], "download": [11, 115, 116, 117, 118, 119, 120, 121], "directori": 11, "show": 12, "co2": 12, "footprint": 12, "extern": [13, 16], "learn": [14, 16, 17, 18, 19, 29], "curv": [14, 16, 17, 18, 19], "scikit": 21, "pytorch": [21, 27], "kera": 21, "convert": 22, "bid": 22, "basic": [22, 33], "usag": [22, 33], "befor": 22, "after": 22, "folder": 22, "structur": 22, "cleanup": [22, 33], "spectral": 23, "trial": 23, "initi": [23, 24, 41, 45], "estim": 23, "power": 23, "densiti": 23, "displai": [23, 24, 41], "size": 24, "vr": 24, "valid": 24, "tensorflow": 26, "deep": [26, 27, 29], "net": [26, 27], "architectur": [26, 27, 181], "braindecod": 27, "grid": 28, "search": 28, "cross": [29, 30, 31, 32], "eegnet": [29, 168], "v4": 29, "multipl": [31, 45, 46], "choos": [31, 32, 37, 44], "subject": [32, 41], "cach": 33, "disk": 33, "intermedi": 33, "comparison": 33, "technic": 33, "detail": 33, "explor": 34, "object": 34, "motorimageri": [34, 140], "leftright": 34, "print": 35, "event": 35, "tutori": [39, 41, 42, 44, 45, 46], "4": [39, 187], "class": [39, 41, 183], "some": 39, "exampledataset": 39, "push": 39, "5": [41, 187], "creation": 41, "merg": 41, "0": [42, 187], "introduct": 42, "1": [44, 187], "instanti": 44, "access": 44, "eeg": [44, 183], "record": 44, "2": [45, 187], "3": [46, 187], "cite": [1, 47, 176], "relat": [1, 47, 176], "public": [1, 47, 176], "summari": [48, 61, 63, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106], "submit": 48, "new": [48, 187], "meta_analysi": [51, 52, 53, 54, 55], "collapse_session_scor": 51, "combine_effect": 52, "combine_pvalu": 53, "compute_dataset_statist": 54, "find_significant_differ": 55, "meta_analysis_plot": 56, "paired_plot": 57, "score_plot": 58, "summary_plot": 59, "alexmi": 61, "bi2012": 62, "bi2013a": 63, "bi2014a": 64, "bi2014b": 65, "bi2015a": 66, "bi2015b": 67, "bnci2014_001": 68, "bnci2014_002": 69, "bnci2014_004": 70, "bnci2014_008": 71, "bnci2014_009": 72, "bnci2015_001": 73, "bnci2015_003": 74, "bnci2015_004": 75, "castillosburstvep100": 76, "castillosburstvep40": 77, "castilloscvep100": 78, "castilloscvep40": 79, "cattan2019_phmd": 80, "cattan2019_vr": 81, "cho2017": 82, "demonsp300": 83, "epflp300": 84, "grossewentrup2009": 85, "huebner2017": 86, "huebner2018": 87, "kalunga2016": 88, "lee2019_erp": 89, "lee2019_mi": 90, "lee2019_ssvep": 91, "mamem1": 92, "mamem2": 93, "mamem3": 94, "nakanishi2015": 95, "ofner2017": 96, "physionetmi": 97, "schirrmeister2017": 98, "shin2017a": 99, "shin2017b": 100, "sosulski2019": 101, "thielen2015": 102, "thielen2021": 103, "wang2016": 104, "weibo2014": 105, "zhou2016": 106, "basedataset": 107, "cacheconfig": 108, "compound_dataset": [109, 110, 111, 112, 113, 114], "bi2014a_il": 109, "bi2014b_il": 110, "bi2015a_il": 111, "bi2015b_il": 112, "bi_il": 113, "cattan2019_vr_il": 114, "data_dl": 115, "data_path": 116, "fs_get_file_hash": 117, "fs_get_file_id": 118, "fs_get_file_list": 119, "fs_get_file_nam": 120, "fs_issue_request": 121, "fake": [122, 123], "fakedataset": 122, "fakevirtualrealitydataset": 123, "dataset_search": 124, "find_intersecting_channel": 125, "crosssessionevalu": 126, "crosssubjectevalu": 127, "withinsessionevalu": 128, "baseevalu": 129, "make_process_pipelin": 130, "basefixedintervalwindowsprocess": 131, "cvep": 132, "filterbankcvep": 133, "filterbankfixedintervalwindowsprocess": 134, "filterbankleftrightimageri": 135, "filterbankmotorimageri": 136, "filterbankssvep": 137, "fixedintervalwindowsprocess": 138, "leftrightimageri": 139, "singlepass": [143, 148], "baseparadigm": 144, "baseprocess": 145, "motor_imageri": [146, 147, 148], "basemotorimageri": 146, "basep300": 149, "basessvep": 150, "classif": [151, 152, 153], "ssvep_cca": 151, "ssvep_msetcca": 152, "ssvep_trca": 153, "trcsp": 154, "deep_learn": [155, 156, 157, 158, 159, 160], "kerasdeepconvnet": 155, "keraseegitnet": 156, "keraseegnex": 157, "keraseegnet_8_2": 158, "keraseegtcnet": 159, "kerasshallowconvnet": 160, "featur": [161, 162, 163, 164, 165], "augmenteddataset": 161, "extendedssvepsign": 162, "fm": 163, "logvari": 164, "standardscaler_epoch": 165, "create_pipeline_from_config": 167, "utils_deep_model": [168, 169, 170], "eegnet_tc": 169, "tcn_block": 170, "utils_pytorch": [171, 172], "braindecodedatasetload": 171, "inputshapesettereeg": 172, "set_download_dir": 173, "set_log_level": 174, "setup_se": 175, "instal": [177, 178, 179], "from": [178, 179], "pypi": [178, 187], "sourc": 179, "clone": 179, "repositori": 179, "build": [179, 180], "your": 179, "work": 179, "docker": 180, "If": 180, "want": 180, "imag": 180, "pre": 180, "main": 181, "concept": 181, "visual": 181, "overview": 182, "": 187, "branch": 187, "enhanc": 187, "bug": 187, "version": 187, "stabl": 187, "6": 187, "largest": 183, "open": 183, "scienc": 183, "left": 183, "v": 183, "right": 183, "hand": 183, "feet": 183}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.todo": 2, "sphinx.ext.intersphinx": 1, "sphinx": 57}, "alltitles": {"Contributing": [[0, "contributing"]], "Where to start": [[0, "where-to-start"]], "Code of Conduct": [[0, "id1"]], "Contributing on Github": [[0, "contributing-on-github"]], "Community": [[0, "community"]], "How can I contribute?": [[0, "how-can-i-contribute"]], "Steps to Contribute": [[0, "steps-to-contribute"]], "Setup development environment": [[0, "id4"]], "Tools used": [[0, "tools-used"]], "Generate the documentation": [[0, "generate-the-documentation"]], "

Mother of all BCI Benchmarks

": [[1, "p-align-center-mother-of-all-bci-benchmarks-p"], [176, "p-align-center-mother-of-all-bci-benchmarks-p"]], "Disclaimer": [[1, "disclaimer"], [176, "disclaimer"]], "Welcome!": [[1, "welcome"], [176, "welcome"]], "The problem": [[1, "the-problem"], [176, "the-problem"]], "The solution": [[1, "the-solution"], [176, "the-solution"]], "Use MOABB": [[1, "use-moabb"], [176, "use-moabb"]], "Core Team": [[1, "core-team"], [176, "core-team"]], "Contributors": [[1, "contributors"], [176, "contributors"]], "What do we need?": [[1, "what-do-we-need"], [176, "what-do-we-need"]], "Citing MOABB and related publications": [[1, "citing-moabb-and-related-publications"], [47, "citing-moabb-and-related-publications"], [176, "citing-moabb-and-related-publications"], [176, "id1"]], "Contact us": [[1, "contact-us"], [176, "contact-us"]], "Analysis": [[2, "module-moabb.analysis"], [3, "module-moabb.analysis"]], "Plotting": [[2, "plotting"], [3, "plotting"]], "Statistics": [[2, "statistics"], [3, "statistics"]], "API Reference": [[3, "api-reference"]], "Datasets": [[3, "module-moabb.datasets"], [8, "datasets"], [42, "datasets"], [49, "module-moabb.datasets"], [181, "datasets"]], "Motor Imagery Datasets": [[3, "motor-imagery-datasets"], [49, "motor-imagery-datasets"]], "ERP Datasets": [[3, "erp-datasets"], [3, "id3"], [49, "erp-datasets"], [49, "id3"]], "SSVEP Datasets": [[3, "ssvep-datasets"], [49, "ssvep-datasets"]], "c-VEP Datasets": [[3, "c-vep-datasets"], [49, "c-vep-datasets"]], "Resting State Datasets": [[3, "resting-state-datasets"], [49, "resting-state-datasets"]], "Base & Utils": [[3, "base-utils"], [3, "id5"], [3, "id6"], [3, "id15"], [49, "base-utils"], [50, "base-utils"], [184, "base-utils"], [185, "base-utils"]], "Compound Datasets": [[3, "module-moabb.datasets.compound_dataset"], [48, "module-moabb.datasets.compound_dataset"], [49, "module-moabb.datasets.compound_dataset"]], "Evaluations": [[3, "module-moabb.evaluations"], [3, "id4"], [50, "module-moabb.evaluations"], [50, "id1"], [181, "evaluations"]], "Paradigms": [[3, "module-moabb.paradigms"], [184, "module-moabb.paradigms"]], "Motor Imagery Paradigms": [[3, "motor-imagery-paradigms"], [184, "motor-imagery-paradigms"]], "P300 Paradigms": [[3, "p300-paradigms"], [184, "p300-paradigms"]], "SSVEP Paradigms": [[3, "ssvep-paradigms"], [184, "ssvep-paradigms"]], "c-VEP Paradigms": [[3, "c-vep-paradigms"], [184, "c-vep-paradigms"]], "Fixed Interval Windows Processings": [[3, "fixed-interval-windows-processings"], [184, "fixed-interval-windows-processings"]], "Pipelines": [[3, "module-moabb.pipelines"], [3, "id7"], [181, "pipelines"], [185, "module-moabb.pipelines"], [185, "id1"]], "Utils": [[3, "module-moabb"], [3, "id18"], [186, "module-moabb"], [186, "id1"]], "Benchmark": [[3, "benchmark"], [186, "benchmark"]], "Advanced examples": [[4, "advanced-examples"], [16, "advanced-examples"]], "FilterBank CSP versus CSP": [[5, "filterbank-csp-versus-csp"]], "Create Pipelines": [[5, "create-pipelines"], [9, "create-pipelines"], [18, "create-pipelines"], [19, "create-pipelines"], [29, "create-pipelines"], [30, "create-pipelines"], [31, "create-pipelines"], [32, "create-pipelines"], [36, "create-pipelines"], [37, "create-pipelines"]], "Evaluation": [[5, "evaluation"], [8, "evaluation"], [9, "evaluation"], [14, "evaluation"], [18, "evaluation"], [19, "evaluation"], [29, "evaluation"], [30, "evaluation"], [31, "evaluation"], [32, "evaluation"], [36, "evaluation"], [37, "evaluation"], [42, "evaluation"], [44, "evaluation"]], "Plot Results": [[5, "plot-results"], [6, "plot-results"], [8, "plot-results"], [14, "plot-results"], [18, "plot-results"], [19, "plot-results"], [29, "plot-results"], [30, "plot-results"], [31, "plot-results"], [32, "plot-results"], [36, "plot-results"], [37, "plot-results"]], "GridSearch within a session": [[6, "gridsearch-within-a-session"]], "Create the Pipelines": [[6, "create-the-pipelines"]], "Running the Evaluation": [[6, "running-the-evaluation"]], "Load Best Model Parameter": [[6, "load-best-model-parameter"]], "MNE Epochs-based pipelines": [[7, "mne-epochs-based-pipelines"]], "Loading Dataset": [[7, "loading-dataset"], [31, "loading-dataset"], [32, "loading-dataset"], [37, "loading-dataset"]], "Get Data (optional)": [[7, "get-data-optional"], [31, "get-data-optional"], [37, "get-data-optional"]], "A Simple MNE Pipeline": [[7, "a-simple-mne-pipeline"]], "Advanced MNE Pipeline": [[7, "advanced-mne-pipeline"]], "Numpy-based Pipeline": [[7, "numpy-based-pipeline"]], "Combining Results": [[7, "combining-results"]], "Select Electrodes and Resampling": [[8, "select-electrodes-and-resampling"]], "Paradigm": [[8, "paradigm"], [42, "paradigm"], [181, "paradigm"]], "Electrode Selection": [[8, "electrode-selection"]], "Statistical Analysis": [[9, "statistical-analysis"]], "Results Generation": [[9, "results-generation"]], "MOABB Plotting": [[9, "moabb-plotting"]], "Statistical Testing and Further Plots": [[9, "statistical-testing-and-further-plots"]], "Computation times": [[10, "computation-times"], [15, "computation-times"], [20, "computation-times"], [38, "computation-times"], [43, "computation-times"]], "Change Download Directory": [[11, "change-download-directory"]], "Benchmarking with MOABB showing the CO2 footprint": [[12, "benchmarking-with-moabb-showing-the-co2-footprint"]], "Loading the pipelines": [[12, "loading-the-pipelines"], [25, "loading-the-pipelines"]], "Selecting the datasets (optional)": [[12, "selecting-the-datasets-optional"], [25, "selecting-the-datasets-optional"]], "Running the benchmark": [[12, "running-the-benchmark"], [25, "running-the-benchmark"], [26, "running-the-benchmark"], [27, "running-the-benchmark"], [28, "running-the-benchmark"], [29, "running-the-benchmark"]], "Plotting the results": [[12, "plotting-the-results"]], "External examples": [[13, "external-examples"], [16, "external-examples"]], "Within Session P300 with Learning Curve": [[14, "within-session-p300-with-learning-curve"], [19, "within-session-p300-with-learning-curve"]], "Create pipelines": [[14, "create-pipelines"], [42, "create-pipelines"]], "Examples": [[16, "examples"]], "Evaluation with learning curve": [[16, "evaluation-with-learning-curve"], [17, "evaluation-with-learning-curve"]], "Within Session Motor Imagery with Learning Curve": [[18, "within-session-motor-imagery-with-learning-curve"]], "Load Model (Scikit, Pytorch, Keras) with MOABB": [[21, "load-model-scikit-pytorch-keras-with-moabb"]], "Convert a MOABB dataset to BIDS": [[22, "convert-a-moabb-dataset-to-bids"]], "Basic usage": [[22, "basic-usage"], [33, "basic-usage"]], "Before / after folder structure": [[22, "before-after-folder-structure"]], "Cleanup": [[22, "cleanup"], [33, "cleanup"]], "References": [[22, "references"], [26, "references"], [27, "references"], [29, "references"]], "Spectral analysis of the trials": [[23, "spectral-analysis-of-the-trials"]], "Initialization": [[23, "initialization"], [24, "initialization"], [41, "initialization"]], "Estimate Power Spectral Density": [[23, "estimate-power-spectral-density"]], "Display of the data": [[23, "display-of-the-data"], [24, "display-of-the-data"]], "Changing epoch size in P300 VR dataset": [[24, "changing-epoch-size-in-p300-vr-dataset"]], "Validation": [[24, "validation"]], "Examples of how to use MOABB to benchmark pipelines.": [[25, "examples-of-how-to-use-moabb-to-benchmark-pipelines"]], "Benchmarking with MOABB": [[25, "benchmarking-with-moabb"]], "Benchmarking on MOABB with Tensorflow deep net architectures": [[26, "benchmarking-on-moabb-with-tensorflow-deep-net-architectures"]], "Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures": [[27, "benchmarking-on-moabb-with-braindecode-pytorch-deep-net-architectures"]], "Benchmarking with MOABB with Grid Search": [[28, "benchmarking-with-moabb-with-grid-search"]], "Cross-session motor imagery with deep learning EEGNet v4 model": [[29, "cross-session-motor-imagery-with-deep-learning-eegnet-v4-model"]], "Cross-Session Motor Imagery": [[30, "cross-session-motor-imagery"]], "Cross-Session on Multiple Datasets": [[31, "cross-session-on-multiple-datasets"]], "Choose Paradigm": [[31, "choose-paradigm"], [32, "choose-paradigm"], [37, "choose-paradigm"]], "Cross-Subject SSVEP": [[32, "cross-subject-ssvep"]], "Cache on disk intermediate data processing states": [[33, "cache-on-disk-intermediate-data-processing-states"]], "Time comparison": [[33, "time-comparison"]], "Technical details": [[33, "technical-details"]], "Explore Paradigm Object": [[34, "explore-paradigm-object"]], "MotorImagery": [[34, "motorimagery"]], "FilterBank MotorImagery": [[34, "filterbank-motorimagery"]], "LeftRight MotorImagery": [[34, "leftright-motorimagery"]], "Fixed interval windows processing": [[35, "fixed-interval-windows-processing"]], "Process a dataset": [[35, "process-a-dataset"]], "Print the events": [[35, "print-the-events"]], "Within Session P300": [[36, "within-session-p300"]], "Within Session SSVEP": [[37, "within-session-ssvep"]], "Tutorial 4: Creating a dataset class": [[39, "tutorial-4-creating-a-dataset-class"]], "Creating some Data": [[39, "creating-some-data"]], "Creating a Dataset Class": [[39, "creating-a-dataset-class"]], "Using the ExampleDataset": [[39, "using-the-exampledataset"]], "Pushing on MOABB Github": [[39, "pushing-on-moabb-github"]], "Getting Started": [[40, "getting-started"]], "Tutorial 5: Creating a dataset class": [[41, "tutorial-5-creating-a-dataset-class"]], "Creation a selection of subject": [[41, "creation-a-selection-of-subject"]], "Merging the datasets": [[41, "merging-the-datasets"]], "Evaluate and display": [[41, "evaluate-and-display"]], "Tutorial 0: Getting Started": [[42, "tutorial-0-getting-started"]], "Introduction": [[42, "introduction"]], "Tutorial 1: Simple Motor Imagery": [[44, "tutorial-1-simple-motor-imagery"]], "Instantiating Dataset": [[44, "instantiating-dataset"]], "Accessing EEG Recording": [[44, "accessing-eeg-recording"]], "Choosing a Paradigm": [[44, "choosing-a-paradigm"]], "Create Pipeline": [[44, "create-pipeline"]], "Plotting Results": [[44, "plotting-results"], [45, "plotting-results"], [46, "plotting-results"]], "Tutorial 2: Using multiple datasets": [[45, "tutorial-2-using-multiple-datasets"]], "Initializing Datasets": [[45, "initializing-datasets"]], "Tutorial 3: Benchmarking multiple pipelines": [[46, "tutorial-3-benchmarking-multiple-pipelines"]], "Creating Pipelines": [[46, "creating-pipelines"]], "Data Summary": [[48, "id1"]], "Motor Imagery": [[48, "motor-imagery"], [183, "motor-imagery"]], "P300/ERP": [[48, "p300-erp"]], "SSVEP": [[48, "ssvep"]], "c-VEP": [[48, "c-vep"]], "Resting States": [[48, "resting-states"]], "Submit a new dataset": [[48, "submit-a-new-dataset"]], "moabb.analysis.meta_analysis.collapse_session_scores": [[51, "moabb-analysis-meta-analysis-collapse-session-scores"]], "moabb.analysis.meta_analysis.combine_effects": [[52, "moabb-analysis-meta-analysis-combine-effects"]], "moabb.analysis.meta_analysis.combine_pvalues": [[53, "moabb-analysis-meta-analysis-combine-pvalues"]], "moabb.analysis.meta_analysis.compute_dataset_statistics": [[54, "moabb-analysis-meta-analysis-compute-dataset-statistics"]], "moabb.analysis.meta_analysis.find_significant_differences": [[55, "moabb-analysis-meta-analysis-find-significant-differences"]], "moabb.analysis.plotting.meta_analysis_plot": [[56, "moabb-analysis-plotting-meta-analysis-plot"]], "Examples using moabb.analysis.plotting.meta_analysis_plot": [[56, "examples-using-moabb-analysis-plotting-meta-analysis-plot"]], "moabb.analysis.plotting.paired_plot": [[57, "moabb-analysis-plotting-paired-plot"]], "Examples using moabb.analysis.plotting.paired_plot": [[57, "examples-using-moabb-analysis-plotting-paired-plot"]], "moabb.analysis.plotting.score_plot": [[58, "moabb-analysis-plotting-score-plot"]], "Examples using moabb.analysis.plotting.score_plot": [[58, "examples-using-moabb-analysis-plotting-score-plot"]], "moabb.analysis.plotting.summary_plot": [[59, "moabb-analysis-plotting-summary-plot"]], "Examples using moabb.analysis.plotting.summary_plot": [[59, "examples-using-moabb-analysis-plotting-summary-plot"]], "moabb.benchmark": [[60, "moabb-benchmark"]], "Examples using moabb.benchmark": [[60, "examples-using-moabb-benchmark"]], "moabb.datasets.AlexMI": [[61, "moabb-datasets-alexmi"]], "Dataset summary": [[61, null], [63, null], [68, null], [69, null], [70, null], [71, null], [72, null], [73, null], [74, null], [75, null], [76, null], [77, null], [78, null], [80, null], [82, null], [83, null], [84, null], [85, null], [86, null], [87, null], [88, null], [89, null], [90, null], [91, null], [92, null], [93, null], [94, null], [95, null], [96, null], [97, null], [98, null], [99, null], [100, null], [101, null], [102, null], [103, null], [104, null], [105, null], [106, null]], "Examples using moabb.datasets.AlexMI": [[61, "examples-using-moabb-datasets-alexmi"]], "moabb.datasets.BI2012": [[62, "moabb-datasets-bi2012"]], "moabb.datasets.BI2013a": [[63, "moabb-datasets-bi2013a"]], "moabb.datasets.BI2014a": [[64, "moabb-datasets-bi2014a"]], "Examples using moabb.datasets.BI2014a": [[64, "examples-using-moabb-datasets-bi2014a"]], "moabb.datasets.BI2014b": [[65, "moabb-datasets-bi2014b"]], "moabb.datasets.BI2015a": [[66, "moabb-datasets-bi2015a"]], "moabb.datasets.BI2015b": [[67, "moabb-datasets-bi2015b"]], "moabb.datasets.BNCI2014_001": [[68, "moabb-datasets-bnci2014-001"]], "Examples using moabb.datasets.BNCI2014_001": [[68, "examples-using-moabb-datasets-bnci2014-001"]], "moabb.datasets.BNCI2014_002": [[69, "moabb-datasets-bnci2014-002"]], "moabb.datasets.BNCI2014_004": [[70, "moabb-datasets-bnci2014-004"]], "Examples using moabb.datasets.BNCI2014_004": [[70, "examples-using-moabb-datasets-bnci2014-004"]], "moabb.datasets.BNCI2014_008": [[71, "moabb-datasets-bnci2014-008"]], "moabb.datasets.BNCI2014_009": [[72, "moabb-datasets-bnci2014-009"]], "Examples using moabb.datasets.BNCI2014_009": [[72, "examples-using-moabb-datasets-bnci2014-009"]], "moabb.datasets.BNCI2015_001": [[73, "moabb-datasets-bnci2015-001"]], "moabb.datasets.BNCI2015_003": [[74, "moabb-datasets-bnci2015-003"]], "moabb.datasets.BNCI2015_004": [[75, "moabb-datasets-bnci2015-004"]], "moabb.datasets.CastillosBurstVEP100": [[76, "moabb-datasets-castillosburstvep100"]], "moabb.datasets.CastillosBurstVEP40": [[77, "moabb-datasets-castillosburstvep40"]], "moabb.datasets.CastillosCVEP100": [[78, "moabb-datasets-castilloscvep100"]], "moabb.datasets.CastillosCVEP40": [[79, "moabb-datasets-castilloscvep40"]], "moabb.datasets.Cattan2019_PHMD": [[80, "moabb-datasets-cattan2019-phmd"]], "Examples using moabb.datasets.Cattan2019_PHMD": [[80, "examples-using-moabb-datasets-cattan2019-phmd"]], "moabb.datasets.Cattan2019_VR": [[81, "moabb-datasets-cattan2019-vr"]], "Examples using moabb.datasets.Cattan2019_VR": [[81, "examples-using-moabb-datasets-cattan2019-vr"]], "moabb.datasets.Cho2017": [[82, "moabb-datasets-cho2017"]], "moabb.datasets.DemonsP300": [[83, "moabb-datasets-demonsp300"]], "moabb.datasets.EPFLP300": [[84, "moabb-datasets-epflp300"]], "moabb.datasets.GrosseWentrup2009": [[85, "moabb-datasets-grossewentrup2009"]], "moabb.datasets.Huebner2017": [[86, "moabb-datasets-huebner2017"]], "moabb.datasets.Huebner2018": [[87, "moabb-datasets-huebner2018"]], "moabb.datasets.Kalunga2016": [[88, "moabb-datasets-kalunga2016"]], "Examples using moabb.datasets.Kalunga2016": [[88, "examples-using-moabb-datasets-kalunga2016"]], "moabb.datasets.Lee2019_ERP": [[89, "moabb-datasets-lee2019-erp"]], "moabb.datasets.Lee2019_MI": [[90, "moabb-datasets-lee2019-mi"]], "moabb.datasets.Lee2019_SSVEP": [[91, "moabb-datasets-lee2019-ssvep"]], "moabb.datasets.MAMEM1": [[92, "moabb-datasets-mamem1"]], "moabb.datasets.MAMEM2": [[93, "moabb-datasets-mamem2"]], "moabb.datasets.MAMEM3": [[94, "moabb-datasets-mamem3"]], "Examples using moabb.datasets.MAMEM3": [[94, "examples-using-moabb-datasets-mamem3"]], "moabb.datasets.Nakanishi2015": [[95, "moabb-datasets-nakanishi2015"]], "moabb.datasets.Ofner2017": [[96, "moabb-datasets-ofner2017"]], "moabb.datasets.PhysionetMI": [[97, "moabb-datasets-physionetmi"]], "moabb.datasets.Schirrmeister2017": [[98, "moabb-datasets-schirrmeister2017"]], "moabb.datasets.Shin2017A": [[99, "moabb-datasets-shin2017a"]], "moabb.datasets.Shin2017B": [[100, "moabb-datasets-shin2017b"]], "moabb.datasets.Sosulski2019": [[101, "moabb-datasets-sosulski2019"]], "moabb.datasets.Thielen2015": [[102, "moabb-datasets-thielen2015"]], "moabb.datasets.Thielen2021": [[103, "moabb-datasets-thielen2021"]], "moabb.datasets.Wang2016": [[104, "moabb-datasets-wang2016"]], "moabb.datasets.Weibo2014": [[105, "moabb-datasets-weibo2014"]], "moabb.datasets.Zhou2016": [[106, "moabb-datasets-zhou2016"]], "Examples using moabb.datasets.Zhou2016": [[106, "examples-using-moabb-datasets-zhou2016"]], "moabb.datasets.base.BaseDataset": [[107, "moabb-datasets-base-basedataset"]], "Examples using moabb.datasets.base.BaseDataset": [[107, "examples-using-moabb-datasets-base-basedataset"]], "moabb.datasets.base.CacheConfig": [[108, "moabb-datasets-base-cacheconfig"]], "moabb.datasets.compound_dataset.BI2014a_Il": [[109, "moabb-datasets-compound-dataset-bi2014a-il"]], "moabb.datasets.compound_dataset.BI2014b_Il": [[110, "moabb-datasets-compound-dataset-bi2014b-il"]], "moabb.datasets.compound_dataset.BI2015a_Il": [[111, "moabb-datasets-compound-dataset-bi2015a-il"]], "moabb.datasets.compound_dataset.BI2015b_Il": [[112, "moabb-datasets-compound-dataset-bi2015b-il"]], "moabb.datasets.compound_dataset.BI_Il": [[113, "moabb-datasets-compound-dataset-bi-il"]], "moabb.datasets.compound_dataset.Cattan2019_VR_Il": [[114, "moabb-datasets-compound-dataset-cattan2019-vr-il"]], "moabb.datasets.download.data_dl": [[115, "moabb-datasets-download-data-dl"]], "Examples using moabb.datasets.download.data_dl": [[115, "examples-using-moabb-datasets-download-data-dl"]], "moabb.datasets.download.data_path": [[116, "moabb-datasets-download-data-path"]], "moabb.datasets.download.fs_get_file_hash": [[117, "moabb-datasets-download-fs-get-file-hash"]], "moabb.datasets.download.fs_get_file_id": [[118, "moabb-datasets-download-fs-get-file-id"]], "moabb.datasets.download.fs_get_file_list": [[119, "moabb-datasets-download-fs-get-file-list"]], "moabb.datasets.download.fs_get_file_name": [[120, "moabb-datasets-download-fs-get-file-name"]], "moabb.datasets.download.fs_issue_request": [[121, "moabb-datasets-download-fs-issue-request"]], "moabb.datasets.fake.FakeDataset": [[122, "moabb-datasets-fake-fakedataset"]], "moabb.datasets.fake.FakeVirtualRealityDataset": [[123, "moabb-datasets-fake-fakevirtualrealitydataset"]], "moabb.datasets.utils.dataset_search": [[124, "moabb-datasets-utils-dataset-search"]], "Examples using moabb.datasets.utils.dataset_search": [[124, "examples-using-moabb-datasets-utils-dataset-search"]], "moabb.datasets.utils.find_intersecting_channels": [[125, "moabb-datasets-utils-find-intersecting-channels"]], "Examples using moabb.datasets.utils.find_intersecting_channels": [[125, "examples-using-moabb-datasets-utils-find-intersecting-channels"]], "moabb.evaluations.CrossSessionEvaluation": [[126, "moabb-evaluations-crosssessionevaluation"]], "Examples using moabb.evaluations.CrossSessionEvaluation": [[126, "examples-using-moabb-evaluations-crosssessionevaluation"]], "moabb.evaluations.CrossSubjectEvaluation": [[127, "moabb-evaluations-crosssubjectevaluation"]], "Examples using moabb.evaluations.CrossSubjectEvaluation": [[127, "examples-using-moabb-evaluations-crosssubjectevaluation"]], "moabb.evaluations.WithinSessionEvaluation": [[128, "moabb-evaluations-withinsessionevaluation"]], "Examples using moabb.evaluations.WithinSessionEvaluation": [[128, "examples-using-moabb-evaluations-withinsessionevaluation"]], "moabb.evaluations.base.BaseEvaluation": [[129, "moabb-evaluations-base-baseevaluation"]], "Examples using moabb.evaluations.base.BaseEvaluation": [[129, "examples-using-moabb-evaluations-base-baseevaluation"]], "moabb.make_process_pipelines": [[130, "moabb-make-process-pipelines"]], "moabb.paradigms.BaseFixedIntervalWindowsProcessing": [[131, "moabb-paradigms-basefixedintervalwindowsprocessing"]], "Examples using moabb.paradigms.BaseFixedIntervalWindowsProcessing": [[131, "examples-using-moabb-paradigms-basefixedintervalwindowsprocessing"]], "moabb.paradigms.CVEP": [[132, "moabb-paradigms-cvep"]], "moabb.paradigms.FilterBankCVEP": [[133, "moabb-paradigms-filterbankcvep"]], "moabb.paradigms.FilterBankFixedIntervalWindowsProcessing": [[134, "moabb-paradigms-filterbankfixedintervalwindowsprocessing"]], "Examples using moabb.paradigms.FilterBankFixedIntervalWindowsProcessing": [[134, "examples-using-moabb-paradigms-filterbankfixedintervalwindowsprocessing"]], "moabb.paradigms.FilterBankLeftRightImagery": [[135, "moabb-paradigms-filterbankleftrightimagery"]], "Examples using moabb.paradigms.FilterBankLeftRightImagery": [[135, "examples-using-moabb-paradigms-filterbankleftrightimagery"]], "moabb.paradigms.FilterBankMotorImagery": [[136, "moabb-paradigms-filterbankmotorimagery"]], "Examples using moabb.paradigms.FilterBankMotorImagery": [[136, "examples-using-moabb-paradigms-filterbankmotorimagery"]], "moabb.paradigms.FilterBankSSVEP": [[137, "moabb-paradigms-filterbankssvep"]], "Examples using moabb.paradigms.FilterBankSSVEP": [[137, "examples-using-moabb-paradigms-filterbankssvep"]], "moabb.paradigms.FixedIntervalWindowsProcessing": [[138, "moabb-paradigms-fixedintervalwindowsprocessing"]], "Examples using moabb.paradigms.FixedIntervalWindowsProcessing": [[138, "examples-using-moabb-paradigms-fixedintervalwindowsprocessing"]], "moabb.paradigms.LeftRightImagery": [[139, "moabb-paradigms-leftrightimagery"]], "Examples using moabb.paradigms.LeftRightImagery": [[139, "examples-using-moabb-paradigms-leftrightimagery"]], "moabb.paradigms.MotorImagery": [[140, "moabb-paradigms-motorimagery"]], "Examples using moabb.paradigms.MotorImagery": [[140, "examples-using-moabb-paradigms-motorimagery"]], "moabb.paradigms.P300": [[141, "moabb-paradigms-p300"]], "Examples using moabb.paradigms.P300": [[141, "examples-using-moabb-paradigms-p300"]], "moabb.paradigms.SSVEP": [[142, "moabb-paradigms-ssvep"]], "Examples using moabb.paradigms.SSVEP": [[142, "examples-using-moabb-paradigms-ssvep"]], "moabb.paradigms.SinglePass": [[143, "moabb-paradigms-singlepass"]], "Examples using moabb.paradigms.SinglePass": [[143, "examples-using-moabb-paradigms-singlepass"]], "moabb.paradigms.base.BaseParadigm": [[144, "moabb-paradigms-base-baseparadigm"]], "moabb.paradigms.base.BaseProcessing": [[145, "moabb-paradigms-base-baseprocessing"]], "moabb.paradigms.motor_imagery.BaseMotorImagery": [[146, "moabb-paradigms-motor-imagery-basemotorimagery"]], "moabb.paradigms.motor_imagery.FilterBank": [[147, "moabb-paradigms-motor-imagery-filterbank"]], "moabb.paradigms.motor_imagery.SinglePass": [[148, "moabb-paradigms-motor-imagery-singlepass"]], "Examples using moabb.paradigms.motor_imagery.SinglePass": [[148, "examples-using-moabb-paradigms-motor-imagery-singlepass"]], "moabb.paradigms.p300.BaseP300": [[149, "moabb-paradigms-p300-basep300"]], "moabb.paradigms.ssvep.BaseSSVEP": [[150, "moabb-paradigms-ssvep-basessvep"]], "moabb.pipelines.classification.SSVEP_CCA": [[151, "moabb-pipelines-classification-ssvep-cca"]], "moabb.pipelines.classification.SSVEP_MsetCCA": [[152, "moabb-pipelines-classification-ssvep-msetcca"]], "moabb.pipelines.classification.SSVEP_TRCA": [[153, "moabb-pipelines-classification-ssvep-trca"]], "moabb.pipelines.csp.TRCSP": [[154, "moabb-pipelines-csp-trcsp"]], "moabb.pipelines.deep_learning.KerasDeepConvNet": [[155, "moabb-pipelines-deep-learning-kerasdeepconvnet"]], "moabb.pipelines.deep_learning.KerasEEGITNet": [[156, "moabb-pipelines-deep-learning-keraseegitnet"]], "moabb.pipelines.deep_learning.KerasEEGNeX": [[157, "moabb-pipelines-deep-learning-keraseegnex"]], "moabb.pipelines.deep_learning.KerasEEGNet_8_2": [[158, "moabb-pipelines-deep-learning-keraseegnet-8-2"]], "moabb.pipelines.deep_learning.KerasEEGTCNet": [[159, "moabb-pipelines-deep-learning-keraseegtcnet"]], "moabb.pipelines.deep_learning.KerasShallowConvNet": [[160, "moabb-pipelines-deep-learning-kerasshallowconvnet"]], "moabb.pipelines.features.AugmentedDataset": [[161, "moabb-pipelines-features-augmenteddataset"]], "moabb.pipelines.features.ExtendedSSVEPSignal": [[162, "moabb-pipelines-features-extendedssvepsignal"]], "moabb.pipelines.features.FM": [[163, "moabb-pipelines-features-fm"]], "moabb.pipelines.features.LogVariance": [[164, "moabb-pipelines-features-logvariance"]], "moabb.pipelines.features.StandardScaler_Epoch": [[165, "moabb-pipelines-features-standardscaler-epoch"]], "Examples using moabb.pipelines.features.StandardScaler_Epoch": [[165, "examples-using-moabb-pipelines-features-standardscaler-epoch"]], "moabb.pipelines.utils.FilterBank": [[166, "moabb-pipelines-utils-filterbank"]], "moabb.pipelines.utils.create_pipeline_from_config": [[167, "moabb-pipelines-utils-create-pipeline-from-config"]], "moabb.pipelines.utils_deep_model.EEGNet": [[168, "moabb-pipelines-utils-deep-model-eegnet"]], "moabb.pipelines.utils_deep_model.EEGNet_TC": [[169, "moabb-pipelines-utils-deep-model-eegnet-tc"]], "moabb.pipelines.utils_deep_model.TCN_block": [[170, "moabb-pipelines-utils-deep-model-tcn-block"]], "moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader": [[171, "moabb-pipelines-utils-pytorch-braindecodedatasetloader"]], "moabb.pipelines.utils_pytorch.InputShapeSetterEEG": [[172, "moabb-pipelines-utils-pytorch-inputshapesettereeg"]], "moabb.set_download_dir": [[173, "moabb-set-download-dir"]], "Examples using moabb.set_download_dir": [[173, "examples-using-moabb-set-download-dir"]], "moabb.set_log_level": [[174, "moabb-set-log-level"]], "Examples using moabb.set_log_level": [[174, "examples-using-moabb-set-log-level"]], "moabb.setup_seed": [[175, "moabb-setup-seed"]], "Examples using moabb.setup_seed": [[175, "examples-using-moabb-setup-seed"]], "Installation": [[177, "installation"]], "Installing from PyPI": [[178, "installing-from-pypi"]], "Installing from sources": [[179, "installing-from-sources"]], "Clone the repository from GitHub": [[179, "clone-the-repository-from-github"]], "Installing Moabb from the source": [[179, "installing-moabb-from-the-source"]], "Building MOABB from source with the development environment": [[179, "building-moabb-from-source-with-the-development-environment"]], "Testing if your installation is working": [[179, "testing-if-your-installation-is-working"]], "Moabb and docker": [[180, "moabb-and-docker"]], "If you want to use the docker image pre-build": [[180, "if-you-want-to-use-the-docker-image-pre-build"]], "Architecture and Main Concepts": [[181, "architecture-and-main-concepts"]], "Statistics and visualization": [[181, "statistics-and-visualization"]], "Documentation overview": [[182, "documentation-overview"]], "The largest EEG-based Benchmark for Open Science": [[183, "the-largest-eeg-based-benchmark-for-open-science"]], "Motor Imagery - Left vs Right Hand": [[183, "motor-imagery-left-vs-right-hand"]], "Motor Imagery - Right Hand vs Feet": [[183, "motor-imagery-right-hand-vs-feet"]], "Motor Imagery - All classes": [[183, "motor-imagery-all-classes"]], "SSVEP (All classes)": [[183, "ssvep-all-classes"]], "P300/ERP (All classes)": [[183, "p300-erp-all-classes"]], "What\u2019s new": [[187, "what-s-new"]], "Develop branch": [[187, "develop-branch"]], "Enhancements": [[187, "enhancements"], [187, "id1"], [187, "id6"], [187, "id9"], [187, "id11"], [187, "id13"], [187, "id16"], [187, "id19"], [187, "id22"], [187, "id25"], [187, "id28"], [187, "id31"], [187, "id34"]], "Bugs": [[187, "bugs"], [187, "id4"], [187, "id7"], [187, "id10"], [187, "id12"], [187, "id14"], [187, "id17"], [187, "id20"], [187, "id23"], [187, "id26"], [187, "id29"], [187, "id32"], [187, "id35"]], "API changes": [[187, "api-changes"], [187, "id5"], [187, "id8"], [187, "id15"], [187, "id18"], [187, "id21"], [187, "id24"], [187, "id27"], [187, "id30"], [187, "id33"], [187, "id36"]], "Version - 1.0.0 (Stable - PyPi)": [[187, "version-1-0-0-stable-pypi"]], "Version - 0.5.0": [[187, "version-0-5-0"]], "Version - 0.4.6": [[187, "version-0-4-6"]], "Version - 0.4.5": [[187, "version-0-4-5"]], "Version - 0.4.4": [[187, "version-0-4-4"]], "Version - 0.4.3": [[187, "version-0-4-3"]], "Version - 0.4.2": [[187, "version-0-4-2"]], "Version - 0.4.1": [[187, "version-0-4-1"]], "Version - 0.4.0": [[187, "version-0-4-0"]], "Version 0.3.0": [[187, "version-0-3-0"]], "Version 0.2.1": [[187, "version-0-2-1"]], "Version 0.2.0": [[187, "version-0-2-0"]]}, "indexentries": {"moabb.analysis": [[2, "module-moabb.analysis"], [3, "module-moabb.analysis"]], "module": [[2, "module-moabb.analysis"], [3, "module-moabb"], [3, "module-moabb.analysis"], [3, "module-moabb.datasets"], [3, "module-moabb.datasets.compound_dataset"], [3, "module-moabb.evaluations"], [3, "module-moabb.paradigms"], [3, "module-moabb.pipelines"], [48, "module-moabb.datasets"], [48, "module-moabb.datasets.compound_dataset"], [49, "module-moabb.datasets"], [49, "module-moabb.datasets.compound_dataset"], [50, "module-moabb.evaluations"], [184, "module-moabb.paradigms"], [185, "module-moabb.pipelines"], [186, "module-moabb"]], "moabb": [[3, "module-moabb"], [186, "module-moabb"]], "moabb.datasets": [[3, "module-moabb.datasets"], [48, "module-moabb.datasets"], [49, "module-moabb.datasets"]], "moabb.datasets.compound_dataset": [[3, "module-moabb.datasets.compound_dataset"], [48, "module-moabb.datasets.compound_dataset"], [49, "module-moabb.datasets.compound_dataset"]], "moabb.evaluations": [[3, "module-moabb.evaluations"], [50, "module-moabb.evaluations"]], "moabb.paradigms": [[3, "module-moabb.paradigms"], [184, "module-moabb.paradigms"]], "moabb.pipelines": [[3, "module-moabb.pipelines"], [185, "module-moabb.pipelines"]], "collapse_session_scores() (in module moabb.analysis.meta_analysis)": [[51, "moabb.analysis.meta_analysis.collapse_session_scores"]], "combine_effects() (in module moabb.analysis.meta_analysis)": [[52, "moabb.analysis.meta_analysis.combine_effects"]], "combine_pvalues() (in module moabb.analysis.meta_analysis)": [[53, "moabb.analysis.meta_analysis.combine_pvalues"]], "compute_dataset_statistics() (in module moabb.analysis.meta_analysis)": [[54, "moabb.analysis.meta_analysis.compute_dataset_statistics"]], "find_significant_differences() (in module moabb.analysis.meta_analysis)": [[55, "moabb.analysis.meta_analysis.find_significant_differences"]], "meta_analysis_plot() (in module moabb.analysis.plotting)": [[56, "moabb.analysis.plotting.meta_analysis_plot"]], "paired_plot() (in module moabb.analysis.plotting)": [[57, "moabb.analysis.plotting.paired_plot"]], "score_plot() (in module moabb.analysis.plotting)": [[58, "moabb.analysis.plotting.score_plot"]], "summary_plot() (in module moabb.analysis.plotting)": [[59, "moabb.analysis.plotting.summary_plot"]], "benchmark() (in module moabb)": [[60, "moabb.benchmark"]], "alexmi (class in moabb.datasets)": [[61, "moabb.datasets.AlexMI"]], "data_path() (moabb.datasets.alexmi method)": [[61, "moabb.datasets.AlexMI.data_path"]], "bi2012 (class in moabb.datasets)": [[62, "moabb.datasets.BI2012"]], "data_path() (moabb.datasets.bi2012 method)": [[62, "moabb.datasets.BI2012.data_path"]], "bi2013a (class in moabb.datasets)": [[63, "moabb.datasets.BI2013a"]], "data_path() (moabb.datasets.bi2013a method)": [[63, "moabb.datasets.BI2013a.data_path"]], "bi2014a (class in moabb.datasets)": [[64, "moabb.datasets.BI2014a"]], "data_path() (moabb.datasets.bi2014a method)": [[64, "moabb.datasets.BI2014a.data_path"]], "bi2014b (class in moabb.datasets)": [[65, "moabb.datasets.BI2014b"]], "data_path() (moabb.datasets.bi2014b method)": [[65, "moabb.datasets.BI2014b.data_path"]], "bi2015a (class in moabb.datasets)": [[66, "moabb.datasets.BI2015a"]], "data_path() (moabb.datasets.bi2015a method)": [[66, "moabb.datasets.BI2015a.data_path"]], "bi2015b (class in moabb.datasets)": [[67, "moabb.datasets.BI2015b"]], "data_path() (moabb.datasets.bi2015b method)": [[67, "moabb.datasets.BI2015b.data_path"]], "bnci2014_001 (class in moabb.datasets)": [[68, "moabb.datasets.BNCI2014_001"]], "bnci2014_002 (class in moabb.datasets)": [[69, "moabb.datasets.BNCI2014_002"]], "bnci2014_004 (class in moabb.datasets)": [[70, "moabb.datasets.BNCI2014_004"]], "bnci2014_008 (class in moabb.datasets)": [[71, "moabb.datasets.BNCI2014_008"]], "bnci2014_009 (class in moabb.datasets)": [[72, "moabb.datasets.BNCI2014_009"]], "bnci2015_001 (class in moabb.datasets)": [[73, "moabb.datasets.BNCI2015_001"]], "bnci2015_003 (class in moabb.datasets)": [[74, "moabb.datasets.BNCI2015_003"]], "bnci2015_004 (class in moabb.datasets)": [[75, "moabb.datasets.BNCI2015_004"]], "castillosburstvep100 (class in moabb.datasets)": [[76, "moabb.datasets.CastillosBurstVEP100"]], "castillosburstvep40 (class in moabb.datasets)": [[77, "moabb.datasets.CastillosBurstVEP40"]], "castilloscvep100 (class in moabb.datasets)": [[78, "moabb.datasets.CastillosCVEP100"]], "castilloscvep40 (class in moabb.datasets)": [[79, "moabb.datasets.CastillosCVEP40"]], "cattan2019_phmd (class in moabb.datasets)": [[80, "moabb.datasets.Cattan2019_PHMD"]], "data_path() (moabb.datasets.cattan2019_phmd method)": [[80, "moabb.datasets.Cattan2019_PHMD.data_path"]], "cattan2019_vr (class in moabb.datasets)": [[81, "moabb.datasets.Cattan2019_VR"]], "data_path() (moabb.datasets.cattan2019_vr method)": [[81, "moabb.datasets.Cattan2019_VR.data_path"]], "get_block_repetition() (moabb.datasets.cattan2019_vr method)": [[81, "moabb.datasets.Cattan2019_VR.get_block_repetition"]], "cho2017 (class in moabb.datasets)": [[82, "moabb.datasets.Cho2017"]], "data_path() (moabb.datasets.cho2017 method)": [[82, "moabb.datasets.Cho2017.data_path"]], "demonsp300 (class in moabb.datasets)": [[83, "moabb.datasets.DemonsP300"]], "data_path() (moabb.datasets.demonsp300 method)": [[83, "moabb.datasets.DemonsP300.data_path"]], "read_hdf() (moabb.datasets.demonsp300 class method)": [[83, "moabb.datasets.DemonsP300.read_hdf"]], "epflp300 (class in moabb.datasets)": [[84, "moabb.datasets.EPFLP300"]], "data_path() (moabb.datasets.epflp300 method)": [[84, "moabb.datasets.EPFLP300.data_path"]], "grossewentrup2009 (class in moabb.datasets)": [[85, "moabb.datasets.GrosseWentrup2009"]], "data_path() (moabb.datasets.grossewentrup2009 method)": [[85, "moabb.datasets.GrosseWentrup2009.data_path"]], "huebner2017 (class in moabb.datasets)": [[86, "moabb.datasets.Huebner2017"]], "huebner2018 (class in moabb.datasets)": [[87, "moabb.datasets.Huebner2018"]], "kalunga2016 (class in moabb.datasets)": [[88, "moabb.datasets.Kalunga2016"]], "data_path() (moabb.datasets.kalunga2016 method)": [[88, "moabb.datasets.Kalunga2016.data_path"]], "lee2019_erp (class in moabb.datasets)": [[89, "moabb.datasets.Lee2019_ERP"]], "lee2019_mi (class in moabb.datasets)": [[90, "moabb.datasets.Lee2019_MI"]], "lee2019_ssvep (class in moabb.datasets)": [[91, "moabb.datasets.Lee2019_SSVEP"]], "mamem1 (class in moabb.datasets)": [[92, "moabb.datasets.MAMEM1"]], "mamem2 (class in moabb.datasets)": [[93, "moabb.datasets.MAMEM2"]], "mamem3 (class in moabb.datasets)": [[94, "moabb.datasets.MAMEM3"]], "nakanishi2015 (class in moabb.datasets)": [[95, "moabb.datasets.Nakanishi2015"]], "data_path() (moabb.datasets.nakanishi2015 method)": [[95, "moabb.datasets.Nakanishi2015.data_path"]], "ofner2017 (class in moabb.datasets)": [[96, "moabb.datasets.Ofner2017"]], "data_path() (moabb.datasets.ofner2017 method)": [[96, "moabb.datasets.Ofner2017.data_path"]], "physionetmi (class in moabb.datasets)": [[97, "moabb.datasets.PhysionetMI"]], "data_path() (moabb.datasets.physionetmi method)": [[97, "moabb.datasets.PhysionetMI.data_path"]], "schirrmeister2017 (class in moabb.datasets)": [[98, "moabb.datasets.Schirrmeister2017"]], "data_path() (moabb.datasets.schirrmeister2017 method)": [[98, "moabb.datasets.Schirrmeister2017.data_path"]], "shin2017a (class in moabb.datasets)": [[99, "moabb.datasets.Shin2017A"]], "shin2017b (class in moabb.datasets)": [[100, "moabb.datasets.Shin2017B"]], "sosulski2019 (class in moabb.datasets)": [[101, "moabb.datasets.Sosulski2019"]], "data_path() (moabb.datasets.sosulski2019 method)": [[101, "moabb.datasets.Sosulski2019.data_path"]], "thielen2015 (class in moabb.datasets)": [[102, "moabb.datasets.Thielen2015"]], "data_path() (moabb.datasets.thielen2015 method)": [[102, "moabb.datasets.Thielen2015.data_path"]], "thielen2021 (class in moabb.datasets)": [[103, "moabb.datasets.Thielen2021"]], "data_path() (moabb.datasets.thielen2021 method)": [[103, "moabb.datasets.Thielen2021.data_path"]], "wang2016 (class in moabb.datasets)": [[104, "moabb.datasets.Wang2016"]], "data_path() (moabb.datasets.wang2016 method)": [[104, "moabb.datasets.Wang2016.data_path"]], "weibo2014 (class in moabb.datasets)": [[105, "moabb.datasets.Weibo2014"]], "data_path() (moabb.datasets.weibo2014 method)": [[105, "moabb.datasets.Weibo2014.data_path"]], "zhou2016 (class in moabb.datasets)": [[106, "moabb.datasets.Zhou2016"]], "data_path() (moabb.datasets.zhou2016 method)": [[106, "moabb.datasets.Zhou2016.data_path"]], "basedataset (class in moabb.datasets.base)": [[107, "moabb.datasets.base.BaseDataset"]], "data_path() (moabb.datasets.base.basedataset method)": [[107, "moabb.datasets.base.BaseDataset.data_path"]], "download() (moabb.datasets.base.basedataset method)": [[107, "moabb.datasets.base.BaseDataset.download"]], "get_data() (moabb.datasets.base.basedataset method)": [[107, "moabb.datasets.base.BaseDataset.get_data"]], "cacheconfig (class in moabb.datasets.base)": [[108, "moabb.datasets.base.CacheConfig"]], "__hash__ (moabb.datasets.base.cacheconfig attribute)": [[108, "moabb.datasets.base.CacheConfig.__hash__"]], "make() (moabb.datasets.base.cacheconfig class method)": [[108, "moabb.datasets.base.CacheConfig.make"]], "bi2014a_il (class in moabb.datasets.compound_dataset)": [[109, "moabb.datasets.compound_dataset.BI2014a_Il"]], "bi2014b_il (class in moabb.datasets.compound_dataset)": [[110, "moabb.datasets.compound_dataset.BI2014b_Il"]], "bi2015a_il (class in moabb.datasets.compound_dataset)": [[111, "moabb.datasets.compound_dataset.BI2015a_Il"]], "bi2015b_il (class in moabb.datasets.compound_dataset)": [[112, "moabb.datasets.compound_dataset.BI2015b_Il"]], "bi_il (class in moabb.datasets.compound_dataset)": [[113, "moabb.datasets.compound_dataset.BI_Il"]], "cattan2019_vr_il (class in moabb.datasets.compound_dataset)": [[114, "moabb.datasets.compound_dataset.Cattan2019_VR_Il"]], "data_dl() (in module moabb.datasets.download)": [[115, "moabb.datasets.download.data_dl"]], "data_path() (in module moabb.datasets.download)": [[116, "moabb.datasets.download.data_path"]], "fs_get_file_hash() (in module moabb.datasets.download)": [[117, "moabb.datasets.download.fs_get_file_hash"]], "fs_get_file_id() (in module moabb.datasets.download)": [[118, "moabb.datasets.download.fs_get_file_id"]], "fs_get_file_list() (in module moabb.datasets.download)": [[119, "moabb.datasets.download.fs_get_file_list"]], "fs_get_file_name() (in module moabb.datasets.download)": [[120, "moabb.datasets.download.fs_get_file_name"]], "fs_issue_request() (in module moabb.datasets.download)": [[121, "moabb.datasets.download.fs_issue_request"]], "fakedataset (class in moabb.datasets.fake)": [[122, "moabb.datasets.fake.FakeDataset"]], "data_path() (moabb.datasets.fake.fakedataset method)": [[122, "moabb.datasets.fake.FakeDataset.data_path"]], "fakevirtualrealitydataset (class in moabb.datasets.fake)": [[123, "moabb.datasets.fake.FakeVirtualRealityDataset"]], "get_block_repetition() (moabb.datasets.fake.fakevirtualrealitydataset method)": [[123, "moabb.datasets.fake.FakeVirtualRealityDataset.get_block_repetition"]], "dataset_search() (in module moabb.datasets.utils)": [[124, "moabb.datasets.utils.dataset_search"]], "find_intersecting_channels() (in module moabb.datasets.utils)": [[125, "moabb.datasets.utils.find_intersecting_channels"]], "crosssessionevaluation (class in moabb.evaluations)": [[126, "moabb.evaluations.CrossSessionEvaluation"]], "evaluate() (moabb.evaluations.crosssessionevaluation method)": [[126, "moabb.evaluations.CrossSessionEvaluation.evaluate"]], "is_valid() (moabb.evaluations.crosssessionevaluation method)": [[126, "moabb.evaluations.CrossSessionEvaluation.is_valid"]], "crosssubjectevaluation (class in moabb.evaluations)": [[127, "moabb.evaluations.CrossSubjectEvaluation"]], "evaluate() (moabb.evaluations.crosssubjectevaluation method)": [[127, "moabb.evaluations.CrossSubjectEvaluation.evaluate"]], "is_valid() (moabb.evaluations.crosssubjectevaluation method)": [[127, "moabb.evaluations.CrossSubjectEvaluation.is_valid"]], "withinsessionevaluation (class in moabb.evaluations)": [[128, "moabb.evaluations.WithinSessionEvaluation"]], "evaluate() (moabb.evaluations.withinsessionevaluation method)": [[128, "moabb.evaluations.WithinSessionEvaluation.evaluate"]], "is_valid() (moabb.evaluations.withinsessionevaluation method)": [[128, "moabb.evaluations.WithinSessionEvaluation.is_valid"]], "baseevaluation (class in moabb.evaluations.base)": [[129, "moabb.evaluations.base.BaseEvaluation"]], "evaluate() (moabb.evaluations.base.baseevaluation method)": [[129, "moabb.evaluations.base.BaseEvaluation.evaluate"]], "is_valid() (moabb.evaluations.base.baseevaluation method)": [[129, "moabb.evaluations.base.BaseEvaluation.is_valid"]], "process() (moabb.evaluations.base.baseevaluation method)": [[129, "moabb.evaluations.base.BaseEvaluation.process"]], "make_process_pipelines() (in module moabb)": [[130, "moabb.make_process_pipelines"]], "basefixedintervalwindowsprocessing (class in moabb.paradigms)": [[131, "moabb.paradigms.BaseFixedIntervalWindowsProcessing"]], "datasets (moabb.paradigms.basefixedintervalwindowsprocessing property)": [[131, "moabb.paradigms.BaseFixedIntervalWindowsProcessing.datasets"]], "is_valid() (moabb.paradigms.basefixedintervalwindowsprocessing method)": [[131, "moabb.paradigms.BaseFixedIntervalWindowsProcessing.is_valid"]], "cvep (class in moabb.paradigms)": [[132, "moabb.paradigms.CVEP"]], "filterbankcvep (class in moabb.paradigms)": [[133, "moabb.paradigms.FilterBankCVEP"]], "filterbankfixedintervalwindowsprocessing (class in moabb.paradigms)": [[134, "moabb.paradigms.FilterBankFixedIntervalWindowsProcessing"]], "filterbankleftrightimagery (class in moabb.paradigms)": [[135, "moabb.paradigms.FilterBankLeftRightImagery"]], "scoring (moabb.paradigms.filterbankleftrightimagery property)": [[135, "moabb.paradigms.FilterBankLeftRightImagery.scoring"]], "filterbankmotorimagery (class in moabb.paradigms)": [[136, "moabb.paradigms.FilterBankMotorImagery"]], "datasets (moabb.paradigms.filterbankmotorimagery property)": [[136, "moabb.paradigms.FilterBankMotorImagery.datasets"]], "is_valid() (moabb.paradigms.filterbankmotorimagery method)": [[136, "moabb.paradigms.FilterBankMotorImagery.is_valid"]], "scoring (moabb.paradigms.filterbankmotorimagery property)": [[136, "moabb.paradigms.FilterBankMotorImagery.scoring"]], "filterbankssvep (class in moabb.paradigms)": [[137, "moabb.paradigms.FilterBankSSVEP"]], "fixedintervalwindowsprocessing (class in moabb.paradigms)": [[138, "moabb.paradigms.FixedIntervalWindowsProcessing"]], "leftrightimagery (class in moabb.paradigms)": [[139, "moabb.paradigms.LeftRightImagery"]], "scoring (moabb.paradigms.leftrightimagery property)": [[139, "moabb.paradigms.LeftRightImagery.scoring"]], "motorimagery (class in moabb.paradigms)": [[140, "moabb.paradigms.MotorImagery"]], "datasets (moabb.paradigms.motorimagery property)": [[140, "moabb.paradigms.MotorImagery.datasets"]], "is_valid() (moabb.paradigms.motorimagery method)": [[140, "moabb.paradigms.MotorImagery.is_valid"]], "scoring (moabb.paradigms.motorimagery property)": [[140, "moabb.paradigms.MotorImagery.scoring"]], "p300 (class in moabb.paradigms)": [[141, "moabb.paradigms.P300"]], "scoring (moabb.paradigms.p300 property)": [[141, "moabb.paradigms.P300.scoring"]], "ssvep (class in moabb.paradigms)": [[142, "moabb.paradigms.SSVEP"]], "singlepass (class in moabb.paradigms)": [[143, "moabb.paradigms.SinglePass"]], "baseparadigm (class in moabb.paradigms.base)": [[144, "moabb.paradigms.base.BaseParadigm"]], "scoring (moabb.paradigms.base.baseparadigm property)": [[144, "moabb.paradigms.base.BaseParadigm.scoring"]], "baseprocessing (class in moabb.paradigms.base)": [[145, "moabb.paradigms.base.BaseProcessing"]], "datasets (moabb.paradigms.base.baseprocessing property)": [[145, "moabb.paradigms.base.BaseProcessing.datasets"]], "get_data() (moabb.paradigms.base.baseprocessing method)": [[145, "moabb.paradigms.base.BaseProcessing.get_data"]], "is_valid() (moabb.paradigms.base.baseprocessing method)": [[145, "moabb.paradigms.base.BaseProcessing.is_valid"]], "make_labels_pipeline() (moabb.paradigms.base.baseprocessing method)": [[145, "moabb.paradigms.base.BaseProcessing.make_labels_pipeline"]], "make_process_pipelines() (moabb.paradigms.base.baseprocessing method)": [[145, "moabb.paradigms.base.BaseProcessing.make_process_pipelines"]], "match_all() (moabb.paradigms.base.baseprocessing method)": [[145, "moabb.paradigms.base.BaseProcessing.match_all"]], "prepare_process() (moabb.paradigms.base.baseprocessing method)": [[145, "moabb.paradigms.base.BaseProcessing.prepare_process"]], "basemotorimagery (class in moabb.paradigms.motor_imagery)": [[146, "moabb.paradigms.motor_imagery.BaseMotorImagery"]], "datasets (moabb.paradigms.motor_imagery.basemotorimagery property)": [[146, "moabb.paradigms.motor_imagery.BaseMotorImagery.datasets"]], "is_valid() (moabb.paradigms.motor_imagery.basemotorimagery method)": [[146, "moabb.paradigms.motor_imagery.BaseMotorImagery.is_valid"]], "scoring (moabb.paradigms.motor_imagery.basemotorimagery property)": [[146, "moabb.paradigms.motor_imagery.BaseMotorImagery.scoring"]], "filterbank (class in moabb.paradigms.motor_imagery)": [[147, "moabb.paradigms.motor_imagery.FilterBank"]], "singlepass (class in moabb.paradigms.motor_imagery)": [[148, "moabb.paradigms.motor_imagery.SinglePass"]], "basep300 (class in moabb.paradigms.p300)": [[149, "moabb.paradigms.p300.BaseP300"]], "datasets (moabb.paradigms.p300.basep300 property)": [[149, "moabb.paradigms.p300.BaseP300.datasets"]], "is_valid() (moabb.paradigms.p300.basep300 method)": [[149, "moabb.paradigms.p300.BaseP300.is_valid"]], "scoring (moabb.paradigms.p300.basep300 property)": [[149, "moabb.paradigms.p300.BaseP300.scoring"]], "basessvep (class in moabb.paradigms.ssvep)": [[150, "moabb.paradigms.ssvep.BaseSSVEP"]], "datasets (moabb.paradigms.ssvep.basessvep property)": [[150, "moabb.paradigms.ssvep.BaseSSVEP.datasets"]], "is_valid() (moabb.paradigms.ssvep.basessvep method)": [[150, "moabb.paradigms.ssvep.BaseSSVEP.is_valid"]], "prepare_process() (moabb.paradigms.ssvep.basessvep method)": [[150, "moabb.paradigms.ssvep.BaseSSVEP.prepare_process"]], "scoring (moabb.paradigms.ssvep.basessvep property)": [[150, "moabb.paradigms.ssvep.BaseSSVEP.scoring"]], "used_events() (moabb.paradigms.ssvep.basessvep method)": [[150, "moabb.paradigms.ssvep.BaseSSVEP.used_events"]], "ssvep_cca (class in moabb.pipelines.classification)": [[151, "moabb.pipelines.classification.SSVEP_CCA"]], "fit() (moabb.pipelines.classification.ssvep_cca method)": [[151, "moabb.pipelines.classification.SSVEP_CCA.fit"]], "predict() (moabb.pipelines.classification.ssvep_cca method)": [[151, "moabb.pipelines.classification.SSVEP_CCA.predict"]], "predict_proba() (moabb.pipelines.classification.ssvep_cca method)": [[151, "moabb.pipelines.classification.SSVEP_CCA.predict_proba"]], "set_fit_request() (moabb.pipelines.classification.ssvep_cca method)": [[151, "moabb.pipelines.classification.SSVEP_CCA.set_fit_request"]], "set_score_request() (moabb.pipelines.classification.ssvep_cca method)": [[151, "moabb.pipelines.classification.SSVEP_CCA.set_score_request"]], "ssvep_msetcca (class in moabb.pipelines.classification)": [[152, "moabb.pipelines.classification.SSVEP_MsetCCA"]], "fit() (moabb.pipelines.classification.ssvep_msetcca method)": [[152, "moabb.pipelines.classification.SSVEP_MsetCCA.fit"]], "predict() (moabb.pipelines.classification.ssvep_msetcca method)": [[152, "moabb.pipelines.classification.SSVEP_MsetCCA.predict"]], "predict_proba() (moabb.pipelines.classification.ssvep_msetcca method)": [[152, "moabb.pipelines.classification.SSVEP_MsetCCA.predict_proba"]], "set_fit_request() (moabb.pipelines.classification.ssvep_msetcca method)": [[152, "moabb.pipelines.classification.SSVEP_MsetCCA.set_fit_request"]], "set_score_request() (moabb.pipelines.classification.ssvep_msetcca method)": [[152, "moabb.pipelines.classification.SSVEP_MsetCCA.set_score_request"]], "reference (moabb.pipelines.classification.ssvep_trca attribute)": [[153, "moabb.pipelines.classification.SSVEP_TRCA.Reference"]], "ssvep_trca (class in moabb.pipelines.classification)": [[153, "moabb.pipelines.classification.SSVEP_TRCA"]], "classes_ (moabb.pipelines.classification.ssvep_trca attribute)": [[153, "moabb.pipelines.classification.SSVEP_TRCA.classes_"]], "fb_coefs (moabb.pipelines.classification.ssvep_trca attribute)": [[153, "moabb.pipelines.classification.SSVEP_TRCA.fb_coefs"]], "fit() (moabb.pipelines.classification.ssvep_trca method)": [[153, "moabb.pipelines.classification.SSVEP_TRCA.fit"]], "n_classes (moabb.pipelines.classification.ssvep_trca attribute)": [[153, "moabb.pipelines.classification.SSVEP_TRCA.n_classes"]], "predict() (moabb.pipelines.classification.ssvep_trca method)": [[153, "moabb.pipelines.classification.SSVEP_TRCA.predict"]], "predict_proba() (moabb.pipelines.classification.ssvep_trca method)": [[153, "moabb.pipelines.classification.SSVEP_TRCA.predict_proba"]], "set_score_request() (moabb.pipelines.classification.ssvep_trca method)": [[153, "moabb.pipelines.classification.SSVEP_TRCA.set_score_request"]], "templates_ (moabb.pipelines.classification.ssvep_trca attribute)": [[153, "moabb.pipelines.classification.SSVEP_TRCA.templates_"]], "weights_ (moabb.pipelines.classification.ssvep_trca attribute)": [[153, "moabb.pipelines.classification.SSVEP_TRCA.weights_"]], "trcsp (class in moabb.pipelines.csp)": [[154, "moabb.pipelines.csp.TRCSP"]], "fit() (moabb.pipelines.csp.trcsp method)": [[154, "moabb.pipelines.csp.TRCSP.fit"]], "kerasdeepconvnet (class in moabb.pipelines.deep_learning)": [[155, "moabb.pipelines.deep_learning.KerasDeepConvNet"]], "set_fit_request() (moabb.pipelines.deep_learning.kerasdeepconvnet method)": [[155, "moabb.pipelines.deep_learning.KerasDeepConvNet.set_fit_request"]], "set_partial_fit_request() (moabb.pipelines.deep_learning.kerasdeepconvnet method)": [[155, "moabb.pipelines.deep_learning.KerasDeepConvNet.set_partial_fit_request"]], "set_score_request() (moabb.pipelines.deep_learning.kerasdeepconvnet method)": [[155, "moabb.pipelines.deep_learning.KerasDeepConvNet.set_score_request"]], "keraseegitnet (class in moabb.pipelines.deep_learning)": [[156, "moabb.pipelines.deep_learning.KerasEEGITNet"]], "set_fit_request() (moabb.pipelines.deep_learning.keraseegitnet method)": [[156, "moabb.pipelines.deep_learning.KerasEEGITNet.set_fit_request"]], "set_partial_fit_request() (moabb.pipelines.deep_learning.keraseegitnet method)": [[156, "moabb.pipelines.deep_learning.KerasEEGITNet.set_partial_fit_request"]], "set_score_request() (moabb.pipelines.deep_learning.keraseegitnet method)": [[156, "moabb.pipelines.deep_learning.KerasEEGITNet.set_score_request"]], "keraseegnex (class in moabb.pipelines.deep_learning)": [[157, "moabb.pipelines.deep_learning.KerasEEGNeX"]], "set_fit_request() (moabb.pipelines.deep_learning.keraseegnex method)": [[157, "moabb.pipelines.deep_learning.KerasEEGNeX.set_fit_request"]], "set_partial_fit_request() (moabb.pipelines.deep_learning.keraseegnex method)": [[157, "moabb.pipelines.deep_learning.KerasEEGNeX.set_partial_fit_request"]], "set_score_request() (moabb.pipelines.deep_learning.keraseegnex method)": [[157, "moabb.pipelines.deep_learning.KerasEEGNeX.set_score_request"]], "keraseegnet_8_2 (class in moabb.pipelines.deep_learning)": [[158, "moabb.pipelines.deep_learning.KerasEEGNet_8_2"]], "set_fit_request() (moabb.pipelines.deep_learning.keraseegnet_8_2 method)": [[158, "moabb.pipelines.deep_learning.KerasEEGNet_8_2.set_fit_request"]], "set_partial_fit_request() (moabb.pipelines.deep_learning.keraseegnet_8_2 method)": [[158, "moabb.pipelines.deep_learning.KerasEEGNet_8_2.set_partial_fit_request"]], "set_score_request() (moabb.pipelines.deep_learning.keraseegnet_8_2 method)": [[158, "moabb.pipelines.deep_learning.KerasEEGNet_8_2.set_score_request"]], "keraseegtcnet (class in moabb.pipelines.deep_learning)": [[159, "moabb.pipelines.deep_learning.KerasEEGTCNet"]], "set_fit_request() (moabb.pipelines.deep_learning.keraseegtcnet method)": [[159, "moabb.pipelines.deep_learning.KerasEEGTCNet.set_fit_request"]], "set_partial_fit_request() (moabb.pipelines.deep_learning.keraseegtcnet method)": [[159, "moabb.pipelines.deep_learning.KerasEEGTCNet.set_partial_fit_request"]], "set_score_request() (moabb.pipelines.deep_learning.keraseegtcnet method)": [[159, "moabb.pipelines.deep_learning.KerasEEGTCNet.set_score_request"]], "kerasshallowconvnet (class in moabb.pipelines.deep_learning)": [[160, "moabb.pipelines.deep_learning.KerasShallowConvNet"]], "set_fit_request() (moabb.pipelines.deep_learning.kerasshallowconvnet method)": [[160, "moabb.pipelines.deep_learning.KerasShallowConvNet.set_fit_request"]], "set_partial_fit_request() (moabb.pipelines.deep_learning.kerasshallowconvnet method)": [[160, "moabb.pipelines.deep_learning.KerasShallowConvNet.set_partial_fit_request"]], "set_score_request() (moabb.pipelines.deep_learning.kerasshallowconvnet method)": [[160, "moabb.pipelines.deep_learning.KerasShallowConvNet.set_score_request"]], "augmenteddataset (class in moabb.pipelines.features)": [[161, "moabb.pipelines.features.AugmentedDataset"]], "extendedssvepsignal (class in moabb.pipelines.features)": [[162, "moabb.pipelines.features.ExtendedSSVEPSignal"]], "fit() (moabb.pipelines.features.extendedssvepsignal method)": [[162, "moabb.pipelines.features.ExtendedSSVEPSignal.fit"]], "transform() (moabb.pipelines.features.extendedssvepsignal method)": [[162, "moabb.pipelines.features.ExtendedSSVEPSignal.transform"]], "fm (class in moabb.pipelines.features)": [[163, "moabb.pipelines.features.FM"]], "fit() (moabb.pipelines.features.fm method)": [[163, "moabb.pipelines.features.FM.fit"]], "transform() (moabb.pipelines.features.fm method)": [[163, "moabb.pipelines.features.FM.transform"]], "logvariance (class in moabb.pipelines.features)": [[164, "moabb.pipelines.features.LogVariance"]], "fit() (moabb.pipelines.features.logvariance method)": [[164, "moabb.pipelines.features.LogVariance.fit"]], "transform() (moabb.pipelines.features.logvariance method)": [[164, "moabb.pipelines.features.LogVariance.transform"]], "standardscaler_epoch (class in moabb.pipelines.features)": [[165, "moabb.pipelines.features.StandardScaler_Epoch"]], "filterbank() (in module moabb.pipelines.utils)": [[166, "moabb.pipelines.utils.FilterBank"]], "create_pipeline_from_config() (in module moabb.pipelines.utils)": [[167, "moabb.pipelines.utils.create_pipeline_from_config"]], "eegnet() (in module moabb.pipelines.utils_deep_model)": [[168, "moabb.pipelines.utils_deep_model.EEGNet"]], "eegnet_tc() (in module moabb.pipelines.utils_deep_model)": [[169, "moabb.pipelines.utils_deep_model.EEGNet_TC"]], "tcn_block() (in module moabb.pipelines.utils_deep_model)": [[170, "moabb.pipelines.utils_deep_model.TCN_block"]], "braindecodedatasetloader() (in module moabb.pipelines.utils_pytorch)": [[171, "moabb.pipelines.utils_pytorch.BraindecodeDatasetLoader"]], "inputshapesettereeg() (in module moabb.pipelines.utils_pytorch)": [[172, "moabb.pipelines.utils_pytorch.InputShapeSetterEEG"]], "set_download_dir() (in module moabb)": [[173, "moabb.set_download_dir"]], "set_log_level() (in module moabb)": [[174, "moabb.set_log_level"]], "setup_seed() (in module moabb)": [[175, "moabb.setup_seed"]]}}) \ No newline at end of file diff --git a/docs/utils.html b/docs/utils.html new file mode 100644 index 00000000..1adada96 --- /dev/null +++ b/docs/utils.html @@ -0,0 +1,569 @@ + + + + + + + + + + + + Utils — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Utils#

+
+

Benchmark#

+ + + + + + +

benchmark([pipelines, evaluations, ...])

Run benchmarks for selected pipelines and datasets.

+
+
+

Utils#

+ + + + + + + + + + + + + + + +

set_log_level([level])

Set log level.

setup_seed(seed)

Set the seed for random, numpy, TensorFlow and PyTorch.

set_download_dir(path)

Set the download directory if required to change from default mne path.

make_process_pipelines(processing, dataset)

Shortcut for the method moabb.paradigms.base.BaseProcessing.make_process_pipelines()

+
+
+ + +
+ + + +
+ +
+ +
+
+
+ +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/whats_new.html b/docs/whats_new.html new file mode 100644 index 00000000..56d03b65 --- /dev/null +++ b/docs/whats_new.html @@ -0,0 +1,1072 @@ + + + + + + + + + + + + What’s new — moabb 1.0.0-dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

What’s new#

+
    +
  • “Enhancements” for new features

  • +
  • “Bugs” for bug fixes

  • +
  • “API changes” for backward-incompatible changes

  • +
+
+

Develop branch#

+
+

Enhancements#

+ +
+
+

Bugs#

+ +
+
+

API changes#

+
    +
  • None

  • +
+
+
+
+

Version - 1.0.0 (Stable - PyPi)#

+
+

Enhancements#

+ +
+
+

Bugs#

+ +
+
+

API changes#

+
    +
  • None

  • +
+
+
+
+

Version - 0.5.0#

+
+

Enhancements#

+ +
+
+

Bugs#

+ +
+
+

API changes#

+
    +
  • None

  • +
+
+
+
+

Version - 0.4.6#

+
+

Enhancements#

+ +
+
+

Bugs#

+ +
+
+
+

Version - 0.4.5#

+
+

Enhancements#

+ +
+
+

Bugs#

+ +
+
+
+

Version - 0.4.4#

+
+

Enhancements#

+ +
+
+

Bugs#

+ +
+
+

API changes#

+
    +
  • Minimum supported Python version is now 3.7

  • +
  • MOABB now depends on scikit-learn >= 1.0

  • +
+
+
+
+

Version - 0.4.3#

+
+

Enhancements#

+ +
+
+

Bugs#

+ +
+
+

API changes#

+ +
+
+
+

Version - 0.4.2#

+
+

Enhancements#

+
    +
  • None

  • +
+
+
+

Bugs#

+ +
+
+

API changes#

+
    +
  • None

  • +
+
+
+
+

Version - 0.4.1#

+
+

Enhancements#

+
    +
  • None

  • +
+
+
+

Bugs#

+ +
+
+

API changes#

+
    +
  • Remove update_path on all datasets, update_path parameter in dataset.data_path() is deprecated (#207 by Sylvain Chevallier)

  • +
+
+
+
+

Version - 0.4.0#

+
+

Enhancements#

+ +
+
+

Bugs#

+ +
+
+

API changes#

+
    +
  • Drop update_path from moabb.download.data_path and moabb.download.data_dl

  • +
+
+
+
+

Version 0.3.0#

+
+

Enhancements#

+ +
+
+

Bugs#

+ +
+
+

API changes#

+
    +
  • None

  • +
+
+
+
+

Version 0.2.1#

+
+

Enhancements#

+ +
+
+

Bugs#

+ +
+
+

API changes#

+
    +
  • None

  • +
+
+
+
+

Version 0.2.0#

+
+

Enhancements#

+ +
+
+

Bugs#

+
    +
  • None

  • +
+
+
+

API changes#

+
    +
  • None

  • +
+
+
+
+ + +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + \ No newline at end of file