diff --git a/.circleci/config.yml b/.circleci/config.yml index d4c387b3be0..644fd8b31b7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -433,13 +433,9 @@ jobs: mne sys_info -pd - run: name: make linkcheck + no_output_timeout: 40m command: | make -C doc linkcheck - - run: - name: make linkcheck-grep - when: always - command: | - make -C doc linkcheck-grep - store_artifacts: path: doc/_build/linkcheck destination: linkcheck diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d4f5921e70c..054b0c65924 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,7 +1,16 @@ -e81ec528a42ac687f3d961ed5cf8e25f236925b0 # black -12395f9d9cf6ea3c72b225b62e052dd0d17d9889 # YAML indentation -d6d2f8c6a2ed4a0b27357da9ddf8e0cd14931b59 # isort -e7dd1588013179013a50d3f6b8e8f9ae0a185783 # ruff format -e39995d9be6fc831c7a4a59f09b7a7c0a41ae315 # percent formatting -940ac9553ce42c15b4c16ecd013824ca3ea7244a # whitespace -1c5b39ff1d99bbcb2fc0e0071a989b3f3845ff30 # ruff UP028 +# PR number should follow the commit number so that our code credit +# can parse this file correctly: +d71e497dcf6f98e19eb81e82e641404a71d2d663 # 1420, split up viz.py +203a96cbba2732d2e349a8f96065e74bbfd2a53b # 5862, split utils.py +ff349f356edb04e1b5f0db13deda8d1a20aca351 # 6767, move around manual parts +31a83063557fbd54d898f00f9527ffc547888395 # 10407, alphabetize docdict +e81ec528a42ac687f3d961ed5cf8e25f236925b0 # 11667, black +12395f9d9cf6ea3c72b225b62e052dd0d17d9889 # 11868, YAML indentation +d6d2f8c6a2ed4a0b27357da9ddf8e0cd14931b59 # 12097, isort +e7dd1588013179013a50d3f6b8e8f9ae0a185783 # 12261, ruff format +940ac9553ce42c15b4c16ecd013824ca3ea7244a # 12533, whitespace +e39995d9be6fc831c7a4a59f09b7a7c0a41ae315 # 12588, percent formatting +1c5b39ff1d99bbcb2fc0e0071a989b3f3845ff30 # 12603, ruff UP028 +b8b168088cb474f27833f5f9db9d60abe00dca83 # 12779, PR JSONs +ee64eba6f345e895e3d5e7d2804fa6aa2dac2e6d # 12781, Header unification +362f9330925fb79a6adc19a42243672676dec63e # 12799, UP038 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 837e4eaa1e2..231488d2d47 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,13 +15,20 @@ Again, thanks for contributing! --> -#### Reference issue -Example: Fixes #1234. +#### Reference issue (if any) + + #### What does this implement/fix? -Explain your changes. + + #### Additional information -Any additional information you think is important. + + diff --git a/.github/actions/rename_towncrier/rename_towncrier.py b/.github/actions/rename_towncrier/rename_towncrier.py index e4efd27ef95..72d4f4be272 100755 --- a/.github/actions/rename_towncrier/rename_towncrier.py +++ b/.github/actions/rename_towncrier/rename_towncrier.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + # Adapted from action-towncrier-changelog import json import os diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 75730eec717..27632574e08 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -9,13 +9,14 @@ permissions: jobs: autofix: - name: Autoupdate changelog entry + name: Autoupdate changelog entry and headers runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.12' - - run: pip install --upgrade towncrier pygithub + - run: pip install --upgrade towncrier pygithub gitpython numpy - run: python ./.github/actions/rename_towncrier/rename_towncrier.py + - run: python ./tools/dev/ensure_headers.py - uses: autofix-ci/action@dd55f44df8f7cdb7a6bf74c78677eb8acd40cd0a diff --git a/.github/workflows/credit.yml b/.github/workflows/credit.yml new file mode 100644 index 00000000000..96ab7544034 --- /dev/null +++ b/.github/workflows/credit.yml @@ -0,0 +1,44 @@ +name: Contributor credit + +on: # yamllint disable-line rule:truthy + # Scheduled actions only run on the main repo branch, which is exactly what we want + schedule: + - cron: '0 0 1 * *' # At 00:00 on day-of-month 1 + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update_credit: + name: Update + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ github.token }} + GITHUB_TOKEN: ${{ github.token }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - run: pip install pygithub -e . + - run: python tools/dev/update_credit_json.py + - run: git add -f doc/sphinxext/prs/*.json + - run: | + git diff && git status --porcelain + if [[ $(git status --porcelain) ]]; then + echo "dirty=true" >> $GITHUB_OUTPUT + fi + id: status + - name: Create PR + run: | + set -xeo pipefail + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git checkout -b credit + git commit -am "MAINT: Update code credit [ci skip]" + git push origin credit + PR_NUM=$(gh pr create --base main --head credit --title "MAINT: Update code credit" --body "Created by \"${{ github.workflow }}\" GitHub action." --label "no-changelog-entry-needed") + echo "Opened https://github.com/mne-tools/mne-python/pull/${PR_NUM}" >> $GITHUB_STEP_SUMMARY + if: steps.status.outputs.dirty == 'true' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b039f9ddc69..571d4329831 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -72,10 +72,10 @@ jobs: python: '3.10' kind: mamba - os: ubuntu-latest - python: '3.9' + python: '3.10' kind: minimal - os: ubuntu-20.04 - python: '3.9' + python: '3.10' kind: old steps: - uses: actions/checkout@v4 @@ -131,4 +131,4 @@ jobs: - uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} - if: success() + if: always() diff --git a/.gitignore b/.gitignore index 79d03aac44f..d66fbef96de 100644 --- a/.gitignore +++ b/.gitignore @@ -97,7 +97,7 @@ cover .venv/ venv/ -*.json +/*.json !codemeta.json .hypothesis/ .ruff_cache/ diff --git a/.mailmap b/.mailmap index d71df509cc2..f130380a955 100644 --- a/.mailmap +++ b/.mailmap @@ -2,8 +2,8 @@ Adam Li Adam Li Adam Li Adam Li Alan Leggitt leggitta Alessandro Tonin Lychfindel <58313635+Lychfindel@users.noreply.github.com> -Alex Rockhill Alex Alex Rockhill Alex +Alex Rockhill Alex Alex Rockhill Alex Rockhill Alex Rockhill Alex Rockhill Alexander Rudiuk Alexander Rudiuk @@ -14,19 +14,23 @@ Alexandre Gramfort Alexandre Gramfort Alexandre Gramfort Alexandre Gramfort Alexandre Gramfort Ana Radanovic anaradanovic <79697247+anaradanovic@users.noreply.github.com> +Andres Rodriguez Andrew Dykstra Andrew Quinn AJQuinn +Andy Gilbert <7andy121@gmail.com> Andrew Gilbert Andy Gilbert <7andy121@gmail.com> Andrew Gilbert -Anna Padee <44297909+apadee@users.noreply.github.com> apadee <44297909+apadee@users.noreply.github.com> +Anna Padee apadee <44297909+apadee@users.noreply.github.com> Anne-Sophie Dubarry annesodub Archit Singhal <43236121+architsinghal-mriirs@users.noreply.github.com> archit singhal Arne Pelzer aplzr <7202498+aplzr@users.noreply.github.com> Arne Pelzer pzr -Ashley Drew <33734402+ashdrew@users.noreply.github.com> ashdrew <33734402+ashdrew@users.noreply.github.com> +Ashley Drew ashdrew <33734402+ashdrew@users.noreply.github.com> Asish Panda kaichogami Basile Pinsard Brad Buran Brad Buran Britta Westner britta-wstnr +btkcodedev +buildqa Burkhard Maess Burkhard Maess Carina Forster Carina Carlos de la Torre carlos @@ -43,15 +47,18 @@ Christina Zhao ChristinaZhao Christoph Dinh Christoph Dinh Christopher J. Bailey Chris Bailey Claire Braboszcz claire-braboszcz +Clemens Brunner Clément Moutard -Cora Kim <41998428+kimcoco@users.noreply.github.com> kimcoco <41998428+kimcoco@users.noreply.github.com> +Cora Kim kimcoco <41998428+kimcoco@users.noreply.github.com> Cristóbal Moënne-Loccoz Cristóbal Dan G. Wakeman Daniel G. Wakeman Dan G. Wakeman Daniel Wakeman Dan G. Wakeman dgwakeman Dan G. Wakeman dgwakeman -Daniel Carlström Schad Daniel C Schad +Daniel C Schad Daniel C Schad +Daniel C Schad Daniel Carlström Schad Daniel McCloy Daniel McCloy +Daniel McCloy Daniel McCloy Daniel McCloy drammock Daniel Strohmeier Daniel Strohmeier Daniel Strohmeier joewalter @@ -70,6 +77,7 @@ Dmitrii Altukhov dmalt Dominik Krzemiński dokato Dominik Welke dominikwelke <33089761+dominikwelke@users.noreply.github.com> Dominik Welke dominikwelke +Dominik Wetzel Dominik Wetzel Eberhard Eich ebeich Eduard Ort Eduard Ort Eduard Ort eort @@ -77,7 +85,7 @@ Eduard Ort examplename Ellen Lau ellenlau Emily Stephen Emily P. Stephen Emily Stephen emilyps14 -Enrico Varano <69973551+enricovara@users.noreply.github.com> enricovara <69973551+enricovara@users.noreply.github.com> +Enrico Varano enricovara <69973551+enricovara@users.noreply.github.com> Enzo Altamiranda enzo Eric Larson Eric Larson Eric Larson Eric Larson @@ -93,7 +101,7 @@ Erkka Heinila Teekuningas Etienne de Montalivet Evgenii Kalenkovich kalenkovich Evgeny Goldstein <84768107+evgenygoldstein@users.noreply.github.com> evgenygoldstein <84768107+evgenygoldstein@users.noreply.github.com> -Ezequiel Mikulan <39155887+ezemikulan@users.noreply.github.com> ezemikulan <39155887+ezemikulan@users.noreply.github.com> +Ezequiel Mikulan ezemikulan <39155887+ezemikulan@users.noreply.github.com> Fahimeh Mamashli <33672431+fmamashli@users.noreply.github.com> fmamashli <33672431+fmamashli@users.noreply.github.com> Fede Raimondo Fede Fede Raimondo Fede Raimondo @@ -104,21 +112,24 @@ Fede Raimondo Federico Raimondo Federico Zamberlan <44038765+fzamberlan@users.noreply.github.com> Felix Klotzsche eioe Felix Klotzsche eioe -Félix Raimundo Felix Raimundo Frederik D. Weber Frederik-D-Weber Fu-Te Wong foucault Fu-Te Wong zuxfoucault +Félix Raimundo Felix Raimundo Gansheng Tan <49130176+GanshengT@users.noreply.github.com> Gansheng TAN <49130176+GanshengT@users.noreply.github.com> Gennadiy Belonosov <7503709+Genuster@users.noreply.github.com> Gennadiy <7503709+Genuster@users.noreply.github.com> Giorgio Marinato neurogima <76406896+neurogima@users.noreply.github.com> +Giulio Gabrieli Guillaume Dumas deep-introspection Guillaume Dumas Guillaume Dumas +Hakimeh Aslsardroud Hamid Maymandi <46011104+HamidMandi@users.noreply.github.com> Hamid <46011104+HamidMandi@users.noreply.github.com> -Hasrat Ali Arzoo <56307533+hasrat17@users.noreply.github.com> hasrat17 <56307533+hasrat17@users.noreply.github.com> +Hasrat Ali Arzoo hasrat17 <56307533+hasrat17@users.noreply.github.com> +Hongjiang Ye YE Hongjiang Hongjiang Ye YE Hongjiang Hubert Banville hubertjb -Hüseyin Orkun Elmas Hüseyin Hyonyoung Shin <55095699+mcvain@users.noreply.github.com> mcvain <55095699+mcvain@users.noreply.github.com> +Hüseyin Orkun Elmas Hüseyin Ingoo Lee dlsrnsi Ivo de Jong ivopascal Jaakko Leppakangas Jaakko Leppakangas @@ -126,15 +137,17 @@ Jaakko Leppakangas jaeilepp Jaakko Leppakangas jaeilepp Jair Montoya jmontoyam Jan Ebert janEbert +Jan Sedivy Jan Sosulski jsosulski Jean-Baptiste Schiratti Jean-Baptiste SCHIRATTI -Jean-Remi King Jean-Rémi KING -Jean-Remi King kingjr -Jean-Remi King kingjr -Jean-Remi King kingjr -Jean-Remi King UMR9752 -Jean-Remi King UMR9752 +Jean-Rémi King Jean-Rémi KING +Jean-Rémi King kingjr +Jean-Rémi King kingjr +Jean-Rémi King kingjr +Jean-Rémi King UMR9752 +Jean-Rémi King UMR9752 Jeff Stout jstout211 +Jennifer Behnke Jesper Duemose Nielsen jdue Jevri Hanna Jeff Hanna Jevri Hanna Jevri Hanna @@ -151,16 +164,18 @@ Jona Sassenhagen jona-sassenhagen jona-sassenhagen@ Jona Sassenhagen jona.sassenhagen@gmail.com Jona Sassenhagen sassenha +Jonathan Kuziek Jordan Drew <39603454+jadrew43@users.noreply.github.com> jadrew43 <39603454+jadrew43@users.noreply.github.com> Joris Van den Bossche Joris Van den Bossche +Joshua Calder-Travis <38797399+jCalderTravis@users.noreply.github.com> jCalderTravis <38797399+jCalderTravis@users.noreply.github.com> +Joshua J Bear +Joshua Teves Joshua Teves José C. García Alanis Jose Alanis José C. García Alanis Jose C. G. Alanis <12409129+JoseAlanis@users.noreply.github.com> José C. García Alanis José C. G. Alanis <12409129+JoseAlanis@users.noreply.github.com> José C. García Alanis José C. García Alanis <12409129+JoseAlanis@users.noreply.github.com> -Joshua J Bear -Joshua Teves Joshua Teves -Joshua Calder-Travis <38797399+jCalderTravis@users.noreply.github.com> jCalderTravis <38797399+jCalderTravis@users.noreply.github.com> Julius Welzel <52565341+JuliusWelzel@users.noreply.github.com> jwelzel <52565341+JuliusWelzel@users.noreply.github.com> +Justus Schwabedal Kaisu Lankinen <41806798+klankinen@users.noreply.github.com> klankinen <41806798+klankinen@users.noreply.github.com> Kambiz Tabavi Kambiz Tavabi Kambiz Tabavi kambysese @@ -171,11 +186,12 @@ Kostiantyn Maksymenko Maksymenko Kostiantyn LaetitiaG Larry Eisenman lneisenman Lenny Varghese lennyvarghese +Liberty Hamilton Lorenz Esch Lorenz Esch Lorenzo Alfine lorrandal Louis Thibault = Louis Thibault Louis Thibault -Lukas Gemein gemeinl +Lukas Gemein gemeinl Lukáš Hejtmánek hejtmy Mads Jensen mads jensen Mainak Jas Mainak @@ -185,21 +201,26 @@ Mainak Jas Mainak Jas mainakjas Manoj Kumar MechCoder Manu Sutela MJAS1 -Marian Dovgialo Marian Dovgialo -Marian Dovgialo mdovgialo +Marian Dovgialo Marian Dovgialo +Marian Dovgialo Marian Dovgialo +Marian Dovgialo mdovgialo Marijn van Vliet Marijn van Vliet -Mark Alexander Henney Mark -Mark Alexander Henney Mark Henney <120719655+henneysq@users.noreply.github.com> +Mark Henney Mark +Mark Henney Mark Alexander Henney +Mark Henney Mark Henney <120719655+henneysq@users.noreply.github.com> Mark Wronkiewicz wronk Marmaduke Woodman maedoc -Martin Billinger kazemakase -Martin Billinger Martin -Martin Billinger Martin Billinger -Martin Billinger mbillingr +Martin BaBer +Martin Billinger kazemakase +Martin Billinger kazemakase +Martin Billinger Martin Billinger +Martin Billinger mbillingr Martin Luessi martin Martin Luessi martin Martin Luessi mluessi@nmr.mgh.harvard.edu -Martin Schulz Martin Schulz <46245704+marsipu@users.noreply.github.com> +Martin Perez-Guevara +Martin Schulz Martin Schulz <46245704+marsipu@users.noreply.github.com> +Martin Schulz Martin Schulz Martin van Harmelen <1544429+MPvHarmelen@users.noreply.github.com> Martin <1544429+MPvHarmelen@users.noreply.github.com> Mathieu Scheltienne Mathieu Scheltienne <73893616+mscheltienne@users.noreply.github.com> Mathieu Scheltienne Mathieu Scheltienne @@ -209,7 +230,7 @@ Mats van Es Mats monkeyman192 Matteo Anelli Matteo Anelli Matteo Visconti di Oleggio Castello Matteo Visconti dOC -Matthias Dold <62005770+matthiasdold@users.noreply.github.com> matthiasdold <62005770+matthiasdold@users.noreply.github.com> +Matthias Dold matthiasdold <62005770+matthiasdold@users.noreply.github.com> Matthias Eberlein <41163089+MatthiasEb@users.noreply.github.com> MatthiasEb <41163089+MatthiasEb@users.noreply.github.com> Matti Hämäläinen Matti Hamalainen Matti Hämäläinen Matti Hamalainen @@ -229,6 +250,7 @@ Nathalie Gayraud Nathalie Naveen <172697+naveensrinivasan@users.noreply.github.com> Nicolas Barascud nbara Nicolas Barascud Nicolas Barascud <10333715+nbara@users.noreply.github.com> +Nicolas Fourcaud-Trocmé Fourcaud-Trocmé Nicolas Gensollen Gensollen Nicolas Legrand Legrand Nicolas Nicolas Legrand LegrandNico @@ -238,12 +260,15 @@ Niklas Wilming Niklas Wilming chapochn <23103092+chapochn@users.noreply.github.com> Nikolai Chapochnikov <23103092+chapochn@users.noreply.github.com> Nikolai M Chapochnikov <23103092+chapochn@users.noreply.github.com> Nikolas Chalas Nichalas +Noah Markowitz <34498671+nmarkowitz@users.noreply.github.com> NoahMarkowitz <34498671+nmarkowitz@users.noreply.github.com> Olaf Hauk Olaf Hauk Olaf Hauk olafhauk Omer Shubi Omer S +Pablo Arias Paul Pasler ppasler Paul Roujansky Paul ROUJANSKY Paul Roujansky paulroujansky +Pavel Navratil Pedro Silva pbnsilva Phillip Alday Phillip Alday Phillip Alday Phillip Alday @@ -253,6 +278,7 @@ Pierre-Antoine Bannier Pierre-Antoine Bannier Pierre-Antoine Bannier Pierre-Antoine Bannier Pierre-Antoine Bannier Pierre-Antoine Bannier Pierre-Antoine Bannier Pierre-Antoine Bannier +Ping-Keng Jao nafraw Praveen Sripad prav Praveen Sripad prav Proloy Das pdas6 @@ -261,9 +287,14 @@ Ramonapariciog Apariciogarcia ramonapariciog roraa Reza Nasri Reza Reza Nasri RezaNasri +Riessarius Stargardsky Roan LaPlante aestrivex -Rob Luke Robert Luke <748691+rob-luke@users.noreply.github.com> +Robert Luke Robert Luke <748691+rob-luke@users.noreply.github.com> +Robert Luke Robert Luke +Robert Seymour Robin Tibor Schirrmeister robintibor +Roeland Hancock +Romain Derollepot Romain Trachel Romain Trachel Romain Trachel Romain Trachel Romain Trachel trachelr @@ -271,9 +302,12 @@ Roman Goj Ross Maddox rkmaddox Ross Maddox Ross Maddox Ross Maddox unknown -Rotem Falach Falach +Rotem Falach Falach Ryan Law Ryan Law +Ryan Law Ryan M.C. Law +Sammi Chekroud Samuel Deslauriers-Gauthier Samuel Deslauriers-Gauthier +Santeri Ruuskanen Santeri Ruuskanen <66060772+ruuskas@users.noreply.github.com> Sara Sommariva sarasommariva Sebastien Treguer DataFox Sena Er <2799280+sena-neuro@users.noreply.github.com> Sena <2799280+sena-neuro@users.noreply.github.com> @@ -283,32 +317,40 @@ Simon Kern Simon Kern <14980558+skjerns@users.noreply.git Simon Kern skjerns <14980558+skjerns@users.noreply.github.com> Simon Kern skjerns Sondre Foslien sondrfos +Sophie Herbst Steve Matindi stevemats Steven Bierer Steven Bierer <40672003+NeuroLaunch@users.noreply.github.com> Steven M. Gutstein S. M. Gutstein Steven M. Gutstein smgutstein -T. Wang <81429617+twang5@users.noreply.github.com> twang5 <81429617+twang5@users.noreply.github.com> +sviter +T. Wang twang5 <81429617+twang5@users.noreply.github.com> Tanay Gahlot Tanay -Teon Brooks -Teon Brooks -Teon Brooks Teon -Teon Brooks Teon Brooks +Teon L Brooks +Teon L Brooks +Teon L Brooks Teon +Teon L Brooks Teon Brooks Thomas Donoghue Tom Thomas Radman -Timon Merk <38216460+timonmerk@users.noreply.github.com> timonmerk <38216460+timonmerk@users.noreply.github.com> +Timon Merk +Timon Merk Timon Merk <38216460+timonmerk@users.noreply.github.com> +Timon Merk timonmerk <38216460+timonmerk@users.noreply.github.com> Timothy Gates Tim Gates +Timur Sokhin Tod Flak <45362686+todflak@users.noreply.github.com> todflak <45362686+todflak@users.noreply.github.com> Tom Ma myd7349 -Tom Stone tomdstone <77251489+tomdstone@users.noreply.github.com> Tom Stone Stone +Tom Stone tomdstone <77251489+tomdstone@users.noreply.github.com> Tristan Stenner Tristan Stenner Tziona NessAiver TzionaN Valerii Chirkov Valerii <42982039+vagechirkov@users.noreply.github.com> Valerii Chirkov Valerii +Velu Prabhakar Kumaravel Velu Prabhakar Kumaravel Victoria Peterson vpeterson +Will Turner Will Turner +Yiping Zuo Frostime Yousra Bekhti Yoursa BEKHTI Yousra Bekhti Yoursa BEKHTI Yousra Bekhti Yousra BEKHTI Yousra Bekhti yousrabk -Yiping Zuo Frostime Zhi Zhang <850734033@qq.com> ZHANG Zhi <850734033@qq.com> +Zhi Zhang <850734033@qq.com> ZHANG Zhi diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8f937143c53..dfe129eb803 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,16 +1,17 @@ repos: # Ruff mne - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.6 + rev: v0.6.5 hooks: - id: ruff name: ruff lint mne args: ["--fix"] - files: ^mne/ + files: ^mne/|^tools/ + exclude: vulture_allowlist.py - id: ruff name: ruff lint mne preview args: ["--fix", "--preview", "--select=NPY201"] - files: ^mne/ + files: ^mne/|^tools/ - id: ruff name: ruff lint doc, tutorials, and examples # D103: missing docstring in public function @@ -18,7 +19,7 @@ repos: args: ["--ignore=D103,D400", "--fix"] files: ^doc/|^tutorials/|^examples/ - id: ruff-format - files: ^mne/|^doc/|^tutorials/|^examples/ + files: ^mne/|^doc/|^tutorials/|^examples/|^tools/ # Codespell - repo: https://github.com/codespell-project/codespell @@ -27,7 +28,7 @@ repos: - id: codespell additional_dependencies: - tomli - files: ^mne/|^doc/|^examples/|^tutorials/ + files: ^mne/|^doc/|^examples/|^tutorials/|^tools/ types_or: [python, bib, rst, inc] # yamllint @@ -45,13 +46,15 @@ repos: additional_dependencies: - tomli files: ^doc/.*\.(rst|inc)$ + # Credit is problematic because we generate an include on the fly + exclude: ^doc/credit.rst$ # sorting - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: - id: file-contents-sorter - files: ^doc/changes/names.inc + files: ^doc/changes/names.inc|^.mailmap args: ["--ignore-case"] # The following are too slow to run on local commits, so let's only run on CIs: diff --git a/CITATION.cff b/CITATION.cff index bea700c0427..a55d21e00c0 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,9 +1,9 @@ cff-version: 1.2.0 title: "MNE-Python" message: "If you use this software, please cite both the software itself, and the paper listed in the preferred-citation field." -version: 1.7.1 -date-released: "2024-06-14" -commit: 7c00b56d077eaf6a2ca691eadd567d974865a03c +version: 1.8.0 +date-released: "2024-08-18" +commit: 9a760d76971e845b67b619804c1156cc04c9c948 doi: 10.5281/zenodo.592483 keywords: - MEG @@ -32,7 +32,7 @@ authors: - family-names: Jas given-names: Mainak - family-names: Brooks - given-names: Teon + given-names: Teon L - family-names: Sassenhagen given-names: Jona - family-names: McCloy @@ -81,8 +81,6 @@ authors: given-names: Mikołaj - family-names: Westner given-names: Britta - - family-names: Billinger - given-names: Martin - family-names: Wakeman given-names: Dan G - family-names: Strohmeier @@ -107,6 +105,8 @@ authors: given-names: Fede - family-names: Nurminen given-names: Jussi + - family-names: Billinger + given-names: Martin - family-names: Montoya given-names: Jair - family-names: Woodman @@ -115,20 +115,20 @@ authors: given-names: Ingoo - family-names: Schulz given-names: Martin - - family-names: Foti - given-names: Nick - family-names: Huberty given-names: Scott + - family-names: Foti + given-names: Nick - family-names: Nangini given-names: Cathy - family-names: García Alanis given-names: José C + - family-names: Orfanos + given-names: Dimitri Papadopoulos - family-names: Hauk given-names: Olaf - family-names: Maddox given-names: Ross - - family-names: Orfanos - given-names: Dimitri Papadopoulos - family-names: LaPlante given-names: Roan - family-names: Drew @@ -137,12 +137,15 @@ authors: given-names: Christoph - family-names: Dumas given-names: Guillaume + - name: Martin - family-names: Benerradi given-names: Johann - family-names: Hartmann given-names: Thomas - family-names: Ort given-names: Eduard + - family-names: Billinger + given-names: Martin - family-names: Pasler given-names: Paul - family-names: Repplinger @@ -179,6 +182,8 @@ authors: given-names: Yaroslav - family-names: Luo given-names: Yu-Han + - family-names: Gramfort + given-names: Alexandre - family-names: Kasper given-names: Johannes - family-names: Doelling @@ -189,8 +194,6 @@ authors: given-names: Tanay - family-names: Nunes given-names: Adonay - - family-names: Gramfort - given-names: Alexandre - family-names: Gütlin given-names: Dirk - family-names: Heinila @@ -266,6 +269,8 @@ authors: given-names: Louis - family-names: Gerster given-names: Moritz + - family-names: Alibou + given-names: Nabil - family-names: Gayraud given-names: Nathalie - family-names: Ward @@ -294,6 +299,8 @@ authors: given-names: Evgenii - family-names: Mamashli given-names: Fahimeh + - family-names: O'Neill + given-names: George - family-names: Marinato given-names: Giorgio - family-names: Anevar @@ -314,8 +321,6 @@ authors: given-names: Lorenz - family-names: Dovgialo given-names: Marian - - family-names: Alibou - given-names: Nabil - family-names: Barascud given-names: Nicolas - family-names: Legrand @@ -332,6 +337,8 @@ authors: given-names: Steve - family-names: Bierer given-names: Steven + - family-names: Binns + given-names: Thomas S - family-names: Binns given-names: Thomas Samuel - family-names: Stenner @@ -364,8 +371,6 @@ authors: given-names: Ezequiel - family-names: Belonosov given-names: Gennadiy - - family-names: O'Neill - given-names: George - family-names: Schiratti given-names: Jean-Baptiste - family-names: Evans @@ -395,6 +400,8 @@ authors: given-names: Matt - family-names: Eberlein given-names: Matthias + - family-names: Žák + given-names: Michal - family-names: Sherif given-names: Mohamed - family-names: Kozhemiako @@ -409,6 +416,8 @@ authors: given-names: Peter J - family-names: Ablin given-names: Pierre + - family-names: Chu + given-names: Qian - family-names: Bertrand given-names: Quentin - family-names: Shoorangiz @@ -486,7 +495,7 @@ authors: - family-names: Braboszcz given-names: Claire - family-names: Schad - given-names: Daniel Carlström + given-names: Daniel C - family-names: Hasegan given-names: Daniel - family-names: Tse @@ -525,6 +534,8 @@ authors: given-names: Etienne - family-names: Goldstein given-names: Evgeny + - family-names: Negahbani + given-names: Farzin - family-names: Zamberlan given-names: Federico - family-names: Hofer @@ -554,6 +565,8 @@ authors: given-names: Hyonyoung - family-names: Elmas given-names: Hüseyin Orkun + - family-names: AZZ + given-names: Ilian - family-names: Machairas given-names: Ilias - family-names: Zubarev @@ -609,14 +622,13 @@ authors: - family-names: Koculak given-names: Marcin - family-names: Henney - given-names: Mark Alexander - - family-names: Oberg + given-names: Mark + - family-names: BaBer given-names: Martin - - family-names: Schulz + - family-names: Oberg given-names: Martin - family-names: van Harmelen given-names: Martin - - name: MartinBaBer - family-names: Courtemanche given-names: Matt - family-names: Tucker @@ -639,6 +651,8 @@ authors: given-names: Mingjian - family-names: Daneshzand given-names: Mohammad + - family-names: Fourcaud-Trocmé + given-names: Nicolas - family-names: Gensollen given-names: Nicolas - family-names: Proulx @@ -647,6 +661,8 @@ authors: given-names: Niels - family-names: Chalas given-names: Nikolas + - family-names: Markowitz + given-names: Noah - family-names: Shubi given-names: Omer - family-names: Mainar @@ -657,8 +673,6 @@ authors: given-names: Pedro - family-names: Das given-names: Proloy - - family-names: Chu - given-names: Qian - family-names: Li given-names: Quanliang - family-names: Barthélemy @@ -747,6 +761,8 @@ authors: given-names: Velu Prabhakar - family-names: Turner given-names: Will + - family-names: Zuazo + given-names: Xabier de - family-names: Xia given-names: Xiaokai - family-names: Zuo diff --git a/README.rst b/README.rst index 236bc1287b2..745e74849c3 100644 --- a/README.rst +++ b/README.rst @@ -74,8 +74,8 @@ Dependencies The minimum required dependencies to run MNE-Python are: - `Python `__ ≥ 3.9 -- `NumPy `__ ≥ 1.23 -- `SciPy `__ ≥ 1.9 +- `NumPy `__ ≥ 1.24 +- `SciPy `__ ≥ 1.10 - `Matplotlib `__ ≥ 3.6 - `Pooch `__ ≥ 1.5 - `tqdm `__ @@ -85,8 +85,8 @@ The minimum required dependencies to run MNE-Python are: For full functionality, some functions require: -- `scikit-learn `__ ≥ 1.1 -- `Joblib `__ ≥ 0.15 (for parallelization) +- `scikit-learn `__ ≥ 1.2 +- `Joblib `__ ≥ 1.2 (for parallelization) - `mne-qt-browser `__ ≥ 0.5 (for fast raw data visualization) - `Qt `__ ≥ 5.15 via one of the following bindings (for fast raw data visualization and interactive 3D visualization): @@ -94,16 +94,16 @@ For full functionality, some functions require: - `PyQt6 `__ ≥ 6.0 - `PyQt5 `__ ≥ 5.15 -- `Numba `__ ≥ 0.54.0 +- `Numba `__ ≥ 0.56.4 - `NiBabel `__ ≥ 3.2.1 - `OpenMEEG `__ ≥ 2.5.6 -- `pandas `__ ≥ 1.3.2 +- `pandas `__ ≥ 1.5.2 - `Picard `__ ≥ 0.3 - `CuPy `__ ≥ 9.0.0 (for NVIDIA CUDA acceleration) - `DIPY `__ ≥ 1.4.0 - `imageio `__ ≥ 2.8.0 -- `PyVista `__ ≥ 0.32 (for 3D visualization) -- `PyVistaQt `__ ≥ 0.4 (for 3D visualization) +- `PyVista `__ ≥ 0.37 (for 3D visualization) +- `PyVistaQt `__ ≥ 0.9 (for 3D visualization) - `mffpy `__ ≥ 0.5.7 - `h5py `__ - `h5io `__ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 73ea5b42ac4..3ced8ce46f9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -244,7 +244,7 @@ stages: PYTHONIOENCODING: 'utf-8' AZURE_CI_WINDOWS: 'true' PYTHON_ARCH: 'x64' - timeoutInMinutes: 70 + timeoutInMinutes: 75 strategy: maxParallel: 4 matrix: diff --git a/codemeta.json b/codemeta.json index c7ec3537dbf..0351ca98a1c 100644 --- a/codemeta.json +++ b/codemeta.json @@ -5,11 +5,11 @@ "codeRepository": "git+https://github.com/mne-tools/mne-python.git", "dateCreated": "2010-12-26", "datePublished": "2014-08-04", - "dateModified": "2024-06-14", - "downloadUrl": "https://github.com/mne-tools/mne-python/archive/v1.7.1.zip", + "dateModified": "2024-08-18", + "downloadUrl": "https://github.com/mne-tools/mne-python/archive/v1.8.0.zip", "issueTracker": "https://github.com/mne-tools/mne-python/issues", "name": "MNE-Python", - "version": "1.7.1", + "version": "1.8.0", "description": "MNE-Python is an open-source Python package for exploring, visualizing, and analyzing human neurophysiological data. It provides methods for data input/output, preprocessing, visualization, source estimation, time-frequency analysis, connectivity analysis, machine learning, and statistics.", "applicationCategory": "Neuroscience", "developmentStatus": "active", @@ -38,9 +38,9 @@ ], "softwareRequirements": [ "python>=3.9", - "numpy>=1.21.2", - "scipy>=1.7.1", - "matplotlib>=3.5.0", + "numpy>=1.23,<3", + "scipy>=1.9", + "matplotlib>=3.6", "tqdm", "pooch>=1.5", "decorator", @@ -88,7 +88,7 @@ { "@type":"Person", "email":"teon.brooks@gmail.com", - "givenName":"Teon", + "givenName":"Teon L", "familyName": "Brooks" }, { @@ -235,12 +235,6 @@ "givenName":"Britta", "familyName": "Westner" }, - { - "@type":"Person", - "email":"martin.billinger@tugraz.at", - "givenName":"Martin", - "familyName": "Billinger" - }, { "@type":"Person", "email":"dgwakeman@gmail.com", @@ -313,6 +307,12 @@ "givenName":"Jussi", "familyName": "Nurminen" }, + { + "@type":"Person", + "email":"flKazemakase@gmail.com", + "givenName":"Martin", + "familyName": "Billinger" + }, { "@type":"Person", "email":"montoya.jair.m@gmail.com", @@ -333,22 +333,22 @@ }, { "@type":"Person", - "email":"dev@earthman-music.de", + "email":"dev@mgschulz.de", "givenName":"Martin", "familyName": "Schulz" }, - { - "@type":"Person", - "email":"nfoti01@gmail.com", - "givenName":"Nick", - "familyName": "Foti" - }, { "@type":"Person", "email":"", "givenName":"Scott", "familyName": "Huberty" }, + { + "@type":"Person", + "email":"nfoti01@gmail.com", + "givenName":"Nick", + "familyName": "Foti" + }, { "@type":"Person", "email":"cnangini@gmail.com", @@ -361,6 +361,12 @@ "givenName":"José C", "familyName": "García Alanis" }, + { + "@type":"Person", + "email":"", + "givenName":"Dimitri Papadopoulos", + "familyName": "Orfanos" + }, { "@type":"Person", "email":"olaf.hauk@mrc-cbu.cam.ac.uk", @@ -373,12 +379,6 @@ "givenName":"Ross", "familyName": "Maddox" }, - { - "@type":"Person", - "email":"", - "givenName":"Dimitri Papadopoulos", - "familyName": "Orfanos" - }, { "@type":"Person", "email":"aestrivex@gmail.com", @@ -387,7 +387,7 @@ }, { "@type":"Person", - "email":"", + "email":"ashdrew@uw.edu", "givenName":"Ashley", "familyName": "Drew" }, @@ -403,6 +403,12 @@ "givenName":"Guillaume", "familyName": "Dumas" }, + { + "@type":"Person", + "email":"martin.billinger@tugraz.at", + "givenName":"", + "familyName": "Martin" + }, { "@type":"Person", "email":"johann.benerradi@gmail.com", @@ -421,6 +427,12 @@ "givenName":"Eduard", "familyName": "Ort" }, + { + "@type":"Person", + "email":"flkazemakase@gmail.com", + "givenName":"Martin", + "familyName": "Billinger" + }, { "@type":"Person", "email":"paul@ppasler.de", @@ -529,6 +541,12 @@ "givenName":"Yu-Han", "familyName": "Luo" }, + { + "@type":"Person", + "email":"agramfort@fb.com", + "givenName":"Alexandre", + "familyName": "Gramfort" + }, { "@type":"Person", "email":"jeythekey@tutanota.com", @@ -559,12 +577,6 @@ "givenName":"Adonay", "familyName": "Nunes" }, - { - "@type":"Person", - "email":"agramfort@fb.com", - "givenName":"Alexandre", - "familyName": "Gramfort" - }, { "@type":"Person", "email":"", @@ -741,7 +753,7 @@ }, { "@type":"Person", - "email":"", + "email":"kimjico@gmail.com", "givenName":"Cora", "familyName": "Kim" }, @@ -793,6 +805,12 @@ "givenName":"Moritz", "familyName": "Gerster" }, + { + "@type":"Person", + "email":"", + "givenName":"Nabil", + "familyName": "Alibou" + }, { "@type":"Person", "email":"nathalie.gayraud@inria.fr", @@ -807,7 +825,7 @@ }, { "@type":"Person", - "email":"", + "email":"santeri.ruuskanen@aalto.fi", "givenName":"Santeri", "familyName": "Ruuskanen" }, @@ -877,6 +895,12 @@ "givenName":"Fahimeh", "familyName": "Mamashli" }, + { + "@type":"Person", + "email":"g.o'neill@ucl.ac.uk", + "givenName":"George", + "familyName": "O'Neill" + }, { "@type":"Person", "email":"giorgio.marinato@unitn.it", @@ -933,16 +957,10 @@ }, { "@type":"Person", - "email":"mdovgialo@fabrizzio.zfb.fuw.edu.pl", + "email":"marian.dowgialo@gmail.com", "givenName":"Marian", "familyName": "Dovgialo" }, - { - "@type":"Person", - "email":"", - "givenName":"Nabil", - "familyName": "Alibou" - }, { "@type":"Person", "email":"", @@ -991,6 +1009,12 @@ "givenName":"Steven", "familyName": "Bierer" }, + { + "@type":"Person", + "email":"t.s.binns@outlook.com", + "givenName":"Thomas S", + "familyName": "Binns" + }, { "@type":"Person", "email":"t.s.binns@outlook.com", @@ -1077,7 +1101,7 @@ }, { "@type":"Person", - "email":"", + "email":"e.mikulan@gmail.com", "givenName":"Ezequiel", "familyName": "Mikulan" }, @@ -1087,12 +1111,6 @@ "givenName":"Gennadiy", "familyName": "Belonosov" }, - { - "@type":"Person", - "email":"g.o'neill@ucl.ac.uk", - "givenName":"George", - "familyName": "O'Neill" - }, { "@type":"Person", "email":"jean.baptiste.schiratti@gmail.com", @@ -1149,7 +1167,7 @@ }, { "@type":"Person", - "email":"", + "email":"lukas.gemein@gmx.de", "givenName":"Lukas", "familyName": "Gemein" }, @@ -1183,6 +1201,12 @@ "givenName":"Matthias", "familyName": "Eberlein" }, + { + "@type":"Person", + "email":"", + "givenName":"Michal", + "familyName": "Žák" + }, { "@type":"Person", "email":"molpsychistb@gmail.com", @@ -1225,6 +1249,12 @@ "givenName":"Pierre", "familyName": "Ablin" }, + { + "@type":"Person", + "email":"", + "givenName":"Qian", + "familyName": "Chu" + }, { "@type":"Person", "email":"quentinbertrand54@gmail.com", @@ -1287,7 +1317,7 @@ }, { "@type":"Person", - "email":"", + "email":"timon.merk@charite.de", "givenName":"Timon", "familyName": "Merk" }, @@ -1377,7 +1407,7 @@ }, { "@type":"Person", - "email":"", + "email":"anna.padee@gmail.com", "givenName":"Anna", "familyName": "Padee" }, @@ -1462,7 +1492,7 @@ { "@type":"Person", "email":"daniel.c.schad@protonmail.com", - "givenName":"Daniel Carlström", + "givenName":"Daniel C", "familyName": "Schad" }, { @@ -1551,7 +1581,7 @@ }, { "@type":"Person", - "email":"", + "email":"enricovarano@gmail.com", "givenName":"Enrico", "familyName": "Varano" }, @@ -1579,6 +1609,12 @@ "givenName":"Evgeny", "familyName": "Goldstein" }, + { + "@type":"Person", + "email":"farzin.negahbani@gmail.com", + "givenName":"Farzin", + "familyName": "Negahbani" + }, { "@type":"Person", "email":"", @@ -1641,7 +1677,7 @@ }, { "@type":"Person", - "email":"", + "email":"hasrat407@gmail.com", "givenName":"Hasrat Ali", "familyName": "Arzoo" }, @@ -1669,6 +1705,12 @@ "givenName":"Hüseyin Orkun", "familyName": "Elmas" }, + { + "@type":"Person", + "email":"", + "givenName":"Ilian", + "familyName": "AZZ" + }, { "@type":"Person", "email":"", @@ -1834,20 +1876,20 @@ { "@type":"Person", "email":"mah@optoceutics.com", - "givenName":"Mark Alexander", + "givenName":"Mark", "familyName": "Henney" }, { "@type":"Person", - "email":"", + "email":"Martinb.nmb@gmail.com", "givenName":"Martin", - "familyName": "Oberg" + "familyName": "BaBer" }, { "@type":"Person", - "email":"dev@mgschulz.de", + "email":"", "givenName":"Martin", - "familyName": "Schulz" + "familyName": "Oberg" }, { "@type":"Person", @@ -1855,12 +1897,6 @@ "givenName":"Martin", "familyName": "van Harmelen" }, - { - "@type":"Person", - "email":"Martinb.nmb@gmail.com", - "givenName":"", - "familyName": "MartinBaBer" - }, { "@type":"Person", "email":"", @@ -1881,7 +1917,7 @@ }, { "@type":"Person", - "email":"", + "email":"matthias.dold@gmx.net", "givenName":"Matthias", "familyName": "Dold" }, @@ -1927,6 +1963,12 @@ "givenName":"Mohammad", "familyName": "Daneshzand" }, + { + "@type":"Person", + "email":"celicolimmo@free.fr", + "givenName":"Nicolas", + "familyName": "Fourcaud-Trocmé" + }, { "@type":"Person", "email":"nicolas.gensollen@gmail.com", @@ -1951,6 +1993,12 @@ "givenName":"Nikolas", "familyName": "Chalas" }, + { + "@type":"Person", + "email":"", + "givenName":"Noah", + "familyName": "Markowitz" + }, { "@type":"Person", "email":"omer.shubi@gmail.com", @@ -1981,12 +2029,6 @@ "givenName":"Proloy", "familyName": "Das" }, - { - "@type":"Person", - "email":"", - "givenName":"Qian", - "familyName": "Chu" - }, { "@type":"Person", "email":"glia@dtu.dk", @@ -2193,7 +2235,7 @@ }, { "@type":"Person", - "email":"", + "email":"twang5@swarthmore.edu", "givenName":"T", "familyName": "Wang" }, @@ -2251,6 +2293,12 @@ "givenName":"Will", "familyName": "Turner" }, + { + "@type":"Person", + "email":"xabier@zuazo.org", + "givenName":"Xabier de", + "familyName": "Zuazo" + }, { "@type":"Person", "email":"xia@xiaokai.me", diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 00000000000..e696138e098 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1 @@ +/code_credit.inc diff --git a/doc/Makefile b/doc/Makefile index 6569adab0f3..c0badd0bd9b 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -65,10 +65,7 @@ html_dev-noplot: html-noplot html_dev-front: html-front linkcheck: - @$(SPHINXBUILD) -b linkcheck -D nitpicky=0 -D plot_gallery=0 -D exclude_patterns="cited.rst,whats_new.rst,configure_git.rst,_includes,changes/devel" -d _build/doctrees . _build/linkcheck - -linkcheck-grep: - @! grep -h "^.*:.*: \[\(\(local\)\|\(broken\)\)\]" _build/linkcheck/output.txt + @$(SPHINXBUILD) -b linkcheck -D nitpicky=0 -q -D plot_gallery=0 -D exclude_patterns="cited.rst,whats_new.rst,configure_git.rst,_includes,changes/devel" -d _build/doctrees . _build/linkcheck doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest @@ -79,3 +76,6 @@ view: @python -c "import webbrowser; webbrowser.open_new_tab('file://$(PWD)/_build/html/sg_execution_times.html')" show: view + +serve: + python -m http.server -d _build/html diff --git a/doc/_includes/institutional-partners.rst b/doc/_includes/institutional-partners.rst index 46fcc1ede4e..6fac24c6e29 100644 --- a/doc/_includes/institutional-partners.rst +++ b/doc/_includes/institutional-partners.rst @@ -19,7 +19,7 @@ Current partners - `Children’s Hospital of Philadelphia Research Institute `_ - `Donders Institute for Brain, Cognition and Behaviour at Radboud University `_ - `Harvard Medical School `_ -- `Human Neuroscience Platform at Fondation Campus Biotech Geneva `_ +- `Fondation Campus Biotech Geneva `_ - `Institut national de recherche en informatique et en automatique `_ - `Karl-Franzens-Universität Graz `_ - `Massachusetts General Hospital `_ diff --git a/doc/_static/js/set_installer_tab.js b/doc/_static/js/set_installer_tab.js index 5b6b737a565..3b4c043387a 100644 --- a/doc/_static/js/set_installer_tab.js +++ b/doc/_static/js/set_installer_tab.js @@ -12,21 +12,34 @@ function setTabs() { } if (navigator.userAgent.indexOf("Mac") !== -1) { // there's no good way to distinguish intel vs M1 in javascript so we - // just default to showing the first of the 2 macOS tabs - platform = "macos-intel"; + // just default to showing the most modern macOS installer + platform = "macos-apple"; } - let all_tab_nodes = document.querySelectorAll( - '.platform-selector-tabset')[0].children; - let input_nodes = [...all_tab_nodes].filter( - child => child.nodeName === "INPUT"); + var platform_short = platform.split("-")[0]; + let tab_label_nodes = [...document.querySelectorAll('.sd-tab-label')]; - let correct_label = tab_label_nodes.filter( + + let install_tab_nodes = document.querySelectorAll( + '.install-selector-tabset')[0].children; + let install_input_nodes = [...install_tab_nodes].filter( + child => child.nodeName === "INPUT"); + let install_label = tab_label_nodes.filter( // label.id is drawn from :name: property in the rST, which must // be unique across the whole site (*sigh*) - label => label.id.startsWith(platform))[0]; - let input_id = correct_label.getAttribute('for'); - let correct_input = input_nodes.filter(node => node.id === input_id)[0]; - correct_input.checked = true; + label => label.id.startsWith(`install-${platform}`))[0]; + let install_id = install_label.getAttribute('for'); + let install_input = install_input_nodes.filter(node => node.id === install_id)[0]; + install_input.checked = true; + + let uninstall_tab_nodes = document.querySelectorAll( + '.uninstall-selector-tabset')[0].children; + let uninstall_input_nodes = [...uninstall_tab_nodes].filter( + child => child.nodeName === "INPUT"); + let uninstall_label = tab_label_nodes.filter( + label => label.id.startsWith(`uninstall-${platform_short}`))[0]; + let uninstall_id = uninstall_label.getAttribute('for'); + let uninstall_input = uninstall_input_nodes.filter(node => node.id === uninstall_id)[0]; + uninstall_input.checked = true; } documentReady(setTabs); diff --git a/doc/_static/js/update_installer_version.js b/doc/_static/js/update_installer_version.js index 7cb8bdede1e..ad18890caf7 100644 --- a/doc/_static/js/update_installer_version.js +++ b/doc/_static/js/update_installer_version.js @@ -54,7 +54,7 @@ async function warnVersion() { title.innerText = "Warning"; inner.innerText = warn; outer.append(title, inner); - document.querySelectorAll('.platform-selector-tabset')[0].before(outer); + document.querySelectorAll('.install-selector-tabset')[0].before(outer); } } diff --git a/doc/_static/versions.json b/doc/_static/versions.json index 48e4006f494..ba4f9fc5d99 100644 --- a/doc/_static/versions.json +++ b/doc/_static/versions.json @@ -1,14 +1,19 @@ [ { - "name": "1.8 (devel)", + "name": "1.9 (devel)", "version": "dev", "url": "https://mne.tools/dev/" }, { - "name": "1.7 (stable)", + "name": "1.8 (stable)", "version": "stable", "url": "https://mne.tools/stable/" }, + { + "name": "1.7", + "version": "1.7", + "url": "https://mne.tools/1.7/" + }, { "name": "1.6", "version": "1.6", diff --git a/doc/_templates/sidebar-quicklinks.html b/doc/_templates/sidebar-quicklinks.html index fad7be67401..fa26fc0f298 100644 --- a/doc/_templates/sidebar-quicklinks.html +++ b/doc/_templates/sidebar-quicklinks.html @@ -7,6 +7,7 @@
Version {{ release }}
  • Get help
  • Cite
  • Contribute
  • +
  • Contributors
  • diff --git a/doc/api/reading_raw_data.rst b/doc/api/reading_raw_data.rst index 50f524ce7c8..50318d3ae91 100644 --- a/doc/api/reading_raw_data.rst +++ b/doc/api/reading_raw_data.rst @@ -14,33 +14,34 @@ Reading raw data anonymize_info read_raw + read_raw_ant read_raw_artemis123 + read_raw_bdf + read_raw_boxy + read_raw_brainvision read_raw_bti read_raw_cnt read_raw_ctf read_raw_curry read_raw_edf + read_raw_eeglab + read_raw_egi + read_raw_eximia read_raw_eyelink - read_raw_bdf + read_raw_fieldtrip + read_raw_fif + read_raw_fil read_raw_gdf + read_raw_hitachi read_raw_kit read_raw_nedf read_raw_nicolet - read_raw_hitachi - read_raw_nirx - read_raw_snirf - read_raw_eeglab - read_raw_brainvision - read_raw_egi - read_raw_fif - read_raw_eximia - read_raw_fieldtrip - read_raw_boxy - read_raw_persyst read_raw_nihon - read_raw_fil + read_raw_nirx read_raw_nsx read_raw_neuralynx + read_raw_persyst + read_raw_snirf Base class: diff --git a/doc/changes/devel/12300.apichange.rst b/doc/changes/devel/12300.apichange.rst deleted file mode 100644 index f9d082a4b96..00000000000 --- a/doc/changes/devel/12300.apichange.rst +++ /dev/null @@ -1,3 +0,0 @@ -A new argument ``events_as_annotations`` has been added to :func:`mne.io.read_raw_egi` -with a default value of ``False`` that will change to ``True`` in version 1.9, by -`Scott Huberty`_ and `Eric Larson`_. diff --git a/doc/changes/devel/12300.bugfix.rst b/doc/changes/devel/12300.bugfix.rst deleted file mode 100644 index c5c167d0114..00000000000 --- a/doc/changes/devel/12300.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug where an event that occurred only once was excluded in :func:`mne.io.read_raw_egi`, by :newcontrib:`Ping-Keng Jao`. diff --git a/doc/changes/devel/12338.newfeature.rst b/doc/changes/devel/12338.newfeature.rst deleted file mode 100644 index 899884d8b61..00000000000 --- a/doc/changes/devel/12338.newfeature.rst +++ /dev/null @@ -1 +0,0 @@ -Adding :meth:`mne.channels.Layout.copy` and :meth:`mne.channels.Layout.pick` to copy and select channels from a :class:`mne.channels.Layout` object. Plotting 2D topographies of evoked responses with :func:`mne.viz.plot_evoked_topo` with both arguments ``layout`` and ``exclude`` now ignores excluded channels from the :class:`mne.channels.Layout`. By `Mathieu Scheltienne`_. diff --git a/doc/changes/devel/12554.dependency.rst b/doc/changes/devel/12554.dependency.rst deleted file mode 100644 index 5c77efd325f..00000000000 --- a/doc/changes/devel/12554.dependency.rst +++ /dev/null @@ -1,6 +0,0 @@ -Minimum versions for dependencies were bumped to those ~2 years old at the time of release (by `Eric Larson`_), including: - -- NumPy ≥ 1.23 -- SciPy ≥ 1.9 -- Matplotlib ≥ 3.6 -- scikit-learn ≥ 1.1 \ No newline at end of file diff --git a/doc/changes/devel/12556.newfeature.rst b/doc/changes/devel/12556.newfeature.rst deleted file mode 100644 index cbd86d984e7..00000000000 --- a/doc/changes/devel/12556.newfeature.rst +++ /dev/null @@ -1 +0,0 @@ -In :class:`~mne.Report` you can now easily navigate through images and figures connected to a slider with the left and right arrow keys. Clicking on the slider or respective image will focus the slider, enabling keyboard navigation, by `Richard Höchenberger`_ diff --git a/doc/changes/devel/12561.bugfix.rst b/doc/changes/devel/12561.bugfix.rst deleted file mode 100644 index e647b2770e1..00000000000 --- a/doc/changes/devel/12561.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix scrolling behavior in :class:`~mne.Report` when clicking on a TOC entry multiple times, by `Richard Höchenberger`_. diff --git a/doc/changes/devel/12562.bugfix.rst b/doc/changes/devel/12562.bugfix.rst deleted file mode 100644 index 8b58e1bc109..00000000000 --- a/doc/changes/devel/12562.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug where :func:`mne.decoding.get_coef` did not work properly with :class:`mne.decoding.CSP`, by `Eric Larson`_. diff --git a/doc/changes/devel/12569.other.rst b/doc/changes/devel/12569.other.rst deleted file mode 100644 index acbd7d79663..00000000000 --- a/doc/changes/devel/12569.other.rst +++ /dev/null @@ -1 +0,0 @@ -Added `vulture `__ as a pre-commit hook and removed related dead code, by `Eric Larson`_. diff --git a/doc/changes/devel/12573.newfeature.rst b/doc/changes/devel/12573.newfeature.rst deleted file mode 100644 index 147db983edc..00000000000 --- a/doc/changes/devel/12573.newfeature.rst +++ /dev/null @@ -1,3 +0,0 @@ -When plotting EOG and ECG artifact scores for ICA in :meth:`mne.Report.add_ica`, -the channel names used for artifact detection are now displayed in the titles of -each respective subplot, by `Richard Höchenberger`_. \ No newline at end of file diff --git a/doc/changes/devel/12576.newfeature.rst b/doc/changes/devel/12576.newfeature.rst deleted file mode 100644 index 06ea4bb85b0..00000000000 --- a/doc/changes/devel/12576.newfeature.rst +++ /dev/null @@ -1 +0,0 @@ -Use ``aseg='auto'`` for :meth:`mne.viz.Brain.add_volume_labels` and :func:`mne.get_montage_volume_labels` to use ``aparc+aseg`` by default or if not present use ``wmparc`` because freesurfer uses ``wmparc`` in the latest version, by `Alex Rockhill`_. diff --git a/doc/changes/devel/12578.bugfix.rst b/doc/changes/devel/12578.bugfix.rst deleted file mode 100644 index e22dffdd020..00000000000 --- a/doc/changes/devel/12578.bugfix.rst +++ /dev/null @@ -1,3 +0,0 @@ -The color scaling of Evoked topomaps added to reports via :meth:`mne.Report.add_evokeds` -was sometimes sub-optimal if bad channels were present in the data. This has now been fixed -and should be more consistent with the topomaps shown in the joint plots, by `Richard Höchenberger`_. diff --git a/doc/changes/devel/12583.apichange.rst b/doc/changes/devel/12583.apichange.rst deleted file mode 100644 index 92d64f5caf3..00000000000 --- a/doc/changes/devel/12583.apichange.rst +++ /dev/null @@ -1,2 +0,0 @@ -``mne.Info.ch_names`` will now return an empty list instead of raising a ``KeyError`` if no channels -are present, by `Richard Höchenberger`_. \ No newline at end of file diff --git a/doc/changes/devel/12583.newfeature.rst b/doc/changes/devel/12583.newfeature.rst deleted file mode 100644 index 27a0258f8ab..00000000000 --- a/doc/changes/devel/12583.newfeature.rst +++ /dev/null @@ -1,4 +0,0 @@ -The HTML representations of :class:`~mne.io.Raw`, :class:`~mne.Epochs`, -and :class:`~mne.Evoked` (which you will see e.g. when working with Jupyter Notebooks or -:class:`~mne.Report`) have been updated to be more consistent and contain -slightly more information, by `Richard Höchenberger`_. (:gh:`12624`) diff --git a/doc/changes/devel/12584.newfeature.rst b/doc/changes/devel/12584.newfeature.rst deleted file mode 100644 index 88f286afbbe..00000000000 --- a/doc/changes/devel/12584.newfeature.rst +++ /dev/null @@ -1,4 +0,0 @@ -When adding :class:`~mne.Evoked` data to a :class:`~mne.Report` via -:meth:`~mne.Report.add_evokeds`, we now also include an "Info" section -with some basic summary info, as has already been the case for raw and -epochs data, by `Richard Höchenberger`_. \ No newline at end of file diff --git a/doc/changes/devel/12593.bugfix.rst b/doc/changes/devel/12593.bugfix.rst deleted file mode 100644 index e43d6110716..00000000000 --- a/doc/changes/devel/12593.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix error causing :meth:`mne.Epochs.interpolate_bads` not to work for ``seeg`` channels and fix a single contact on neighboring shafts sometimes being included in interpolation, by `Alex Rockhill`_ \ No newline at end of file diff --git a/doc/changes/devel/12597.bugfix.rst b/doc/changes/devel/12597.bugfix.rst deleted file mode 100644 index 77997893f0f..00000000000 --- a/doc/changes/devel/12597.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug where :func:`mne.io.read_raw_fil` could not assign bad channels on import, by `George O'Neill`_. \ No newline at end of file diff --git a/doc/changes/devel/12600.other.rst b/doc/changes/devel/12600.other.rst deleted file mode 100644 index e31e0fa7030..00000000000 --- a/doc/changes/devel/12600.other.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed issue template links by :newcontrib:`Michal Žák` diff --git a/doc/changes/devel/12605.bugfix.rst b/doc/changes/devel/12605.bugfix.rst deleted file mode 100644 index 0251eed410e..00000000000 --- a/doc/changes/devel/12605.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed a bug where :meth:`mne.Evoked.animate_topomap` did not work with :func:`mne.preprocessing.compute_current_source_density` - modified data, by `Michal Žák`_. diff --git a/doc/changes/devel/12609.bugfix.rst b/doc/changes/devel/12609.bugfix.rst deleted file mode 100644 index 1cd7e50d664..00000000000 --- a/doc/changes/devel/12609.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug where :func:`mne.stats.permutation_cluster_test` (and related functions) uses excessive amount of memory for large 2D data when TFCE method is selected, by :newcontrib:`Nicolas Fourcaud-Trocmé`. \ No newline at end of file diff --git a/doc/changes/devel/12612.bugfix.rst b/doc/changes/devel/12612.bugfix.rst deleted file mode 100644 index 5868fb93a2a..00000000000 --- a/doc/changes/devel/12612.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix overflow when plotting source estimates where data is all zero (or close to zero), and fix the range of allowed values for the colorbar sliders, by `Marijn van Vliet`_. diff --git a/doc/changes/devel/12616.bugfix.rst b/doc/changes/devel/12616.bugfix.rst deleted file mode 100644 index b7c5fc7fced..00000000000 --- a/doc/changes/devel/12616.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix adding channels to :class:`~mne.time_frequency.EpochsTFR` objects, by `Clemens Brunner`_. \ No newline at end of file diff --git a/doc/changes/devel/12620.bugfix.rst b/doc/changes/devel/12620.bugfix.rst deleted file mode 100644 index 0e8d53f02b1..00000000000 --- a/doc/changes/devel/12620.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix for new sklearn metadata routing protocol in decoding search_light, by `Alex Gramfort`_ diff --git a/doc/changes/devel/12628.newfeature.rst b/doc/changes/devel/12628.newfeature.rst deleted file mode 100644 index 82bab838318..00000000000 --- a/doc/changes/devel/12628.newfeature.rst +++ /dev/null @@ -1,4 +0,0 @@ -We added new installation variants for a full installation with the PySide6 Qt binding -(``"mne[full-pyside6]"``), with the PyQt6 binding (``"mne[full-pyqt6]"``, equivalent to -``"mne[full]"``), and without any Qt binding (``"mne[full-no-qt]"``), which may be useful -in certain situations by `Richard Höchenberger`_. diff --git a/doc/changes/devel/12633.bugfix.rst b/doc/changes/devel/12633.bugfix.rst deleted file mode 100644 index dfc69bc2fe7..00000000000 --- a/doc/changes/devel/12633.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug where :func:`mne.time_frequency.csd_multitaper`, :func:`mne.time_frequency.csd_fourier`, :func:`mne.time_frequency.csd_array_multitaper`, and :func:`mne.time_frequency.csd_array_fourier` would return cross-spectral densities with the ``fmin`` and ``fmax`` frequencies missing, by `Thomas Binns`_ \ No newline at end of file diff --git a/doc/changes/devel/12646.bugfix.rst b/doc/changes/devel/12646.bugfix.rst deleted file mode 100644 index a02ec58f77c..00000000000 --- a/doc/changes/devel/12646.bugfix.rst +++ /dev/null @@ -1,10 +0,0 @@ -Output types of sparse arrays were changed from ``matrix`` to ``array`` in -:func:`~mne.channels.read_ch_adjacency`, :func:`~mne.channels.find_ch_adjacency`, -:func:`~mne.stats.combine_adjacency`, :func:`~mne.spatio_temporal_src_adjacency`, -and related functions to comply with the pending deprecation of ``np.matrix``. -The returned objects now behave like standard :class:`~numpy.ndarray` objects, and -in particular ``*`` now operates element-wise instead of performing matrix -multiplication. You can use ``@`` as a backward compatible matrix multiplication -for both ``np.matrix`` and ``np.ndarray`` objects, and if a matrix is desired -the outputs can be cast directly, for example as ``scipy.sparse.csr_matrix(out)``. -Changed by `Eric Larson`_. diff --git a/doc/changes/devel/12649.newfeature.rst b/doc/changes/devel/12649.newfeature.rst deleted file mode 100644 index 33908f8dc89..00000000000 --- a/doc/changes/devel/12649.newfeature.rst +++ /dev/null @@ -1 +0,0 @@ -Adding argument ``'random'`` to :func:`~mne.epochs.equalize_epoch_counts` and to :meth:`~mne.Epochs.equalize_event_counts` to randomly select epochs or events. By `Mathieu Scheltienne`_. diff --git a/doc/changes/devel/12650.other.rst b/doc/changes/devel/12650.other.rst deleted file mode 100644 index b97a204dff4..00000000000 --- a/doc/changes/devel/12650.other.rst +++ /dev/null @@ -1 +0,0 @@ -Enhance documentation on decimation filtering to prevent aliasing, by :newcontrib:`Xabier de Zuazo`. diff --git a/doc/changes/devel/12652.newfeature.rst b/doc/changes/devel/12652.newfeature.rst deleted file mode 100644 index 6273aa7b87f..00000000000 --- a/doc/changes/devel/12652.newfeature.rst +++ /dev/null @@ -1 +0,0 @@ -Add new parameter ``ignore_marker_types`` to :func:`~mne.io.read_raw_brainvision` to ignore marker types (and only use marker descriptions) when reading BrainVision files, by `Clemens Brunner`_. \ No newline at end of file diff --git a/doc/changes/devel/12655.newfeature.rst b/doc/changes/devel/12655.newfeature.rst deleted file mode 100644 index b2711d2f2ed..00000000000 --- a/doc/changes/devel/12655.newfeature.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added support for passing ``axes`` to :func:`mne.viz.plot_head_positions` when -``mode='field'``, by `Eric Larson`_. diff --git a/doc/changes/devel/12659.other.rst b/doc/changes/devel/12659.other.rst deleted file mode 100644 index f538d3adc1e..00000000000 --- a/doc/changes/devel/12659.other.rst +++ /dev/null @@ -1 +0,0 @@ -Add link to BEst-Python in the list of related software. by `Ilian Azz`_. \ No newline at end of file diff --git a/doc/changes/devel/12661.bugfix.rst b/doc/changes/devel/12661.bugfix.rst deleted file mode 100644 index 5dae12d05ec..00000000000 --- a/doc/changes/devel/12661.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix incorrect RuntimeWarning (different channel filter settings) in EDF/BDF import, by `Clemens Brunner`_. \ No newline at end of file diff --git a/doc/changes/devel/12664.other.rst b/doc/changes/devel/12664.other.rst deleted file mode 100644 index 1647e12cda0..00000000000 --- a/doc/changes/devel/12664.other.rst +++ /dev/null @@ -1 +0,0 @@ -Improved clarity of parameter documentation for `mne.decoding.SSD.fit`, by `Thomas Binns`_. \ No newline at end of file diff --git a/doc/changes/devel/12669.newfeature.rst b/doc/changes/devel/12669.newfeature.rst deleted file mode 100644 index a5829f22060..00000000000 --- a/doc/changes/devel/12669.newfeature.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added internals to allow modifying single-channel annotations in the Qt -raw browser, by :newcontrib:`Noah Markowitz`. \ No newline at end of file diff --git a/doc/changes/devel/12676.bugfix.rst b/doc/changes/devel/12676.bugfix.rst deleted file mode 100644 index 44ccc9feee5..00000000000 --- a/doc/changes/devel/12676.bugfix.rst +++ /dev/null @@ -1,2 +0,0 @@ -In :func:`mne.export.export_raw` (``fmt='edf'``), when padding data to create equal-length data blocks, -edge-padding is favored over zero-padding in order to avoid accidentally enlarging physical range, by `Qian Chu`_. \ No newline at end of file diff --git a/doc/changes/devel/12686.newfeature.rst b/doc/changes/devel/12686.newfeature.rst deleted file mode 100644 index bb67cc622df..00000000000 --- a/doc/changes/devel/12686.newfeature.rst +++ /dev/null @@ -1,2 +0,0 @@ -The HTML representation of :class:`~mne.Epochs` (visible e.g. in Jupyter or in :class:`~mne.Report`) now -indicates whether metadata is attached to the epochs, by `Richard Höchenberger`_. \ No newline at end of file diff --git a/doc/changes/devel/12687.bugfix.rst b/doc/changes/devel/12687.bugfix.rst deleted file mode 100644 index a7d049f8ae5..00000000000 --- a/doc/changes/devel/12687.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -In :func:`mne.io.read_raw_eyelink`, gracefully handle missing datetime in file by `Scott Huberty`_. \ No newline at end of file diff --git a/doc/changes/devel/12688.other.rst b/doc/changes/devel/12688.other.rst deleted file mode 100644 index 620eca7e3f7..00000000000 --- a/doc/changes/devel/12688.other.rst +++ /dev/null @@ -1 +0,0 @@ -Disable the "Back to top" button in the documentation, by `Richard Höchenberger`_. \ No newline at end of file diff --git a/doc/changes/devel/12694.bugfix.rst b/doc/changes/devel/12694.bugfix.rst deleted file mode 100644 index 18abfed7ebc..00000000000 --- a/doc/changes/devel/12694.bugfix.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix regression with :class:`mne.decoding.CSP` where using ``rank="full"`` errantly -raised an error, by `Eric Larson`_. \ No newline at end of file diff --git a/doc/changes/devel/12697.other.rst b/doc/changes/devel/12697.other.rst deleted file mode 100644 index 643b9a07af2..00000000000 --- a/doc/changes/devel/12697.other.rst +++ /dev/null @@ -1 +0,0 @@ -Improve argument ``ylim`` documentation through :class:`~mne.Evoked` plotting function and validate type to :class:`dict` or ``None`` to prevent misuage, by `Mathieu Scheltienne`_. diff --git a/doc/changes/devel/12699.apichange.rst b/doc/changes/devel/12699.apichange.rst deleted file mode 100644 index 37f489afeb6..00000000000 --- a/doc/changes/devel/12699.apichange.rst +++ /dev/null @@ -1 +0,0 @@ -Documented that :func:`~mne.match_channel_orders` can also work on Epochs, and Evoked objects. Reflecting this, deprecated the ``raws`` parameter in favor of an ``insts`` parameter, by `Stefan Appelhoff`_. diff --git a/doc/changes/devel/12703.newfeature.rst b/doc/changes/devel/12703.newfeature.rst deleted file mode 100644 index 0c6afa4468b..00000000000 --- a/doc/changes/devel/12703.newfeature.rst +++ /dev/null @@ -1 +0,0 @@ -Montage plots created with :meth:`~mne.channels.DigMontage.plot` now scale both the channel dots *and* channel names with the new ``scale`` parameter. The default is ``scale=1`` (factors less than 1 will scale down, whereas factors greater than 1 will scale up). The previous ``scale_factor`` parameter only affected marker size, and this parameter is now deprecated. By `Clemens Brunner`_. \ No newline at end of file diff --git a/doc/changes/devel/12707.newfeature.rst b/doc/changes/devel/12707.newfeature.rst deleted file mode 100644 index 3e367296378..00000000000 --- a/doc/changes/devel/12707.newfeature.rst +++ /dev/null @@ -1 +0,0 @@ -Add :func:`~mne.stats.erp.compute_sme` to compute the analytical standardized measurement error (SME) as a data quality measure for ERP studies, by `Clemens Brunner`_. \ No newline at end of file diff --git a/doc/changes/devel/12719.apichange.rst b/doc/changes/devel/12719.apichange.rst deleted file mode 100644 index d1512070f03..00000000000 --- a/doc/changes/devel/12719.apichange.rst +++ /dev/null @@ -1,2 +0,0 @@ -The ``block`` argument to :class:`mne.viz.Brain` is deprecated and will be removed in -1.9, use :func:`matplotlib.pyplot.show` with ``block=True`` instead, by `Eric Larson`_. \ No newline at end of file diff --git a/doc/changes/devel/12720.bugfix.rst b/doc/changes/devel/12720.bugfix.rst deleted file mode 100644 index 41aa30ac14c..00000000000 --- a/doc/changes/devel/12720.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix in-memory anonymization of data read with :func:`mne.io.read_raw_edf` by `Eric Larson`_. diff --git a/doc/changes/devel/12720.newfeature.rst b/doc/changes/devel/12720.newfeature.rst deleted file mode 100644 index 39b4709caba..00000000000 --- a/doc/changes/devel/12720.newfeature.rst +++ /dev/null @@ -1,2 +0,0 @@ -Use :class:`python:datetime.date` for ``info["subject_info"]["birthday"]`` rather than -a tuple of ``(year, month, day)`` by `Eric Larson`_. diff --git a/doc/changes/devel/12721.bugfix.rst b/doc/changes/devel/12721.bugfix.rst deleted file mode 100644 index c3fbe513d03..00000000000 --- a/doc/changes/devel/12721.bugfix.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug with overplotting of butterfly labels in :func:`mne.viz.plot_raw` and related -functions and methods, by `Eric Larson`_. diff --git a/doc/changes/devel/12724.bugfix.rst b/doc/changes/devel/12724.bugfix.rst deleted file mode 100644 index 8799c2830ec..00000000000 --- a/doc/changes/devel/12724.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a bug where the ``ylim`` parameter would sometimes apply to the wrong channel types in :func:`mne.viz.plot_evoked_topo`, by `Marijn van Vliet`_. diff --git a/doc/changes/devel/12725.newfeature.rst b/doc/changes/devel/12725.newfeature.rst deleted file mode 100644 index 3775b851a59..00000000000 --- a/doc/changes/devel/12725.newfeature.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add default ``spatial_colors="auto"`` to :func:`mne.viz.plot_evoked_white` and -:meth:`mne.Evoked.plot_white` to enable spatial colors by default, by `Eric Larson`_. diff --git a/doc/changes/devel/12727.bugfix.rst b/doc/changes/devel/12727.bugfix.rst deleted file mode 100644 index c0fb6847c87..00000000000 --- a/doc/changes/devel/12727.bugfix.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix bug where ad-hoc regularization of a covariance with -:func:`mne.cov.regularize` did not properly account for bad channels -in rank calculations, by `Eric Larson`_. diff --git a/doc/changes/devel/12727.newfeature.rst b/doc/changes/devel/12727.newfeature.rst deleted file mode 100644 index 0d1e9529389..00000000000 --- a/doc/changes/devel/12727.newfeature.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`mne.minimum_norm.make_inverse_operator` and related functions now more robustly -warn if the whitener computed from the noise covariance has an incorrect rank, -by `Eric Larson`_. diff --git a/doc/changes/devel/12730.bugfix.rst b/doc/changes/devel/12730.bugfix.rst deleted file mode 100644 index b6180815110..00000000000 --- a/doc/changes/devel/12730.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug when reading NIRX files saved in a non-western encoding, by `Daniel McCloy`_. diff --git a/doc/changes/devel/12733.newfeature.rst b/doc/changes/devel/12733.newfeature.rst deleted file mode 100644 index be9faafedcf..00000000000 --- a/doc/changes/devel/12733.newfeature.rst +++ /dev/null @@ -1,3 +0,0 @@ -When indexing :class:`~mne.Epochs` (e.g. by doing ``epochs[0]``), static code analysis tools like Pylance -should now be able to infer that the returned object is an epoch, too, and provide editor support -like automated code completions, by `Richard Höchenberger`_. \ No newline at end of file diff --git a/doc/changes/devel/12734.newfeature.rst b/doc/changes/devel/12734.newfeature.rst deleted file mode 100644 index 7c78c8f1503..00000000000 --- a/doc/changes/devel/12734.newfeature.rst +++ /dev/null @@ -1,3 +0,0 @@ -When using the ``data_path()`` in any dataset included in :py:mod:`mne.datasets`, -static analysis tools like Pylance will now correctly infer that a `pathlib.Path` will -be returned and provide editor support like automated code completions, by `Richard Höchenberger`_. \ No newline at end of file diff --git a/doc/changes/devel/12735.bugfix.rst b/doc/changes/devel/12735.bugfix.rst deleted file mode 100644 index ce2a565bd9a..00000000000 --- a/doc/changes/devel/12735.bugfix.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`~mne.set_log_file` and :func:`~mne.set_log_level` can now be correctly detected by -static analysis tools like Pylance, by `Richard Höchenberger`_. \ No newline at end of file diff --git a/doc/changes/devel/12742.dependency.rst b/doc/changes/devel/12742.dependency.rst deleted file mode 100644 index 98b10481751..00000000000 --- a/doc/changes/devel/12742.dependency.rst +++ /dev/null @@ -1,2 +0,0 @@ -Official support for PySide2 has been dropped in this release (though it might continue -to work), by `Eric Larson`_. diff --git a/doc/changes/devel/12747.newfeature.rst b/doc/changes/devel/12747.newfeature.rst deleted file mode 100644 index 2957117b778..00000000000 --- a/doc/changes/devel/12747.newfeature.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add support for storing Fourier coefficients in :class:`mne.time_frequency.Spectrum`, -:class:`mne.time_frequency.EpochsSpectrum`, :class:`mne.time_frequency.SpectrumArray`, -and :class:`mne.time_frequency.EpochsSpectrumArray` objects, by `Thomas Binns`_. \ No newline at end of file diff --git a/doc/changes/devel/12754.bugfix.rst b/doc/changes/devel/12754.bugfix.rst deleted file mode 100644 index 9cce20925e8..00000000000 --- a/doc/changes/devel/12754.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Safeguard loading of ``meas_date`` in :func:`mne.io.read_raw_edf`, by `Mathieu Scheltienne`_. diff --git a/doc/changes/devel/12759.bugfix.rst b/doc/changes/devel/12759.bugfix.rst deleted file mode 100644 index f2d59280fd0..00000000000 --- a/doc/changes/devel/12759.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Assure that blink times are handled correctly :func:`mne.preprocessing.eyetracking.interpolate_blinks`, even when the raw object is cropped by `Scott Huberty`_ and :newcontrib:`Sammi Chekroud`. diff --git a/doc/changes/devel/12760.bugfix.rst b/doc/changes/devel/12760.bugfix.rst deleted file mode 100644 index 3afe215c57e..00000000000 --- a/doc/changes/devel/12760.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug in :func:`~mne.preprocessing.maxwell_filter_prepare_emptyroom` where a difference in sampling frequencies between data and emptyroom files was ignored, by `Daniel McCloy`_. \ No newline at end of file diff --git a/doc/changes/devel/12763.bugfix.rst b/doc/changes/devel/12763.bugfix.rst deleted file mode 100644 index 405abd19313..00000000000 --- a/doc/changes/devel/12763.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix check for dropping all channels in :meth:`mne.io.Raw.drop_channels` and related methods, by :newcontrib:`Farzin Negahbani`. \ No newline at end of file diff --git a/doc/changes/devel/12771.apichange.rst b/doc/changes/devel/12771.apichange.rst deleted file mode 100644 index 49110fff558..00000000000 --- a/doc/changes/devel/12771.apichange.rst +++ /dev/null @@ -1,4 +0,0 @@ -:func:`mne.datasets.fetch_fsaverage` now returns a :class:`python:pathlib.Path` object -rather than a string. Support for string concatenation with plus (``+``) is thus -deprecated and will be removed in 1.9, use the forward-slash ``/`` operator instead, -by `Eric Larson`_. diff --git a/doc/changes/devel/12787.other.rst b/doc/changes/devel/12787.other.rst new file mode 100644 index 00000000000..1f53fdea066 --- /dev/null +++ b/doc/changes/devel/12787.other.rst @@ -0,0 +1 @@ +Use custom code in :func:`mne.sys_info` to get the amount of physical memory and a more informative CPU name instead of using the ``psutil`` package, by `Clemens Brunner`_. \ No newline at end of file diff --git a/doc/changes/devel/12792.newfeature.rst b/doc/changes/devel/12792.newfeature.rst new file mode 100644 index 00000000000..81ef79c8a11 --- /dev/null +++ b/doc/changes/devel/12792.newfeature.rst @@ -0,0 +1 @@ +Add reader for ANT Neuro files in the ``*.cnt`` format with :func:`~mne.io.read_raw_ant`, by `Mathieu Scheltienne`_, `Eric Larson`_ and `Proloy Das`_. diff --git a/doc/changes/devel/12798.dependency.rst b/doc/changes/devel/12798.dependency.rst new file mode 100644 index 00000000000..ef05dab1e8d --- /dev/null +++ b/doc/changes/devel/12798.dependency.rst @@ -0,0 +1 @@ +- Minimum supported dependencies were updated in accordance with SPEC0_, most notably Python 3.10+ is now required. diff --git a/doc/changes/devel/12801.newfeature.rst b/doc/changes/devel/12801.newfeature.rst new file mode 100644 index 00000000000..5f81e025c52 --- /dev/null +++ b/doc/changes/devel/12801.newfeature.rst @@ -0,0 +1 @@ +- Add support for a :class:`mne.transforms.Transform` in the argument ``trans`` of the coregistration GUI called with :func:`mne.gui.coregistration`, by `Mathieu Scheltienne`_. diff --git a/doc/changes/devel/12803.bugfix.rst b/doc/changes/devel/12803.bugfix.rst new file mode 100644 index 00000000000..c10bddd517b --- /dev/null +++ b/doc/changes/devel/12803.bugfix.rst @@ -0,0 +1 @@ +Fix handling of MRI file-path in :class:`mne.SourceSpaces` and safeguard saving of :class:`pathlib.Path` with ``h5io`` by casting to :class:`str`, by `Mathieu Scheltienne`_. diff --git a/doc/changes/devel/12804.bugfix.rst b/doc/changes/devel/12804.bugfix.rst new file mode 100644 index 00000000000..87a988a4525 --- /dev/null +++ b/doc/changes/devel/12804.bugfix.rst @@ -0,0 +1 @@ +Cast ``fwd["info"]`` to :class:`~mne.Info` and ``fwd["src"]`` to :class:`~mne.SourceSpaces` when loading a forward solution from an HDF5 file, by `Mathieu Scheltienne`_. diff --git a/doc/changes/devel/12805.newfeature.rst b/doc/changes/devel/12805.newfeature.rst new file mode 100644 index 00000000000..2c77d55d3ba --- /dev/null +++ b/doc/changes/devel/12805.newfeature.rst @@ -0,0 +1 @@ +Added support for ``sensor_scales`` to :meth:`mne.viz.Brain.add_sensors` and :func:`mne.viz.plot_alignment`, by :newcontrib:`Alex Lepauvre`. \ No newline at end of file diff --git a/doc/changes/devel/12811.newfeature.rst b/doc/changes/devel/12811.newfeature.rst new file mode 100644 index 00000000000..def54b1a68b --- /dev/null +++ b/doc/changes/devel/12811.newfeature.rst @@ -0,0 +1 @@ +:meth:`~mne.io.Raw` and :meth:`~mne.Epochs.save` now return the path to the saved file(s), by `Victor Ferat`_. diff --git a/doc/changes/devel/12827.other.rst b/doc/changes/devel/12827.other.rst new file mode 100644 index 00000000000..3ccbaa0bff6 --- /dev/null +++ b/doc/changes/devel/12827.other.rst @@ -0,0 +1 @@ +Improve documentation clarity of ``fit_transform`` methods for :class:`mne.decoding.SSD`, :class:`mne.decoding.CSP`, and :class:`mne.decoding.SPoC` classes, by `Thomas Binns`_. \ No newline at end of file diff --git a/doc/changes/devel/12829.apichange.rst b/doc/changes/devel/12829.apichange.rst new file mode 100644 index 00000000000..d0bd4c12a46 --- /dev/null +++ b/doc/changes/devel/12829.apichange.rst @@ -0,0 +1 @@ +Deprecate ``average`` parameter in ``plot_filters`` and ``plot_patterns`` methods of the :class:`mne.decoding.CSP` and :class:`mne.decoding.SPoC` classes, by `Thomas Binns`_. \ No newline at end of file diff --git a/doc/changes/devel/12830.newfeature.rst b/doc/changes/devel/12830.newfeature.rst new file mode 100644 index 00000000000..4d51229392d --- /dev/null +++ b/doc/changes/devel/12830.newfeature.rst @@ -0,0 +1 @@ +:func:`mne.channels.read_custom_montage` may now read a newer version of the ``.elc`` ASA Electrode file format, by `Stefan Appelhoff`_. diff --git a/doc/changes/devel/12834.dependency.rst b/doc/changes/devel/12834.dependency.rst new file mode 100644 index 00000000000..ca19423df87 --- /dev/null +++ b/doc/changes/devel/12834.dependency.rst @@ -0,0 +1,2 @@ +Importing from ``mne.decoding`` now explicitly requires ``scikit-learn`` to be installed, +by `Eric Larson`_. diff --git a/doc/changes/devel/12842.bugfix.rst b/doc/changes/devel/12842.bugfix.rst new file mode 100644 index 00000000000..75f83683b8f --- /dev/null +++ b/doc/changes/devel/12842.bugfix.rst @@ -0,0 +1 @@ +Fix bug where :meth:`mne.Epochs.compute_tfr` could not be used with the multitaper method and complex or phase outputs, by `Thomas Binns`_. \ No newline at end of file diff --git a/doc/changes/devel/12846.bugfix.rst b/doc/changes/devel/12846.bugfix.rst new file mode 100644 index 00000000000..2b40e77490e --- /dev/null +++ b/doc/changes/devel/12846.bugfix.rst @@ -0,0 +1 @@ +Enforce SI units for Eyetracking data (eyegaze data should be radians of visual angle, not pixels. Pupil size data should be meters). Updated tutorials so demonstrate how to convert data to SI units before analyses (:gh:`12846`` by `Scott Huberty`_) \ No newline at end of file diff --git a/doc/changes/devel/12853.bugfix.rst b/doc/changes/devel/12853.bugfix.rst new file mode 100644 index 00000000000..18c8afbb8ea --- /dev/null +++ b/doc/changes/devel/12853.bugfix.rst @@ -0,0 +1 @@ +Prevent the ``colorbar`` parameter being ignored in topomap plots such as :meth:`mne.time_frequency.Spectrum.plot_topomap`, by `Thomas Binns`_. \ No newline at end of file diff --git a/doc/changes/names.inc b/doc/changes/names.inc index d8e33e02d3d..8dba79bcccf 100644 --- a/doc/changes/names.inc +++ b/doc/changes/names.inc @@ -10,6 +10,7 @@ .. _Alex Ciok: https://github.com/alexCiok .. _Alex Gramfort: https://alexandre.gramfort.net .. _Alex Kiefer: https://home.alexk101.dev +.. _Alex Lepauvre: https://github.com/AlexLepauvre .. _Alex Rockhill: https://github.com/alexrockhill/ .. _Alexander Rudiuk: https://github.com/ARudiuk .. _Alexandre Barachant: https://alexandre.barachant.org @@ -79,6 +80,7 @@ .. _Erkka Heinila: https://github.com/Teekuningas .. _Etienne de Montalivet: https://github.com/etiennedemontalivet .. _Evan Hathaway: https://github.com/ephathaway +.. _Evgenii Kalenkovich: https://github.com/kalenkovich .. _Evgeny Goldstein: https://github.com/evgenygoldstein .. _Ezequiel Mikulan: https://github.com/ezemikulan .. _Ezequiel Mikulan: https://github.com/ezemikulan @@ -125,7 +127,7 @@ .. _Jan Zerfowski: https://github.com/jzerfowski .. _Jasper van den Bosch: https://github.com/ilogue .. _Jean-Baptiste Schiratti: https://github.com/jbschiratti -.. _Jean-Remi King: https://github.com/kingjr +.. _Jean-Rémi King: https://github.com/kingjr .. _Jeff Stout: https://megcore.nih.gov/index.php/Staff .. _Jennifer Behnke: https://github.com/JKBehnke .. _Jeroen Van Der Donckt: https://github.com/jvdd @@ -150,7 +152,6 @@ .. _Jukka Nenonen: https://www.linkedin.com/pub/jukka-nenonen/28/b5a/684 .. _Jussi Nurminen: https://github.com/jjnurminen .. _Kaisu Lankinen: http://bishoplab.berkeley.edu/Kaisu.html -.. _kalenkovich: https://github.com/kalenkovich .. _Katarina Slama: https://github.com/katarinaslama .. _Keith Doelling: https://github.com/kdoelling1919 .. _Kostiantyn Maksymenko: https://github.com/makkostya diff --git a/doc/changes/v0.10.rst b/doc/changes/v0.10.rst index ac4f2e42857..d237da49930 100644 --- a/doc/changes/v0.10.rst +++ b/doc/changes/v0.10.rst @@ -24,7 +24,7 @@ Changelog - Add ICA plotters for raw and epoch components by `Jaakko Leppakangas`_ -- Add new object ``mne.decoding.TimeDecoding`` for decoding sensors' evoked response across time by `Jean-Remi King`_ +- Add new object ``mne.decoding.TimeDecoding`` for decoding sensors' evoked response across time by `Jean-Rémi King`_ - Add command ``mne freeview_bem_surfaces`` to quickly check BEM surfaces with Freeview by `Alex Gramfort`_. @@ -128,7 +128,7 @@ The committer list for this release is the following (preceded by number of comm * 97 Teon Brooks * 81 Lorenzo De Santis * 55 Yousra Bekhti -* 54 Jean-Remi King +* 54 Jean-Rémi King * 48 Romain Trachel * 45 Mainak Jas * 40 Alexandre Barachant diff --git a/doc/changes/v0.11.rst b/doc/changes/v0.11.rst index e3f9a67e3c4..218508e86fb 100644 --- a/doc/changes/v0.11.rst +++ b/doc/changes/v0.11.rst @@ -32,7 +32,7 @@ Changelog - Add support for Brainvision v2 in :func:`mne.io.read_raw_brainvision` by `Teon Brooks`_ -- Improve speed of generalization across time ``mne.decoding.GeneralizationAcrossTime`` decoding up to a factor of seven by `Jean-Remi King`_ and `Federico Raimondo`_ and `Denis Engemann`_. +- Improve speed of generalization across time ``mne.decoding.GeneralizationAcrossTime`` decoding up to a factor of seven by `Jean-Rémi King`_ and `Federico Raimondo`_ and `Denis Engemann`_. - Add the explained variance for each principal component, ``explained_var``, key to the :class:`mne.Projection` by `Teon Brooks`_ @@ -47,7 +47,7 @@ BUG - Added safeguards against ``None`` and negative values in reject and flat parameters in :class:`mne.Epochs` by `Eric Larson`_ -- Fix train and test time window-length in ``mne.decoding.GeneralizationAcrossTime`` by `Jean-Remi King`_ +- Fix train and test time window-length in ``mne.decoding.GeneralizationAcrossTime`` by `Jean-Rémi King`_ - Added lower bound in :func:`mne.stats.linear_regression` on p-values ``p_val`` (and resulting ``mlog10_p_val``) using double floating point arithmetic limits by `Eric Larson`_ @@ -83,7 +83,7 @@ The committer list for this release is the following (preceded by number of comm * 24 Clemens Brunner * 23 Christian Brodbeck * 15 Mark Wronkiewicz -* 10 Jean-Remi King +* 10 Jean-Rémi King * 5 Marijn van Vliet * 3 Fede Raimondo * 2 Alexander Rudiuk diff --git a/doc/changes/v0.12.rst b/doc/changes/v0.12.rst index b3b7aba1a39..b48b80bf2d0 100644 --- a/doc/changes/v0.12.rst +++ b/doc/changes/v0.12.rst @@ -20,9 +20,9 @@ Changelog - Add system config utility :func:`mne.sys_info` by `Eric Larson`_ -- Automatic cross-validation and scoring metrics in ``mne.decoding.GeneralizationAcrossTime``, by `Jean-Remi King`_ +- Automatic cross-validation and scoring metrics in ``mne.decoding.GeneralizationAcrossTime``, by `Jean-Rémi King`_ -- ``mne.decoding.GeneralizationAcrossTime`` accepts non-deterministic cross-validations, by `Jean-Remi King`_ +- ``mne.decoding.GeneralizationAcrossTime`` accepts non-deterministic cross-validations, by `Jean-Rémi King`_ - Add plotting RMS of gradiometer pairs in :func:`mne.viz.plot_evoked_topo` by `Jaakko Leppakangas`_ @@ -40,7 +40,7 @@ Changelog - Add :func:`mne.io.read_raw_cnt` for reading Neuroscan CNT files by `Jaakko Leppakangas`_ -- Add ``decim`` parameter to ``mne.time_frequency.cwt_morlet``, by `Jean-Remi King`_ +- Add ``decim`` parameter to ``mne.time_frequency.cwt_morlet``, by `Jean-Rémi King`_ - Add method :func:`mne.Epochs.plot_topo_image` by `Jaakko Leppakangas`_ @@ -75,7 +75,7 @@ BUG - MEG projectors are removed after Maxwell filtering by `Eric Larson`_ -- Fix ``mne.decoding.TimeDecoding`` to allow specifying ``clf`` by `Jean-Remi King`_ +- Fix ``mne.decoding.TimeDecoding`` to allow specifying ``clf`` by `Jean-Rémi King`_ - Fix bug with units (uV) in 'Brain Vision Data Exchange Header File Version 1.0' by `Federico Raimondo`_ @@ -83,7 +83,7 @@ BUG - Fix bug in rank calculation of ``mne.utils.estimate_rank``, ``mne.io.Raw.estimate_rank``, and covariance functions where the tolerance was set to slightly too small a value, new 'auto' mode uses values from ``scipy.linalg.orth`` by `Eric Larson`_. -- Fix bug when specifying irregular ``train_times['slices']`` in ``mne.decoding.GeneralizationAcrossTime``, by `Jean-Remi King`_ +- Fix bug when specifying irregular ``train_times['slices']`` in ``mne.decoding.GeneralizationAcrossTime``, by `Jean-Rémi King`_ - Fix colorbar range on norm data by `Jaakko Leppakangas`_ @@ -125,7 +125,7 @@ BUG - Fix bug in :func:`mne.compute_raw_covariance` where rejection by non-data channels (e.g. EOG) was not done properly by `Eric Larson`_. -- Change default scoring method of ``mne.decoding.GeneralizationAcrossTime`` and ``mne.decoding.TimeDecoding`` to estimate the scores within the cross-validation as in scikit-learn_ as opposed to across all cross-validated ``y_pred``. The method can be changed with the ``score_mode`` parameter by `Jean-Remi King`_ +- Change default scoring method of ``mne.decoding.GeneralizationAcrossTime`` and ``mne.decoding.TimeDecoding`` to estimate the scores within the cross-validation as in scikit-learn_ as opposed to across all cross-validated ``y_pred``. The method can be changed with the ``score_mode`` parameter by `Jean-Rémi King`_ - Fix bug in :func:`mne.io.Raw.save` where, in rare cases, automatically split files could end up writing an extra empty file that wouldn't be read properly by `Eric Larson`_ @@ -144,7 +144,7 @@ API - Deprecated function ``mne.time_frequency.multitaper_psd`` and replaced by ``mne.time_frequency.psd_multitaper`` by `Chris Holdgraf`_ -- The ``y_pred`` attribute in ``mne.decoding.GeneralizationAcrossTime`` and ``mne.decoding.TimeDecoding`` is now a numpy array, by `Jean-Remi King`_ +- The ``y_pred`` attribute in ``mne.decoding.GeneralizationAcrossTime`` and ``mne.decoding.TimeDecoding`` is now a numpy array, by `Jean-Rémi King`_ - The :func:`mne.bem.fit_sphere_to_headshape` function now default to ``dig_kinds='auto'`` which will use extra digitization points, falling back to extra plus eeg digitization points if there not enough extra points are available. @@ -154,7 +154,7 @@ API - To unify and extend the behavior of :func:`mne.compute_raw_covariance` relative to :func:`mne.compute_covariance`, the default parameter ``tstep=0.2`` now discards any epochs at the end of the :class:`mne.io.Raw` instance that are not the full ``tstep`` duration. This will slightly change the computation of :func:`mne.compute_raw_covariance`, but should only potentially have a big impact if the :class:`mne.io.Raw` instance is short relative to ``tstep`` and the last, too short (now discarded) epoch contained data inconsistent with the epochs that preceded it. -- The default ``picks=None`` in :func:`mne.io.Raw.filter` now picks eeg, meg, seeg, and ecog channels, by `Jean-Remi King`_ and `Eric Larson`_ +- The default ``picks=None`` in :func:`mne.io.Raw.filter` now picks eeg, meg, seeg, and ecog channels, by `Jean-Rémi King`_ and `Eric Larson`_ - EOG, ECG and EMG channels are now plotted by default (if present in data) when using :func:`mne.viz.plot_evoked` by `Marijn van Vliet`_ @@ -168,7 +168,7 @@ API - The C wrapper ``mne.do_forward_solution`` has been deprecated in favor of the native Python version :func:`mne.make_forward_solution` by `Eric Larson`_ -- The ``events`` parameter of :func:`mne.EpochsArray` is set by default to chronological time-samples and event values to 1, by `Jean-Remi King`_ +- The ``events`` parameter of :func:`mne.EpochsArray` is set by default to chronological time-samples and event values to 1, by `Jean-Rémi King`_ Authors ~~~~~~~ @@ -179,7 +179,7 @@ The committer list for this release is the following (preceded by number of comm * 347 Jaakko Leppakangas * 157 Alexandre Gramfort * 139 Jona Sassenhagen -* 67 Jean-Remi King +* 67 Jean-Rémi King * 32 Chris Holdgraf * 31 Denis A. Engemann * 30 Mainak Jas diff --git a/doc/changes/v0.13.rst b/doc/changes/v0.13.rst index aee297d9d2d..50fcde79702 100644 --- a/doc/changes/v0.13.rst +++ b/doc/changes/v0.13.rst @@ -46,15 +46,15 @@ Changelog - Add the ``--no-decimate`` option to :ref:`mne make_scalp_surfaces` to skip the high-resolution surface decimation step, by `Eric Larson`_ -- Add new class :class:`mne.decoding.EMS` to transform epochs with the event-matched spatial filters and add 'cv' parameter to :func:`mne.decoding.compute_ems`, by `Jean-Remi King`_ +- Add new class :class:`mne.decoding.EMS` to transform epochs with the event-matched spatial filters and add 'cv' parameter to :func:`mne.decoding.compute_ems`, by `Jean-Rémi King`_ -- Added :class:`mne.time_frequency.EpochsTFR` and average parameter in :func:`mne.time_frequency.tfr_morlet` and :func:`mne.time_frequency.tfr_multitaper` to compute time-frequency transforms on single trial epochs without averaging, by `Jean-Remi King`_ and `Alex Gramfort`_ +- Added :class:`mne.time_frequency.EpochsTFR` and average parameter in :func:`mne.time_frequency.tfr_morlet` and :func:`mne.time_frequency.tfr_multitaper` to compute time-frequency transforms on single trial epochs without averaging, by `Jean-Rémi King`_ and `Alex Gramfort`_ -- Added :class:`mne.decoding.TimeFrequency` to transform signals in scikit-learn pipelines, by `Jean-Remi King`_ +- Added :class:`mne.decoding.TimeFrequency` to transform signals in scikit-learn pipelines, by `Jean-Rémi King`_ -- Added :class:`mne.decoding.UnsupervisedSpatialFilter` providing interface for scikit-learn decomposition algorithms to be used with MNE data, by `Jean-Remi King`_ and `Asish Panda`_ +- Added :class:`mne.decoding.UnsupervisedSpatialFilter` providing interface for scikit-learn decomposition algorithms to be used with MNE data, by `Jean-Rémi King`_ and `Asish Panda`_ -- Added support for multiclass decoding in :class:`mne.decoding.CSP`, by `Jean-Remi King`_ and `Alexandre Barachant`_ +- Added support for multiclass decoding in :class:`mne.decoding.CSP`, by `Jean-Rémi King`_ and `Alexandre Barachant`_ - Components obtained from :class:`mne.preprocessing.ICA` are now sorted by explained variance, by `Mikołaj Magnuski`_ @@ -64,7 +64,7 @@ Changelog - Adds new function :func:`mne.viz.plot_compare_evokeds` to show multiple evoked time courses at a single location, or the mean over a ROI, or the GFP, automatically averaging and calculating a CI if multiple subjects are given, by `Jona Sassenhagen`_ -- Added ``transform_into`` parameter into :class:`mne.decoding.CSP` to retrieve the average power of each source or the time course of each source, by `Jean-Remi King`_ +- Added ``transform_into`` parameter into :class:`mne.decoding.CSP` to retrieve the average power of each source or the time course of each source, by `Jean-Rémi King`_ - Added support for reading MaxShield (IAS) evoked data (e.g., from the acquisition machine) in :func:`mne.read_evokeds` by `Eric Larson`_ @@ -72,7 +72,7 @@ Changelog - Added :attr:`mne.io.Raw.acqparser` convenience attribute for :class:`mne.AcqParserFIF` by `Eric Larson`_ -- Added example of Representational Similarity Analysis, by `Jean-Remi King`_ +- Added example of Representational Similarity Analysis, by `Jean-Rémi King`_ BUG ~~~ @@ -101,7 +101,7 @@ BUG - Fixed image scaling in :func:`mne.viz.plot_epochs_image` when plotting more than one channel by `Jaakko Leppakangas`_ -- Fixed :class:`mne.preprocessing.Xdawn` to fit shuffled epochs by `Jean-Remi King`_ +- Fixed :class:`mne.preprocessing.Xdawn` to fit shuffled epochs by `Jean-Rémi King`_ - Fixed a bug with channel order determination that could lead to an ``AssertionError`` when using :class:`mne.Covariance` matrices by `Eric Larson`_ @@ -109,7 +109,7 @@ BUG - Fixed the import of EDF files with encoding characters in :func:`mne.io.read_raw_edf` by `Guillaume Dumas`_ -- Fixed :class:`mne.Epochs` to ensure that detrend parameter is not a boolean by `Jean-Remi King`_ +- Fixed :class:`mne.Epochs` to ensure that detrend parameter is not a boolean by `Jean-Rémi King`_ - Fixed bug with ``mne.realtime.FieldTripClient.get_data_as_epoch`` when ``picks=None`` which crashed the function by `Mainak Jas`_ @@ -164,7 +164,7 @@ API - Now channels with units of 'C', 'µS', 'uS', 'ARU' and 'S' will be turned to misc by default in :func:`mne.io.read_raw_brainvision` by `Jaakko Leppakangas`_ -- Add :func:`mne.io.anonymize_info` function to anonymize measurements and add methods to :class:`mne.io.Raw`, :class:`mne.Epochs` and :class:`mne.Evoked`, by `Jean-Remi King`_ +- Add :func:`mne.io.anonymize_info` function to anonymize measurements and add methods to :class:`mne.io.Raw`, :class:`mne.Epochs` and :class:`mne.Evoked`, by `Jean-Rémi King`_ - Now it is possible to plot only a subselection of channels in :func:`mne.viz.plot_raw` by using an array for order parameter by `Jaakko Leppakangas`_ @@ -194,9 +194,9 @@ API - ``mne.decoding.EpochsVectorizer`` has been deprecated in favor of :class:`mne.decoding.Vectorizer` by `Asish Panda`_ -- The ``epochs_data`` parameter has been deprecated in :class:`mne.decoding.CSP`, in favour of the ``X`` parameter to comply to scikit-learn API, by `Jean-Remi King`_ +- The ``epochs_data`` parameter has been deprecated in :class:`mne.decoding.CSP`, in favour of the ``X`` parameter to comply to scikit-learn API, by `Jean-Rémi King`_ -- Deprecated ``mne.time_frequency.cwt_morlet`` and ``mne.time_frequency.single_trial_power`` in favour of :func:`mne.time_frequency.tfr_morlet` with parameter average=False, by `Jean-Remi King`_ and `Alex Gramfort`_ +- Deprecated ``mne.time_frequency.cwt_morlet`` and ``mne.time_frequency.single_trial_power`` in favour of :func:`mne.time_frequency.tfr_morlet` with parameter average=False, by `Jean-Rémi King`_ and `Alex Gramfort`_ - Add argument ``mask_type`` to :func:`mne.read_events` and :func:`mne.find_events` to support MNE-C style of trigger masking by `Teon Brooks`_ and `Eric Larson`_ @@ -232,7 +232,7 @@ The committer list for this release is the following (sorted by alphabetical ord * Guillaume Dumas * Jaakko Leppakangas * Jair Montoya -* Jean-Remi King +* Jean-Rémi King * Johannes Niediek * Jona Sassenhagen * Jussi Nurminen diff --git a/doc/changes/v0.14.rst b/doc/changes/v0.14.rst index 7db46d27617..bfb9498a0c1 100644 --- a/doc/changes/v0.14.rst +++ b/doc/changes/v0.14.rst @@ -60,7 +60,7 @@ Changelog - Add ``yscale`` keyword argument to :meth:`mne.time_frequency.AverageTFR.plot` that allows specifying whether to present the frequency axis in linear (``'linear'``) or log (``'log'``) scale. The default value is ``'auto'`` which detects whether frequencies are log-spaced and sets yscale to log. Added by `Mikołaj Magnuski`_ -- Add :ref:`Representational Similarity Analysis (RSA) ` example on :mod:`mne.datasets.visual_92_categories.data_path` dataset by `Jaakko Leppakangas`_, `Jean-Remi King`_ and `Alex Gramfort`_ +- Add :ref:`Representational Similarity Analysis (RSA) ` example on :mod:`mne.datasets.visual_92_categories.data_path` dataset by `Jaakko Leppakangas`_, `Jean-Rémi King`_ and `Alex Gramfort`_ - Add support for NeuroScan files with event type 3 in :func:`mne.io.read_raw_cnt` by `Marijn van Vliet`_ @@ -70,7 +70,7 @@ Changelog - Add source space plotting with :meth:`mne.SourceSpaces.plot` using ``mne.viz.plot_trans`` by `Eric Larson`_ -- Add :func:`mne.decoding.get_coef` to retrieve and inverse the coefficients of a linear model - typically a spatial filter or pattern, by `Jean-Remi King`_ +- Add :func:`mne.decoding.get_coef` to retrieve and inverse the coefficients of a linear model - typically a spatial filter or pattern, by `Jean-Rémi King`_ - Add support for reading in EGI MFF digitization coordinate files in ``mne.channels.read_dig_montage`` by `Matt Boggess`_ @@ -113,7 +113,7 @@ BUG - Fix bug with finding layouts in :func:`mne.viz.plot_projs_topomap` by `Eric Larson`_ -- Fix bug :func:`mne.io.anonymize_info` when Info does not contain 'file_id' or 'meas_id' fields by `Jean-Remi King`_ +- Fix bug :func:`mne.io.anonymize_info` when Info does not contain 'file_id' or 'meas_id' fields by `Jean-Rémi King`_ - Fix colormap selection in :func:`mne.viz.plot_evoked_topomap` when using positive vmin with negative data by `Jaakko Leppakangas`_ @@ -141,9 +141,9 @@ BUG - Fix bug in :func:`mne.preprocessing.fix_stim_artifact` where non-data channels were interpolated by `Eric Larson`_ -- :class:`mne.decoding.Scaler` now scales each channel independently using data from all time points (epochs and times) instead of scaling all channels for each time point. It also now accepts parameter ``scalings`` to determine the data scaling method (default is ``None`` to use static channel-type-based scaling), by `Asish Panda`_, `Jean-Remi King`_, and `Eric Larson`_ +- :class:`mne.decoding.Scaler` now scales each channel independently using data from all time points (epochs and times) instead of scaling all channels for each time point. It also now accepts parameter ``scalings`` to determine the data scaling method (default is ``None`` to use static channel-type-based scaling), by `Asish Panda`_, `Jean-Rémi King`_, and `Eric Larson`_ -- Raise error if the cv parameter of ``mne.decoding.GeneralizationAcrossTime`` and ``mne.decoding.TimeDecoding`` is not a partition and the predict_mode is "cross-validation" by `Jean-Remi King`_ +- Raise error if the cv parameter of ``mne.decoding.GeneralizationAcrossTime`` and ``mne.decoding.TimeDecoding`` is not a partition and the predict_mode is "cross-validation" by `Jean-Rémi King`_ - Fix bug in :func:`mne.io.read_raw_edf` when ``preload=False`` and channels have different sampling rates by `Jaakko Leppakangas`_ @@ -196,7 +196,7 @@ API - An ``overwrite=False`` default parameter has been added to :func:`write_source_spaces` to protect against accidental overwrites, by `Eric Larson`_ -- The :class:`mne.decoding.LinearModel` class will no longer support ``plot_filters`` and ``plot_patterns``, use :class:`mne.EvokedArray` with :func:`mne.decoding.get_coef` instead, by `Jean-Remi King`_ +- The :class:`mne.decoding.LinearModel` class will no longer support ``plot_filters`` and ``plot_patterns``, use :class:`mne.EvokedArray` with :func:`mne.decoding.get_coef` instead, by `Jean-Rémi King`_ - Made functions :func:`mne.time_frequency.tfr_array_multitaper`, :func:`mne.time_frequency.tfr_array_morlet`, :func:`mne.time_frequency.tfr_array_stockwell`, :func:`mne.time_frequency.psd_array_multitaper` and :func:`mne.time_frequency.psd_array_welch` public to allow computing TFRs and PSDs on numpy arrays by `Jaakko Leppakangas`_ @@ -227,7 +227,7 @@ People who contributed to this release (in alphabetical order): * Hermann Sonntag * Jaakko Leppakangas * Jakub Kaczmarzyk -* Jean-Remi King +* Jean-Rémi King * Jon Houck * Jona Sassenhagen * Jussi Nurminen diff --git a/doc/changes/v0.15.rst b/doc/changes/v0.15.rst index e2de7301973..94470ba5316 100644 --- a/doc/changes/v0.15.rst +++ b/doc/changes/v0.15.rst @@ -10,7 +10,7 @@ Changelog - Add .bvef extension (BrainVision Electrodes File) to ``mne.channels.read_montage`` by `Jean-Baptiste Schiratti`_ -- Add :func:`mne.decoding.cross_val_multiscore` to allow scoring of multiple tasks, typically used with :class:`mne.decoding.SlidingEstimator`, by `Jean-Remi King`_ +- Add :func:`mne.decoding.cross_val_multiscore` to allow scoring of multiple tasks, typically used with :class:`mne.decoding.SlidingEstimator`, by `Jean-Rémi King`_ - Add :class:`mne.decoding.ReceptiveField` module for modeling electrode response to input features by `Chris Holdgraf`_ @@ -20,7 +20,7 @@ Changelog - Add example of time-frequency decoding with CSP by `Laura Gwilliams`_ -- Add :class:`mne.decoding.SPoC` to fit and apply spatial filters based on continuous target variables, by `Jean-Remi King`_ and `Alexandre Barachant`_ +- Add :class:`mne.decoding.SPoC` to fit and apply spatial filters based on continuous target variables, by `Jean-Rémi King`_ and `Alexandre Barachant`_ - Add Fieldtrip's electromyogram dataset, by `Alexandre Barachant`_ @@ -74,7 +74,7 @@ Changelog - Add function :func:`mne.channels.get_builtin_montages` to list all built-in montages by `Clemens Brunner`_ -- :class:`mne.decoding.SlidingEstimator` and :class:`mne.decoding.GeneralizingEstimator` now accept ``**fit_params`` at fitting by `Jean-Remi King`_ +- :class:`mne.decoding.SlidingEstimator` and :class:`mne.decoding.GeneralizingEstimator` now accept ``**fit_params`` at fitting by `Jean-Rémi King`_ - Add :class:`mne.VectorSourceEstimate` class which enables working with both source power and dipole orientations by `Marijn van Vliet`_ @@ -220,13 +220,13 @@ API - Make the goodness of fit (GOF) of the dipoles returned by :func:`mne.beamformer.rap_music` consistent with the GOF of dipoles returned by :func:`mne.fit_dipole` by `Alex Gramfort`_. -- :class:`mne.decoding.SlidingEstimator` will now replace ``mne.decoding.TimeDecoding`` to make it generic and fully compatible with scikit-learn, by `Jean-Remi King`_ and `Alex Gramfort`_ +- :class:`mne.decoding.SlidingEstimator` will now replace ``mne.decoding.TimeDecoding`` to make it generic and fully compatible with scikit-learn, by `Jean-Rémi King`_ and `Alex Gramfort`_ -- :class:`mne.decoding.GeneralizingEstimator` will now replace ``mne.decoding.GeneralizationAcrossTime`` to make it generic and fully compatible with scikit-learn, by `Jean-Remi King`_ and `Alex Gramfort`_ +- :class:`mne.decoding.GeneralizingEstimator` will now replace ``mne.decoding.GeneralizationAcrossTime`` to make it generic and fully compatible with scikit-learn, by `Jean-Rémi King`_ and `Alex Gramfort`_ -- ``mne.viz.decoding.plot_gat_times``, ``mne.viz.decoding.plot_gat_matrix`` are now deprecated. Use matplotlib instead as shown in the examples, by `Jean-Remi King`_ and `Alex Gramfort`_ +- ``mne.viz.decoding.plot_gat_times``, ``mne.viz.decoding.plot_gat_matrix`` are now deprecated. Use matplotlib instead as shown in the examples, by `Jean-Rémi King`_ and `Alex Gramfort`_ -- Add ``norm_trace`` parameter to control single-epoch covariance normalization in :class:`mne.decoding.CSP`, by `Jean-Remi King`_ +- Add ``norm_trace`` parameter to control single-epoch covariance normalization in :class:`mne.decoding.CSP`, by `Jean-Rémi King`_ - Allow passing a list of channel names as ``show_names`` in function :func:`mne.viz.plot_sensors` and methods :meth:`mne.Evoked.plot_sensors`, :meth:`mne.Epochs.plot_sensors` and :meth:`mne.io.Raw.plot_sensors` to show only a subset of channel names by `Jaakko Leppakangas`_ @@ -302,7 +302,7 @@ People who contributed to this release (in alphabetical order): * Fede Raimondo * Jaakko Leppakangas * Jean-Baptiste Schiratti -* Jean-Remi King +* Jean-Rémi King * Jesper Duemose Nielsen * Joan Massich * Jon Houck diff --git a/doc/changes/v0.16.rst b/doc/changes/v0.16.rst index 4726b6d3efc..cdf6dbf0495 100644 --- a/doc/changes/v0.16.rst +++ b/doc/changes/v0.16.rst @@ -111,7 +111,7 @@ Bug - Fix bug with events when saving split files using :meth:`mne.Epochs.save` by `Eric Larson`_ -- Fix bug in :class:`mne.decoding.SlidingEstimator` and :class:`mne.decoding.GeneralizingEstimator` to allow :func:`mne.decoding.cross_val_multiscore` to automatically detect whether the ``base_estimator`` is a classifier and use a ``StratifiedKFold`` instead of a ``KFold`` when ``cv`` is not specified, by `Jean-Remi King`_ +- Fix bug in :class:`mne.decoding.SlidingEstimator` and :class:`mne.decoding.GeneralizingEstimator` to allow :func:`mne.decoding.cross_val_multiscore` to automatically detect whether the ``base_estimator`` is a classifier and use a ``StratifiedKFold`` instead of a ``KFold`` when ``cv`` is not specified, by `Jean-Rémi King`_ - Fix bug in :func:`mne.set_eeg_reference` to remove an average reference projector when setting the reference to ``[]`` (i.e. do not change the existing reference) by `Clemens Brunner`_ @@ -232,7 +232,7 @@ People who contributed to this release (in alphabetical order): * Erik Hornberger * Fede Raimondo * Henrich Kolkhorst -* Jean-Remi King +* Jean-Rémi King * Jen Evans * Joan Massich * Jon Houck diff --git a/doc/changes/v0.18.rst b/doc/changes/v0.18.rst index 4e73e42239b..aa9c4b37826 100644 --- a/doc/changes/v0.18.rst +++ b/doc/changes/v0.18.rst @@ -151,7 +151,7 @@ Bug - Fix filtering functions (e.g., :meth:`mne.io.Raw.filter`) to properly take into account the two elements in ``n_pad`` parameter by `Bruno Nicenboim`_ -- Fix ``feature_names`` parameter change after fitting in :class:`mne.decoding.ReceptiveField` by `Jean-Remi King`_ +- Fix ``feature_names`` parameter change after fitting in :class:`mne.decoding.ReceptiveField` by `Jean-Rémi King`_ - Fix index error in :func:`mne.io.read_raw_cnt` when creating stim_channel manually by `Joan Massich`_ @@ -161,7 +161,7 @@ Bug - Fix :func:`mne.events_from_annotations` to ignore ``'BAD_'`` and ``'EDGE_'`` annotations by default using a new default ``regexp`` by `Eric Larson`_ -- Fix bug in ``mne.preprocessing.mark_flat`` where ``raw.first_samp`` was not taken into account by `kalenkovich`_ +- Fix bug in ``mne.preprocessing.mark_flat`` where ``raw.first_samp`` was not taken into account by `Evgenii Kalenkovich`_ - Fix date parsing in :func:`mne.io.read_raw_cnt` by `Joan Massich`_ diff --git a/doc/changes/v0.20.rst b/doc/changes/v0.20.rst index 7e6fa7d63c9..eb191834ea2 100644 --- a/doc/changes/v0.20.rst +++ b/doc/changes/v0.20.rst @@ -226,7 +226,7 @@ Bug - Fix bug in ``mne.preprocessing.mark_flat`` where acquisition skips were not handled properly, by `Eric Larson`_ -- Fix bug in :func:`mne.viz.plot_bem` where some sources were not plotted by `Jean-Remi King`_ and `Eric Larson`_ +- Fix bug in :func:`mne.viz.plot_bem` where some sources were not plotted by `Jean-Rémi King`_ and `Eric Larson`_ - Fix TAL channel parsing (annotations) for EDF-D files by `Clemens Brunner`_ diff --git a/doc/changes/v0.21.rst b/doc/changes/v0.21.rst index 1d55c714f96..2f2fa201a3c 100644 --- a/doc/changes/v0.21.rst +++ b/doc/changes/v0.21.rst @@ -29,7 +29,7 @@ Enhancements - Add function :func:`mne.channels.combine_channels` to combine channels from Raw, Epochs, or Evoked according to ROIs (combinations including mean, median, or standard deviation; can also use a callable) **by new contributor** |Johann Benerradi|_ -- Improved documentation building instructions and execution on Windows **by new contributor** |Martin Schulz|_, `kalenkovich`_, and `Eric Larson`_ +- Improved documentation building instructions and execution on Windows **by new contributor** |Martin Schulz|_, `Evgenii Kalenkovich`_, and `Eric Larson`_ - Speed up reading of annotations in EDF+ files **by new contributor** |Jeroen Van Der Donckt|_ diff --git a/doc/changes/v0.22.rst b/doc/changes/v0.22.rst index 1f4045ed780..52d7cec71e5 100644 --- a/doc/changes/v0.22.rst +++ b/doc/changes/v0.22.rst @@ -72,7 +72,7 @@ Enhancements - Add progress bar support to :func:`mne.time_frequency.csd_morlet` (:gh:`8608` by `Eric Larson`_) -- Further improved documentation building instructions and execution on Windows (:gh:`8502` by `kalenkovich`_ and `Eric Larson`_) +- Further improved documentation building instructions and execution on Windows (:gh:`8502` by `Evgenii Kalenkovich`_ and `Eric Larson`_) - Add option to disable TQDM entirely with ``MNE_TQDM='off'`` (:gh:`8515` by `Eric Larson`_) @@ -242,7 +242,7 @@ People who contributed to this release in alphabetical order * Fede Raimondo * Guillaume Favelier * Hongjiang Ye + -* Jean-Remi King +* Jean-Rémi King * Jeff Stout + * Jonathan Kuziek + * Jussi Nurminen diff --git a/doc/changes/v0.23.rst b/doc/changes/v0.23.rst index 0fa34b0dc2d..a005feab4ec 100644 --- a/doc/changes/v0.23.rst +++ b/doc/changes/v0.23.rst @@ -73,7 +73,7 @@ Enhancements - Update citations in maxwell.py (:gh:`9043` **by new contributor** |Valerii Chirkov|_) -- New Tutorial for analyzing frequency-tagging data (:gh:`8867` **by new contributor** |Dominik Welke|_ and `kalenkovich`_) +- New Tutorial for analyzing frequency-tagging data (:gh:`8867` **by new contributor** |Dominik Welke|_ and `Evgenii Kalenkovich`_) - Add dbs as new channel type for deep brain stimulation (DBS) recordings (:gh:`8739` **by new contributor** |Richard Koehler|_) @@ -302,7 +302,7 @@ Bugs - Fix bug with ``picks`` attribute for `~mne.Epochs` after calling :meth:`mne.Epochs.add_channels` (:gh:`9246` by `Alex Gramfort`_) -- Fix bug where ``backend='notebook'`` could not be used in :meth:`mne.SourceEstimate.plot` (:gh:`9305` by `Jean-Remi King`_) +- Fix bug where ``backend='notebook'`` could not be used in :meth:`mne.SourceEstimate.plot` (:gh:`9305` by `Jean-Rémi King`_) - `mne.preprocessing.compute_proj_eog` and `mne.preprocessing.compute_proj_ecg` now return empty lists if no EOG or ECG events, respectively, could be found. Previously, we'd return ``None`` in these situations, which does not match the documented behavior of returning a list of projectors (:gh:`9277` by `Richard Höchenberger`_) @@ -356,7 +356,7 @@ People who contributed to this release in alphabetical order * Giorgio Marinato * Guillaume Favelier * Jack Zhang+ -* Jean-Remi King +* Jean-Rémi King * Johann Benerradi * Joris Van den Bossche * Judy D Zhu+ diff --git a/doc/changes/v0.24.rst b/doc/changes/v0.24.rst index 5f92e3dbdf6..f36191d8af1 100644 --- a/doc/changes/v0.24.rst +++ b/doc/changes/v0.24.rst @@ -63,7 +63,7 @@ Enhancements - Show all good channel types and counts when printing a :class:`mne.Info` in the notebook (:gh:`9725` by `Valerii Chirkov`_ and `Eric Larson`_) -- Speed up point decimation in :func:`mne.io.read_raw_kit` by vectorization and use of :class:`scipy.spatial.cKDTree` (:gh:`9568` by `Jean-Remi King`_ and `Eric Larson`_) +- Speed up point decimation in :func:`mne.io.read_raw_kit` by vectorization and use of :class:`scipy.spatial.cKDTree` (:gh:`9568` by `Jean-Rémi King`_ and `Eric Larson`_) - Add ability to export EDF+ files using :func:`mne.export.export_raw` (:gh:`9643` by `Adam Li`_) @@ -383,7 +383,7 @@ People who contributed to this release in alphabetical order * Guillaume Favelier * Hubert Banville * Jan Sosulski+ -* Jean-Remi King +* Jean-Rémi King * Jeff Stout * Johann Benerradi * John Samuelsson+ diff --git a/doc/changes/v0.8.rst b/doc/changes/v0.8.rst index c1de1638fdf..324bb016123 100644 --- a/doc/changes/v0.8.rst +++ b/doc/changes/v0.8.rst @@ -72,7 +72,7 @@ Changelog - Add ``raw.add_events`` to allow adding events to a raw file by `Eric Larson`_ -- Add ``plot_image`` method to Evoked object to display data as images by `Jean-Remi King`_ and `Alex Gramfort`_ and `Denis Engemann`_ +- Add ``plot_image`` method to Evoked object to display data as images by `Jean-Rémi King`_ and `Alex Gramfort`_ and `Denis Engemann`_ - Add BCI demo with CSP on motor imagery by `Martin Billinger`_ @@ -190,5 +190,5 @@ The committer list for this release is the following (preceded by number of comm * 2 Daniel Strohmeier * 2 Federico Raimondo * 2 Alan Leggitt -* 1 Jean-Remi King +* 1 Jean-Rémi King * 1 Matti Hämäläinen diff --git a/doc/changes/v0.9.rst b/doc/changes/v0.9.rst index 0d8cc565472..5ab19f3a07f 100644 --- a/doc/changes/v0.9.rst +++ b/doc/changes/v0.9.rst @@ -62,7 +62,7 @@ Changelog - Labels support subtraction (``label_1 - label_2``) by `Christian Brodbeck`_ -- Add GeneralizationAcrossTime object with support for cross-condition generalization by `Jean-Remi King`_ and `Denis Engemann`_ +- Add GeneralizationAcrossTime object with support for cross-condition generalization by `Jean-Rémi King`_ and `Denis Engemann`_ - Add support for single dipole fitting by `Eric Larson`_ @@ -208,7 +208,7 @@ The committer list for this release is the following (preceded by number of comm * 304 Alexandre Gramfort * 300 Teon Brooks * 142 Mainak Jas -* 119 Jean-Remi King +* 119 Jean-Rémi King * 77 Alan Leggitt * 75 Marijn van Vliet * 63 Chris Holdgraf diff --git a/doc/changes/v1.1.rst b/doc/changes/v1.1.rst index de0f597c0ee..03b03dc3f18 100644 --- a/doc/changes/v1.1.rst +++ b/doc/changes/v1.1.rst @@ -129,7 +129,7 @@ Bugs - Fix bug in :func:`mne.io.read_raw_ctf` on Windows where large files could not be read (:gh:`10866` by `Eric Larson`_) -- Fix bug in :func:`mne.io.read_raw_ctf` where invalid measurement dates were not handled properly (:gh:`10957` by `Jean-Remi King`_ and `Eric Larson`_) +- Fix bug in :func:`mne.io.read_raw_ctf` where invalid measurement dates were not handled properly (:gh:`10957` by `Jean-Rémi King`_ and `Eric Larson`_) - Rendering issues with recent MESA releases can be avoided by setting the new environment variable ``MNE_3D_OPTION_MULTI_SAMPLES=1`` or using :func:`mne.viz.set_3d_options` (:gh:`10513` by `Eric Larson`_) @@ -242,7 +242,7 @@ Authors * Guillaume Favelier * Hamid Maymandi+ * Ilias Machairas+ -* Jean-Remi King +* Jean-Rémi King * Johann Benerradi * Jon Houck * Jona Sassenhagen diff --git a/doc/changes/v1.7.rst b/doc/changes/v1.7.rst index 9176e855e13..dfd3129a18d 100644 --- a/doc/changes/v1.7.rst +++ b/doc/changes/v1.7.rst @@ -6,8 +6,8 @@ Version 1.7.1 (2024-06-14) Bugfixes -------- -- Fix bug where :func:`mne.time_frequency.csd_multitaper`, :func:`mne.time_frequency.csd_fourier`, :func:`mne.time_frequency.csd_array_multitaper`, and :func:`mne.time_frequency.csd_array_fourier` would return cross-spectral densities with the ``fmin`` and ``fmax`` frequencies missing, by `Thomas Binns`_ (`#12633 `__) -- Fix incorrect RuntimeWarning (different channel filter settings) in EDF/BDF import, by `Clemens Brunner`_. (`#12661 `__) +- Fix bug where :func:`mne.time_frequency.csd_multitaper`, :func:`mne.time_frequency.csd_fourier`, :func:`mne.time_frequency.csd_array_multitaper`, and :func:`mne.time_frequency.csd_array_fourier` would return cross-spectral densities with the ``fmin`` and ``fmax`` frequencies missing, by `Thomas Binns`_ (`#12633 `__) +- Fix incorrect RuntimeWarning (different channel filter settings) in EDF/BDF import, by `Clemens Brunner`_. (`#12661 `__) Authors ------- @@ -33,126 +33,126 @@ Notable changes evaluation in the future. You don't need to do anything to benefit from these changes – your editor will pick them up automatically and provide the - enhanced experience if it supports it! (`#12250 `__) + enhanced experience if it supports it! (`#12250 `__) Dependencies ------------ -- ``defusedxml`` is now an optional (rather than required) dependency and needed when reading EGI-MFF data, NEDF data, and BrainVision montages, by `Eric Larson`_. (`#12264 `__) -- For developers, ``pytest>=8.0`` is now required for running unit tests, by `Eric Larson`_. (`#12376 `__) -- ``pytest-harvest`` is no longer used as a test dependency, by `Eric Larson`_. (`#12451 `__) -- The minimum supported version of Qt bindings is 5.15, by `Eric Larson`_. (`#12491 `__) +- ``defusedxml`` is now an optional (rather than required) dependency and needed when reading EGI-MFF data, NEDF data, and BrainVision montages, by `Eric Larson`_. (`#12264 `__) +- For developers, ``pytest>=8.0`` is now required for running unit tests, by `Eric Larson`_. (`#12376 `__) +- ``pytest-harvest`` is no longer used as a test dependency, by `Eric Larson`_. (`#12451 `__) +- The minimum supported version of Qt bindings is 5.15, by `Eric Larson`_. (`#12491 `__) Bugfixes -------- -- Fix bug where section parameter in :meth:`mne.Report.add_html` was not being utilized resulting in improper formatting, by :newcontrib:`Martin Oberg`. (`#12319 `__) -- Fix bug in :func:`mne.preprocessing.maxwell_filter` where calibration was incorrectly applied during virtual sensor reconstruction, by `Eric Larson`_ and :newcontrib:`Motofumi Fushimi`. (`#12348 `__) -- Reformats channel and detector lookup in :func:`mne.io.read_raw_snirf` from array based to dictionary based. Removes incorrect assertions that every detector and source must have data associated with every registered optode position, by :newcontrib:`Alex Kiefer`. (`#12430 `__) -- Remove FDT file format check for strings in EEGLAB's EEG.data in :func:`mne.io.read_raw_eeglab` and related functions by :newcontrib:`Seyed Yahya Shirazi` (`#12523 `__) -- Fixes to interactivity in time-frequency objects: the rectangle selector now works on TFR image plots of gradiometer data; and in ``TFR.plot_joint()`` plots, the colormap limits of interactively-generated topomaps match the colormap limits of the main plot. By `Daniel McCloy`_. (`#11282 `__) -- Allow :func:`mne.viz.plot_compare_evokeds` to plot eyetracking channels, and improve error handling, y `Scott Huberty`_. (`#12190 `__) -- Fix bug in :meth:`mne.Epochs.apply_function` where data was handed down incorrectly in parallel processing, by `Dominik Welke`_. (`#12206 `__) -- Remove incorrect type hints in :func:`mne.io.read_raw_neuralynx`, by `Richard Höchenberger`_. (`#12236 `__) -- Fix bug with accessing the last data sample using ``raw[:, -1]`` where an empty array was returned, by `Eric Larson`_. (`#12248 `__) -- Correctly handle temporal gaps in Neuralynx .ncs files via :func:`mne.io.read_raw_neuralynx`, by `Kristijan Armeni`_ and `Eric Larson`_. (`#12279 `__) -- Fix bug where parent directory existence was not checked properly in :meth:`mne.io.Raw.save`, by `Eric Larson`_. (`#12282 `__) -- Add ``tol`` parameter to :meth:`mne.events_from_annotations` so that the user can specify the tolerance to ignore rounding errors of event onsets when using ``chunk_duration`` is not None (default is 1e-8), by `Michiru Kaneda`_ (`#12324 `__) -- Allow :meth:`mne.io.Raw.interpolate_bads` and :meth:`mne.Epochs.interpolate_bads` to work on ``ecog`` and ``seeg`` data; for ``seeg`` data a spline is fit to neighboring electrode contacts on the same shaft, by `Alex Rockhill`_ (`#12336 `__) -- Fix clicking on an axis of :func:`mne.viz.plot_evoked_topo` when multiple vertical lines ``vlines`` are used, by `Mathieu Scheltienne`_. (`#12345 `__) -- Fix bug in :meth:`mne.viz.EvokedField.set_vmax` that prevented setting the color limits of the MEG magnetic field density, by `Marijn van Vliet`_ (`#12354 `__) -- Fix faulty indexing in :func:`mne.io.read_raw_neuralynx` when picking a single channel, by `Kristijan Armeni`_. (`#12357 `__) -- Fix bug where :func:`mne.preprocessing.compute_proj_ecg` and :func:`mne.preprocessing.compute_proj_eog` could modify the default ``reject`` and ``flat`` arguments on multiple calls based on channel types present, by `Eric Larson`_. (`#12380 `__) -- Fix bad channels not handled properly in :func:`mne.stc_near_sensors` by `Alex Rockhill`_. (`#12382 `__) -- Fix bug where :func:`mne.preprocessing.regress_artifact` projection check was not specific to the channels being processed, by `Eric Larson`_. (`#12389 `__) -- Change how samples are read when using ``data_format='auto'`` in :func:`mne.io.read_raw_cnt`, by `Jacob Woessner`_. (`#12393 `__) -- Fix bugs with :class:`mne.Report` CSS where TOC items could disappear at the bottom of the page, by `Eric Larson`_. (`#12399 `__) -- In :func:`~mne.viz.plot_compare_evokeds`, actually plot GFP (not RMS amplitude) for EEG channels when global field power is requested by `Daniel McCloy`_. (`#12410 `__) -- Fix :ref:`tut-working-with-seeg` use of :func:`mne.stc_near_sensors` to use the :class:`mne.VolSourceEstimate` positions and not the pial surface, by `Alex Rockhill`_ (`#12436 `__) -- Fix prefiltering information management for EDF/BDF, by `Michiru Kaneda`_ (`#12441 `__) -- Fix validation of ``ch_type`` in :func:`mne.preprocessing.annotate_muscle_zscore`, by `Mathieu Scheltienne`_. (`#12444 `__) -- Fix errant redundant use of ``BIDSPath.split`` when writing split raw and epochs data, by `Eric Larson`_. (`#12451 `__) -- Disable config parser interpolation when reading BrainVision files, which allows using the percent sign as a regular character in channel units, by `Clemens Brunner`_. (`#12456 `__) -- - Fix the default color of :meth:`mne.viz.Brain.add_text` to properly contrast with the figure background color, by `Marijn van Vliet`_. (`#12470 `__) -- - Changed default ECoG and sEEG electrode sizes in brain plots to better reflect real world sizes, by `Liberty Hamilton`_ (`#12474 `__) -- Fixed bugs with handling of rank in :class:`mne.decoding.CSP`, by `Eric Larson`_. (`#12476 `__) -- - Fix reading segmented recordings with :func:`mne.io.read_raw_eyelink` by `Dominik Welke`_. (`#12481 `__) -- Improve compatibility with other Qt-based GUIs by handling theme icons better, by `Eric Larson`_. (`#12483 `__) -- - Fix problem caused by onsets with NaN values using :func:`mne.io.read_raw_eeglab` by `Jacob Woessner`_ (`#12484 `__) -- Fix cleaning of channel names for non vectorview or CTF dataset including whitespaces or dash in their channel names, by `Mathieu Scheltienne`_. (`#12489 `__) +- Fix bug where section parameter in :meth:`mne.Report.add_html` was not being utilized resulting in improper formatting, by :newcontrib:`Martin Oberg`. (`#12319 `__) +- Fix bug in :func:`mne.preprocessing.maxwell_filter` where calibration was incorrectly applied during virtual sensor reconstruction, by `Eric Larson`_ and :newcontrib:`Motofumi Fushimi`. (`#12348 `__) +- Reformats channel and detector lookup in :func:`mne.io.read_raw_snirf` from array based to dictionary based. Removes incorrect assertions that every detector and source must have data associated with every registered optode position, by :newcontrib:`Alex Kiefer`. (`#12430 `__) +- Remove FDT file format check for strings in EEGLAB's EEG.data in :func:`mne.io.read_raw_eeglab` and related functions by :newcontrib:`Seyed Yahya Shirazi` (`#12523 `__) +- Fixes to interactivity in time-frequency objects: the rectangle selector now works on TFR image plots of gradiometer data; and in ``TFR.plot_joint()`` plots, the colormap limits of interactively-generated topomaps match the colormap limits of the main plot. By `Daniel McCloy`_. (`#11282 `__) +- Allow :func:`mne.viz.plot_compare_evokeds` to plot eyetracking channels, and improve error handling, y `Scott Huberty`_. (`#12190 `__) +- Fix bug in :meth:`mne.Epochs.apply_function` where data was handed down incorrectly in parallel processing, by `Dominik Welke`_. (`#12206 `__) +- Remove incorrect type hints in :func:`mne.io.read_raw_neuralynx`, by `Richard Höchenberger`_. (`#12236 `__) +- Fix bug with accessing the last data sample using ``raw[:, -1]`` where an empty array was returned, by `Eric Larson`_. (`#12248 `__) +- Correctly handle temporal gaps in Neuralynx .ncs files via :func:`mne.io.read_raw_neuralynx`, by `Kristijan Armeni`_ and `Eric Larson`_. (`#12279 `__) +- Fix bug where parent directory existence was not checked properly in :meth:`mne.io.Raw.save`, by `Eric Larson`_. (`#12282 `__) +- Add ``tol`` parameter to :meth:`mne.events_from_annotations` so that the user can specify the tolerance to ignore rounding errors of event onsets when using ``chunk_duration`` is not None (default is 1e-8), by `Michiru Kaneda`_ (`#12324 `__) +- Allow :meth:`mne.io.Raw.interpolate_bads` and :meth:`mne.Epochs.interpolate_bads` to work on ``ecog`` and ``seeg`` data; for ``seeg`` data a spline is fit to neighboring electrode contacts on the same shaft, by `Alex Rockhill`_ (`#12336 `__) +- Fix clicking on an axis of :func:`mne.viz.plot_evoked_topo` when multiple vertical lines ``vlines`` are used, by `Mathieu Scheltienne`_. (`#12345 `__) +- Fix bug in :meth:`mne.viz.EvokedField.set_vmax` that prevented setting the color limits of the MEG magnetic field density, by `Marijn van Vliet`_ (`#12354 `__) +- Fix faulty indexing in :func:`mne.io.read_raw_neuralynx` when picking a single channel, by `Kristijan Armeni`_. (`#12357 `__) +- Fix bug where :func:`mne.preprocessing.compute_proj_ecg` and :func:`mne.preprocessing.compute_proj_eog` could modify the default ``reject`` and ``flat`` arguments on multiple calls based on channel types present, by `Eric Larson`_. (`#12380 `__) +- Fix bad channels not handled properly in :func:`mne.stc_near_sensors` by `Alex Rockhill`_. (`#12382 `__) +- Fix bug where :func:`mne.preprocessing.regress_artifact` projection check was not specific to the channels being processed, by `Eric Larson`_. (`#12389 `__) +- Change how samples are read when using ``data_format='auto'`` in :func:`mne.io.read_raw_cnt`, by `Jacob Woessner`_. (`#12393 `__) +- Fix bugs with :class:`mne.Report` CSS where TOC items could disappear at the bottom of the page, by `Eric Larson`_. (`#12399 `__) +- In :func:`~mne.viz.plot_compare_evokeds`, actually plot GFP (not RMS amplitude) for EEG channels when global field power is requested by `Daniel McCloy`_. (`#12410 `__) +- Fix :ref:`tut-working-with-seeg` use of :func:`mne.stc_near_sensors` to use the :class:`mne.VolSourceEstimate` positions and not the pial surface, by `Alex Rockhill`_ (`#12436 `__) +- Fix prefiltering information management for EDF/BDF, by `Michiru Kaneda`_ (`#12441 `__) +- Fix validation of ``ch_type`` in :func:`mne.preprocessing.annotate_muscle_zscore`, by `Mathieu Scheltienne`_. (`#12444 `__) +- Fix errant redundant use of ``BIDSPath.split`` when writing split raw and epochs data, by `Eric Larson`_. (`#12451 `__) +- Disable config parser interpolation when reading BrainVision files, which allows using the percent sign as a regular character in channel units, by `Clemens Brunner`_. (`#12456 `__) +- - Fix the default color of :meth:`mne.viz.Brain.add_text` to properly contrast with the figure background color, by `Marijn van Vliet`_. (`#12470 `__) +- - Changed default ECoG and sEEG electrode sizes in brain plots to better reflect real world sizes, by `Liberty Hamilton`_ (`#12474 `__) +- Fixed bugs with handling of rank in :class:`mne.decoding.CSP`, by `Eric Larson`_. (`#12476 `__) +- - Fix reading segmented recordings with :func:`mne.io.read_raw_eyelink` by `Dominik Welke`_. (`#12481 `__) +- Improve compatibility with other Qt-based GUIs by handling theme icons better, by `Eric Larson`_. (`#12483 `__) +- - Fix problem caused by onsets with NaN values using :func:`mne.io.read_raw_eeglab` by `Jacob Woessner`_ (`#12484 `__) +- Fix cleaning of channel names for non vectorview or CTF dataset including whitespaces or dash in their channel names, by `Mathieu Scheltienne`_. (`#12489 `__) - Fix bug with :meth:`mne.preprocessing.ICA.plot_sources` for ``evoked`` data where the - legend contained too many entries, by `Eric Larson`_. (`#12498 `__) + legend contained too many entries, by `Eric Larson`_. (`#12498 `__) - Fix bug where using ``phase="minimum"`` in filtering functions like :meth:`mne.io.Raw.filter` constructed a filter half the desired length with compromised attenuation. Now ``phase="minimum"`` has the same length and comparable suppression as ``phase="zero"``, and the old (incorrect) behavior can be achieved - with ``phase="minimum-half"``, by `Eric Larson`_. (`#12507 `__) -- Correct reading of ``info["subject_info"]["his_id"]`` in :func:`mne.io.read_raw_snirf`, by `Eric Larson`_. (`#12526 `__) -- Calling :meth:`~mne.io.Raw.compute_psd` with ``method="multitaper"`` is now expressly disallowed when ``reject_by_annotation=True`` and ``bad_*`` annotations are present (previously this was nominally allowed but resulted in ``nan`` values in the PSD). By `Daniel McCloy`_. (`#12535 `__) -- :meth:`~mne.io.Raw.compute_psd` and :func:`~mne.time_frequency.psd_array_welch` will now use FFT windows aligned to the onsets of good data spans when ``bad_*`` annotations are present. By `Daniel McCloy`_. (`#12536 `__) -- Fix bug in loading of complex/phase TFRs. By `Daniel McCloy`_. (`#12537 `__) -- Fix bug with :func:`mne.SourceSpaces.export_volume` where the ``img.affine`` was not set properly, by `Eric Larson`_. (`#12544 `__) + with ``phase="minimum-half"``, by `Eric Larson`_. (`#12507 `__) +- Correct reading of ``info["subject_info"]["his_id"]`` in :func:`mne.io.read_raw_snirf`, by `Eric Larson`_. (`#12526 `__) +- Calling :meth:`~mne.io.Raw.compute_psd` with ``method="multitaper"`` is now expressly disallowed when ``reject_by_annotation=True`` and ``bad_*`` annotations are present (previously this was nominally allowed but resulted in ``nan`` values in the PSD). By `Daniel McCloy`_. (`#12535 `__) +- :meth:`~mne.io.Raw.compute_psd` and :func:`~mne.time_frequency.psd_array_welch` will now use FFT windows aligned to the onsets of good data spans when ``bad_*`` annotations are present. By `Daniel McCloy`_. (`#12536 `__) +- Fix bug in loading of complex/phase TFRs. By `Daniel McCloy`_. (`#12537 `__) +- Fix bug with :func:`mne.SourceSpaces.export_volume` where the ``img.affine`` was not set properly, by `Eric Larson`_. (`#12544 `__) API changes by deprecation -------------------------- -- The default value of the ``zero_mean`` parameter of :func:`mne.time_frequency.tfr_array_morlet` will change from ``False`` to ``True`` in version 1.8, for consistency with related functions. By `Daniel McCloy`_. (`#11282 `__) -- The parameter for providing data to :func:`mne.time_frequency.tfr_array_morlet` and :func:`mne.time_frequency.tfr_array_multitaper` has been switched from ``epoch_data`` to ``data``. Only use the ``data`` parameter to avoid a warning. Changes by `Thomas Binns`_. (`#12308 `__) -- Change :func:`mne.stc_near_sensors` ``surface`` default from the ``'pial'`` surface to the surface in ``src`` if ``src`` is not ``None`` in version 1.8, by `Alex Rockhill`_. (`#12382 `__) +- The default value of the ``zero_mean`` parameter of :func:`mne.time_frequency.tfr_array_morlet` will change from ``False`` to ``True`` in version 1.8, for consistency with related functions. By `Daniel McCloy`_. (`#11282 `__) +- The parameter for providing data to :func:`mne.time_frequency.tfr_array_morlet` and :func:`mne.time_frequency.tfr_array_multitaper` has been switched from ``epoch_data`` to ``data``. Only use the ``data`` parameter to avoid a warning. Changes by `Thomas Binns`_. (`#12308 `__) +- Change :func:`mne.stc_near_sensors` ``surface`` default from the ``'pial'`` surface to the surface in ``src`` if ``src`` is not ``None`` in version 1.8, by `Alex Rockhill`_. (`#12382 `__) New features ------------ -- Detecting Bad EEG/MEG channels using the local outlier factor (LOF) algorithm in :func:`mne.preprocessing.find_bad_channels_lof`, by :newcontrib:`Velu Prabhakar Kumaravel`. (`#11234 `__) -- Inform the user about channel discrepancy between provided info, forward operator, and/or covariance matrices in :func:`mne.beamformer.make_lcmv`, by :newcontrib:`Nikolai Kapralov`. (`#12238 `__) -- Support partial pathlength factors for each wavelength in :func:`mne.preprocessing.nirs.beer_lambert_law`, by :newcontrib:`Richard Scholz`. (`#12446 `__) -- Add ``picks`` parameter to :meth:`mne.io.Raw.plot`, allowing users to select which channels to plot. This makes makes the raw data plotting API consistent with :meth:`mne.Epochs.plot` and :meth:`mne.Evoked.plot`, by :newcontrib:`Ivo de Jong`. (`#12467 `__) -- New class :class:`mne.time_frequency.RawTFR` and new methods :meth:`mne.io.Raw.compute_tfr`, :meth:`mne.Epochs.compute_tfr`, and :meth:`mne.Evoked.compute_tfr`. These new methods supersede functions :func:`mne.time_frequency.tfr_morlet`, and :func:`mne.time_frequency.tfr_multitaper`, and :func:`mne.time_frequency.tfr_stockwell`, which are now considered "legacy" functions. By `Daniel McCloy`_. (`#11282 `__) -- Add ability reject :class:`mne.Epochs` using callables, by `Jacob Woessner`_. (`#12195 `__) +- Detecting Bad EEG/MEG channels using the local outlier factor (LOF) algorithm in :func:`mne.preprocessing.find_bad_channels_lof`, by :newcontrib:`Velu Prabhakar Kumaravel`. (`#11234 `__) +- Inform the user about channel discrepancy between provided info, forward operator, and/or covariance matrices in :func:`mne.beamformer.make_lcmv`, by :newcontrib:`Nikolai Kapralov`. (`#12238 `__) +- Support partial pathlength factors for each wavelength in :func:`mne.preprocessing.nirs.beer_lambert_law`, by :newcontrib:`Richard Scholz`. (`#12446 `__) +- Add ``picks`` parameter to :meth:`mne.io.Raw.plot`, allowing users to select which channels to plot. This makes makes the raw data plotting API consistent with :meth:`mne.Epochs.plot` and :meth:`mne.Evoked.plot`, by :newcontrib:`Ivo de Jong`. (`#12467 `__) +- New class :class:`mne.time_frequency.RawTFR` and new methods :meth:`mne.io.Raw.compute_tfr`, :meth:`mne.Epochs.compute_tfr`, and :meth:`mne.Evoked.compute_tfr`. These new methods supersede functions :func:`mne.time_frequency.tfr_morlet`, and :func:`mne.time_frequency.tfr_multitaper`, and :func:`mne.time_frequency.tfr_stockwell`, which are now considered "legacy" functions. By `Daniel McCloy`_. (`#11282 `__) +- Add ability reject :class:`mne.Epochs` using callables, by `Jacob Woessner`_. (`#12195 `__) - Custom functions applied via :meth:`mne.io.Raw.apply_function`, :meth:`mne.Epochs.apply_function` or :meth:`mne.Evoked.apply_function` can now use ``ch_idx`` or ``ch_name`` to get access to the currently processed channel during channel wise processing. -- :meth:`mne.Evoked.apply_function` can now also work on full data array instead of just channel wise, analogous to :meth:`mne.io.Raw.apply_function` and :meth:`mne.Epochs.apply_function`, by `Dominik Welke`_. (`#12206 `__) -- Allow :class:`mne.time_frequency.EpochsTFR` as input to :func:`mne.epochs.equalize_epoch_counts`, by `Carina Forster`_. (`#12207 `__) -- Speed up export to .edf in :func:`mne.export.export_raw` by using ``edfio`` instead of ``EDFlib-Python``. (`#12218 `__) -- Added a helper function :func:`mne.preprocessing.eyetracking.convert_units` to convert eyegaze data from pixel-on-screen values to radians of visual angle. Also added a helper function :func:`mne.preprocessing.eyetracking.get_screen_visual_angle` to get the visual angle that the participant screen subtends, by `Scott Huberty`_. (`#12237 `__) -- We added type hints for the return values of :func:`mne.read_evokeds` and :func:`mne.io.read_raw`. Development environments like VS Code or PyCharm will now provide more help when using these functions in your code. By `Richard Höchenberger`_ and `Eric Larson`_. (:gh:`12297`) (`#12250 `__) -- Add ``method="polyphase"`` to :meth:`mne.io.Raw.resample` and related functions to allow resampling using :func:`scipy.signal.upfirdn`, by `Eric Larson`_. (`#12268 `__) -- The package build backend was switched from ``setuptools`` to ``hatchling``. This will only affect users who build and install MNE-Python from source. By `Richard Höchenberger`_. (:gh:`12281`) (`#12269 `__) -- :meth:`mne.Annotations.to_data_frame` can now output different formats for the ``onset`` column: seconds, milliseconds, datetime objects, and timedelta objects. By `Daniel McCloy`_. (`#12289 `__) -- Add method :meth:`mne.SourceEstimate.save_as_surface` to allow saving GIFTI files from surface source estimates, by `Peter Molfese`_. (`#12309 `__) -- :class:`mne.Epochs` can now be constructed using :class:`mne.Annotations` stored in the ``raw`` object, by specifying ``events=None``. By `Alex Rockhill`_. (`#12311 `__) -- Add :meth:`~mne.SourceEstimate.savgol_filter`, :meth:`~mne.SourceEstimate.filter`, :meth:`~mne.SourceEstimate.apply_hilbert`, and :meth:`~mne.SourceEstimate.apply_function` methods to :class:`mne.SourceEstimate` and related classes, by `Hamza Abdelhedi`_. (`#12323 `__) -- Add ability to export STIM channels to EDF in :meth:`mne.io.Raw.export`, by `Clemens Brunner`_. (`#12332 `__) -- Speed up raw FIF reading when using small buffer sizes by `Eric Larson`_. (`#12343 `__) -- Speed up :func:`mne.io.read_raw_neuralynx` on large datasets with many gaps, by `Kristijan Armeni`_. (`#12371 `__) -- Add ability to detect minima peaks found in :class:`mne.Evoked` if data is all positive and maxima if data is all negative. (`#12383 `__) -- Add ability to remove bad marker coils in :func:`mne.io.read_raw_kit`, by `Judy D Zhu`_. (`#12394 `__) -- Add option to pass ``image_kwargs`` to :class:`mne.Report.add_epochs` to allow adjusting e.g. ``vmin`` and ``vmax`` of the epochs image in the report, by `Sophie Herbst`_. (`#12443 `__) -- Add support for multiple raw instances in :func:`mne.preprocessing.compute_average_dev_head_t` by `Eric Larson`_. (`#12445 `__) -- Completing PR 12453. Add option to pass ``image_kwargs`` per channel type to :class:`mne.Report.add_epochs`. (`#12454 `__) -- :func:`mne.epochs.make_metadata` now accepts strings as ``tmin`` and ``tmax`` parameter values, simplifying metadata creation based on time-varying events such as responses to a stimulus, by `Richard Höchenberger`_. (`#12462 `__) -- Include date of acquisition and filter parameters in ``raw.info`` for :func:`mne.io.read_raw_neuralynx` by `Kristijan Armeni`_. (`#12463 `__) -- Add ``physical_range="channelwise"`` to :meth:`mne.io.Raw.export` for exporting to EDF, which can improve amplitude resolution if individual channels vary greatly in their offsets, by `Clemens Brunner`_. (`#12510 `__) +- :meth:`mne.Evoked.apply_function` can now also work on full data array instead of just channel wise, analogous to :meth:`mne.io.Raw.apply_function` and :meth:`mne.Epochs.apply_function`, by `Dominik Welke`_. (`#12206 `__) +- Allow :class:`mne.time_frequency.EpochsTFR` as input to :func:`mne.epochs.equalize_epoch_counts`, by `Carina Forster`_. (`#12207 `__) +- Speed up export to .edf in :func:`mne.export.export_raw` by using ``edfio`` instead of ``EDFlib-Python``. (`#12218 `__) +- Added a helper function :func:`mne.preprocessing.eyetracking.convert_units` to convert eyegaze data from pixel-on-screen values to radians of visual angle. Also added a helper function :func:`mne.preprocessing.eyetracking.get_screen_visual_angle` to get the visual angle that the participant screen subtends, by `Scott Huberty`_. (`#12237 `__) +- We added type hints for the return values of :func:`mne.read_evokeds` and :func:`mne.io.read_raw`. Development environments like VS Code or PyCharm will now provide more help when using these functions in your code. By `Richard Höchenberger`_ and `Eric Larson`_. (:gh:`12297`) (`#12250 `__) +- Add ``method="polyphase"`` to :meth:`mne.io.Raw.resample` and related functions to allow resampling using :func:`scipy.signal.upfirdn`, by `Eric Larson`_. (`#12268 `__) +- The package build backend was switched from ``setuptools`` to ``hatchling``. This will only affect users who build and install MNE-Python from source. By `Richard Höchenberger`_. (:gh:`12281`) (`#12269 `__) +- :meth:`mne.Annotations.to_data_frame` can now output different formats for the ``onset`` column: seconds, milliseconds, datetime objects, and timedelta objects. By `Daniel McCloy`_. (`#12289 `__) +- Add method :meth:`mne.SourceEstimate.save_as_surface` to allow saving GIFTI files from surface source estimates, by `Peter Molfese`_. (`#12309 `__) +- :class:`mne.Epochs` can now be constructed using :class:`mne.Annotations` stored in the ``raw`` object, by specifying ``events=None``. By `Alex Rockhill`_. (`#12311 `__) +- Add :meth:`~mne.SourceEstimate.savgol_filter`, :meth:`~mne.SourceEstimate.filter`, :meth:`~mne.SourceEstimate.apply_hilbert`, and :meth:`~mne.SourceEstimate.apply_function` methods to :class:`mne.SourceEstimate` and related classes, by `Hamza Abdelhedi`_. (`#12323 `__) +- Add ability to export STIM channels to EDF in :meth:`mne.io.Raw.export`, by `Clemens Brunner`_. (`#12332 `__) +- Speed up raw FIF reading when using small buffer sizes by `Eric Larson`_. (`#12343 `__) +- Speed up :func:`mne.io.read_raw_neuralynx` on large datasets with many gaps, by `Kristijan Armeni`_. (`#12371 `__) +- Add ability to detect minima peaks found in :class:`mne.Evoked` if data is all positive and maxima if data is all negative. (`#12383 `__) +- Add ability to remove bad marker coils in :func:`mne.io.read_raw_kit`, by `Judy D Zhu`_. (`#12394 `__) +- Add option to pass ``image_kwargs`` to :class:`mne.Report.add_epochs` to allow adjusting e.g. ``vmin`` and ``vmax`` of the epochs image in the report, by `Sophie Herbst`_. (`#12443 `__) +- Add support for multiple raw instances in :func:`mne.preprocessing.compute_average_dev_head_t` by `Eric Larson`_. (`#12445 `__) +- Completing PR 12453. Add option to pass ``image_kwargs`` per channel type to :class:`mne.Report.add_epochs`. (`#12454 `__) +- :func:`mne.epochs.make_metadata` now accepts strings as ``tmin`` and ``tmax`` parameter values, simplifying metadata creation based on time-varying events such as responses to a stimulus, by `Richard Höchenberger`_. (`#12462 `__) +- Include date of acquisition and filter parameters in ``raw.info`` for :func:`mne.io.read_raw_neuralynx` by `Kristijan Armeni`_. (`#12463 `__) +- Add ``physical_range="channelwise"`` to :meth:`mne.io.Raw.export` for exporting to EDF, which can improve amplitude resolution if individual channels vary greatly in their offsets, by `Clemens Brunner`_. (`#12510 `__) - Added the ability to reorder report contents via :meth:`mne.Report.reorder` (with - helper to get contents with :meth:`mne.Report.get_contents`), by `Eric Larson`_. (`#12513 `__) -- Add ``exclude_after_unique`` option to :meth:`mne.io.read_raw_edf` and :meth:`mne.io.read_raw_edf` to search for exclude channels after making channels names unique, by `Michiru Kaneda`_ (`#12518 `__) + helper to get contents with :meth:`mne.Report.get_contents`), by `Eric Larson`_. (`#12513 `__) +- Add ``exclude_after_unique`` option to :meth:`mne.io.read_raw_edf` and :meth:`mne.io.read_raw_edf` to search for exclude channels after making channels names unique, by `Michiru Kaneda`_ (`#12518 `__) Other changes ------------- -- Updated the text in the preprocessing tutorial to use :meth:`mne.io.Raw.pick` instead of the legacy :meth:`mne.io.Raw.pick_types`, by :newcontrib:`btkcodedev`. (`#12326 `__) -- Clarify in the :ref:`EEG referencing tutorial ` that an average reference projector ready is required for inverse modeling, by :newcontrib:`Nabil Alibou` (`#12420 `__) -- Fix dead links in ``README.rst`` documentation by :newcontrib:`Will Turner`. (`#12461 `__) -- Replacing percent format with f-strings format specifiers , by :newcontrib:`Hasrat Ali Arzoo`. (`#12464 `__) -- Adopted towncrier_ for changelog entries, by `Eric Larson`_. (`#12299 `__) -- Automate adding of PR number to towncrier stubs, by `Eric Larson`_. (`#12318 `__) -- Refresh code base to use Python 3.9 syntax using Ruff UP rules (pyupgrade), by `Clemens Brunner`_. (`#12358 `__) -- Move private data preparation functions for BrainVision export from ``pybv`` to ``mne``, by `Clemens Brunner`_. (`#12450 `__) -- Update the list of sensor types in docstrings, tutorials and the glossary by `Nabil Alibou`_. (`#12509 `__) +- Updated the text in the preprocessing tutorial to use :meth:`mne.io.Raw.pick` instead of the legacy :meth:`mne.io.Raw.pick_types`, by :newcontrib:`btkcodedev`. (`#12326 `__) +- Clarify in the :ref:`EEG referencing tutorial ` that an average reference projector ready is required for inverse modeling, by :newcontrib:`Nabil Alibou` (`#12420 `__) +- Fix dead links in ``README.rst`` documentation by :newcontrib:`Will Turner`. (`#12461 `__) +- Replacing percent format with f-strings format specifiers , by :newcontrib:`Hasrat Ali Arzoo`. (`#12464 `__) +- Adopted towncrier_ for changelog entries, by `Eric Larson`_. (`#12299 `__) +- Automate adding of PR number to towncrier stubs, by `Eric Larson`_. (`#12318 `__) +- Refresh code base to use Python 3.9 syntax using Ruff UP rules (pyupgrade), by `Clemens Brunner`_. (`#12358 `__) +- Move private data preparation functions for BrainVision export from ``pybv`` to ``mne``, by `Clemens Brunner`_. (`#12450 `__) +- Update the list of sensor types in docstrings, tutorials and the glossary by `Nabil Alibou`_. (`#12509 `__) Authors diff --git a/doc/changes/v1.8.rst b/doc/changes/v1.8.rst new file mode 100644 index 00000000000..f6abcc65e52 --- /dev/null +++ b/doc/changes/v1.8.rst @@ -0,0 +1,173 @@ +.. _changes_1_8_0: + +Version 1.8.0 (2024-08-18) +========================== + +Dependencies +------------ + +- Minimum versions for dependencies were bumped to those ~2 years old at the time of release (by `Eric Larson`_), including: + + - NumPy ≥ 1.23 + - SciPy ≥ 1.9 + - Matplotlib ≥ 3.6 + - scikit-learn ≥ 1.1 (`#12554 `__) +- Official support for PySide2 has been dropped in this release (though it might continue + to work), by `Eric Larson`_. (`#12742 `__) + + +Bugfixes +-------- + +- Fix bug where an event that occurred only once was excluded in :func:`mne.io.read_raw_egi`, by :newcontrib:`Ping-Keng Jao`. (`#12300 `__) +- Fix bug where :func:`mne.stats.permutation_cluster_test` (and related functions) uses excessive amount of memory for large 2D data when TFCE method is selected, by :newcontrib:`Nicolas Fourcaud-Trocmé`. (`#12609 `__) +- Assure that blink times are handled correctly :func:`mne.preprocessing.eyetracking.interpolate_blinks`, even when the raw object is cropped by `Scott Huberty`_ and :newcontrib:`Sammi Chekroud`. (`#12759 `__) +- Fix check for dropping all channels in :meth:`mne.io.Raw.drop_channels` and related methods, by :newcontrib:`Farzin Negahbani`. (`#12763 `__) +- Fix scrolling behavior in :class:`~mne.Report` when clicking on a TOC entry multiple times, by `Richard Höchenberger`_. (`#12561 `__) +- Fix bug where :func:`mne.decoding.get_coef` did not work properly with :class:`mne.decoding.CSP`, by `Eric Larson`_. (`#12562 `__) +- The color scaling of Evoked topomaps added to reports via :meth:`mne.Report.add_evokeds` + was sometimes sub-optimal if bad channels were present in the data. This has now been fixed + and should be more consistent with the topomaps shown in the joint plots, by `Richard Höchenberger`_. (`#12578 `__) +- Fix error causing :meth:`mne.Epochs.interpolate_bads` not to work for ``seeg`` channels and fix a single contact on neighboring shafts sometimes being included in interpolation, by `Alex Rockhill`_ (`#12593 `__) +- Fix bug where :func:`mne.io.read_raw_fil` could not assign bad channels on import, by `George O'Neill`_. (`#12597 `__) +- Fixed a bug where :meth:`mne.Evoked.animate_topomap` did not work with :func:`mne.preprocessing.compute_current_source_density` - modified data, by `Michal Žák`_. (`#12605 `__) +- Fix overflow when plotting source estimates where data is all zero (or close to zero), and fix the range of allowed values for the colorbar sliders, by `Marijn van Vliet`_. (`#12612 `__) +- Fix adding channels to :class:`~mne.time_frequency.EpochsTFR` objects, by `Clemens Brunner`_. (`#12616 `__) +- Fix for new sklearn metadata routing protocol in decoding search_light, by `Alex Gramfort`_ (`#12620 `__) +- Fix bug where :func:`mne.time_frequency.csd_multitaper`, :func:`mne.time_frequency.csd_fourier`, :func:`mne.time_frequency.csd_array_multitaper`, and :func:`mne.time_frequency.csd_array_fourier` would return cross-spectral densities with the ``fmin`` and ``fmax`` frequencies missing, by `Thomas Binns`_ (`#12633 `__) +- Output types of sparse arrays were changed from ``matrix`` to ``array`` in + :func:`~mne.channels.read_ch_adjacency`, :func:`~mne.channels.find_ch_adjacency`, + :func:`~mne.stats.combine_adjacency`, :func:`~mne.spatio_temporal_src_adjacency`, + and related functions to comply with the pending deprecation of ``np.matrix``. + The returned objects now behave like standard :class:`~numpy.ndarray` objects, and + in particular ``*`` now operates element-wise instead of performing matrix + multiplication. You can use ``@`` as a backward compatible matrix multiplication + for both ``np.matrix`` and ``np.ndarray`` objects, and if a matrix is desired + the outputs can be cast directly, for example as ``scipy.sparse.csr_matrix(out)``. + Changed by `Eric Larson`_. (`#12646 `__) +- Fix incorrect RuntimeWarning (different channel filter settings) in EDF/BDF import, by `Clemens Brunner`_. (`#12661 `__) +- In :func:`mne.export.export_raw` (``fmt='edf'``), when padding data to create equal-length data blocks, + edge-padding is favored over zero-padding in order to avoid accidentally enlarging physical range, by `Qian Chu`_. (`#12676 `__) +- In :func:`mne.io.read_raw_eyelink`, gracefully handle missing datetime in file by `Scott Huberty`_. (`#12687 `__) +- Fix regression with :class:`mne.decoding.CSP` where using ``rank="full"`` errantly + raised an error, by `Eric Larson`_. (`#12694 `__) +- Fix in-memory anonymization of data read with :func:`mne.io.read_raw_edf` by `Eric Larson`_. (`#12720 `__) +- Fix bug with overplotting of butterfly labels in :func:`mne.viz.plot_raw` and related + functions and methods, by `Eric Larson`_. (`#12721 `__) +- Fix a bug where the ``ylim`` parameter would sometimes apply to the wrong channel types in :func:`mne.viz.plot_evoked_topo`, by `Marijn van Vliet`_. (`#12724 `__) +- Fix bug where ad-hoc regularization of a covariance with + :func:`mne.cov.regularize` did not properly account for bad channels + in rank calculations, by `Eric Larson`_. (`#12727 `__) +- Fix bug when reading NIRX files saved in a non-western encoding, by `Daniel McCloy`_. (`#12730 `__) +- :func:`~mne.set_log_file` and :func:`~mne.set_log_level` can now be correctly detected by + static analysis tools like Pylance, by `Richard Höchenberger`_. (`#12735 `__) +- Safeguard loading of ``meas_date`` in :func:`mne.io.read_raw_edf`, by `Mathieu Scheltienne`_. (`#12754 `__) +- Fix bug in :func:`~mne.preprocessing.maxwell_filter_prepare_emptyroom` where a difference in sampling frequencies between data and emptyroom files was ignored, by `Daniel McCloy`_. (`#12760 `__) + + +API changes by deprecation +-------------------------- + +- A new argument ``events_as_annotations`` has been added to :func:`mne.io.read_raw_egi` + with a default value of ``False`` that will change to ``True`` in version 1.9, by + `Scott Huberty`_ and `Eric Larson`_. (`#12300 `__) +- ``mne.Info.ch_names`` will now return an empty list instead of raising a ``KeyError`` if no channels + are present, by `Richard Höchenberger`_. (`#12583 `__) +- Documented that :func:`~mne.match_channel_orders` can also work on Epochs, and Evoked objects. Reflecting this, deprecated the ``raws`` parameter in favor of an ``insts`` parameter, by `Stefan Appelhoff`_. (`#12699 `__) +- The ``block`` argument to :class:`mne.viz.Brain` is deprecated and will be removed in + 1.9, use :func:`matplotlib.pyplot.show` with ``block=True`` instead, by `Eric Larson`_. (`#12719 `__) +- :func:`mne.datasets.fetch_fsaverage` now returns a :class:`python:pathlib.Path` object + rather than a string. Support for string concatenation with plus (``+``) is thus + deprecated and will be removed in 1.9, use the forward-slash ``/`` operator instead, + by `Eric Larson`_. (`#12771 `__) + + +New features +------------ + +- Added internals to allow modifying single-channel annotations in the Qt + raw browser, by :newcontrib:`Noah Markowitz`. (`#12669 `__) +- Adding :meth:`mne.channels.Layout.copy` and :meth:`mne.channels.Layout.pick` to copy and select channels from a :class:`mne.channels.Layout` object. Plotting 2D topographies of evoked responses with :func:`mne.viz.plot_evoked_topo` with both arguments ``layout`` and ``exclude`` now ignores excluded channels from the :class:`mne.channels.Layout`. By `Mathieu Scheltienne`_. (`#12338 `__) +- In :class:`~mne.Report` you can now easily navigate through images and figures connected to a slider with the left and right arrow keys. Clicking on the slider or respective image will focus the slider, enabling keyboard navigation, by `Richard Höchenberger`_ (`#12556 `__) +- When plotting EOG and ECG artifact scores for ICA in :meth:`mne.Report.add_ica`, + the channel names used for artifact detection are now displayed in the titles of + each respective subplot, by `Richard Höchenberger`_. (`#12573 `__) +- Use ``aseg='auto'`` for :meth:`mne.viz.Brain.add_volume_labels` and :func:`mne.get_montage_volume_labels` to use ``aparc+aseg`` by default or if not present use ``wmparc`` because freesurfer uses ``wmparc`` in the latest version, by `Alex Rockhill`_. (`#12576 `__) +- The HTML representations of :class:`~mne.io.Raw`, :class:`~mne.Epochs`, + and :class:`~mne.Evoked` (which you will see e.g. when working with Jupyter Notebooks or + :class:`~mne.Report`) have been updated to be more consistent and contain + slightly more information, by `Richard Höchenberger`_. (:gh:`12624`) (`#12583 `__) +- When adding :class:`~mne.Evoked` data to a :class:`~mne.Report` via + :meth:`~mne.Report.add_evokeds`, we now also include an "Info" section + with some basic summary info, as has already been the case for raw and + epochs data, by `Richard Höchenberger`_. (`#12584 `__) +- We added new installation variants for a full installation with the PySide6 Qt binding + (``"mne[full-pyside6]"``), with the PyQt6 binding (``"mne[full-pyqt6]"``, equivalent to + ``"mne[full]"``), and without any Qt binding (``"mne[full-no-qt]"``), which may be useful + in certain situations by `Richard Höchenberger`_. (`#12628 `__) +- Adding argument ``'random'`` to :func:`~mne.epochs.equalize_epoch_counts` and to :meth:`~mne.Epochs.equalize_event_counts` to randomly select epochs or events. By `Mathieu Scheltienne`_. (`#12649 `__) +- Add new parameter ``ignore_marker_types`` to :func:`~mne.io.read_raw_brainvision` to ignore marker types (and only use marker descriptions) when reading BrainVision files, by `Clemens Brunner`_. (`#12652 `__) +- Added support for passing ``axes`` to :func:`mne.viz.plot_head_positions` when + ``mode='field'``, by `Eric Larson`_. (`#12655 `__) +- The HTML representation of :class:`~mne.Epochs` (visible e.g. in Jupyter or in :class:`~mne.Report`) now + indicates whether metadata is attached to the epochs, by `Richard Höchenberger`_. (`#12686 `__) +- Montage plots created with :meth:`~mne.channels.DigMontage.plot` now scale both the channel dots *and* channel names with the new ``scale`` parameter. The default is ``scale=1`` (factors less than 1 will scale down, whereas factors greater than 1 will scale up). The previous ``scale_factor`` parameter only affected marker size, and this parameter is now deprecated. By `Clemens Brunner`_. (`#12703 `__) +- Add :func:`~mne.stats.erp.compute_sme` to compute the analytical standardized measurement error (SME) as a data quality measure for ERP studies, by `Clemens Brunner`_. (`#12707 `__) +- Use :class:`python:datetime.date` for ``info["subject_info"]["birthday"]`` rather than + a tuple of ``(year, month, day)`` by `Eric Larson`_. (`#12720 `__) +- Add default ``spatial_colors="auto"`` to :func:`mne.viz.plot_evoked_white` and + :meth:`mne.Evoked.plot_white` to enable spatial colors by default, by `Eric Larson`_. (`#12725 `__) +- :func:`mne.minimum_norm.make_inverse_operator` and related functions now more robustly + warn if the whitener computed from the noise covariance has an incorrect rank, + by `Eric Larson`_. (`#12727 `__) +- When indexing :class:`~mne.Epochs` (e.g. by doing ``epochs[0]``), static code analysis tools like Pylance + should now be able to infer that the returned object is an epoch, too, and provide editor support + like automated code completions, by `Richard Höchenberger`_. (`#12733 `__) +- When using the ``data_path()`` in any dataset included in :py:mod:`mne.datasets`, + static analysis tools like Pylance will now correctly infer that a `pathlib.Path` will + be returned and provide editor support like automated code completions, by `Richard Höchenberger`_. (`#12734 `__) +- Add support for storing Fourier coefficients in :class:`mne.time_frequency.Spectrum`, + :class:`mne.time_frequency.EpochsSpectrum`, :class:`mne.time_frequency.SpectrumArray`, + and :class:`mne.time_frequency.EpochsSpectrumArray` objects, by `Thomas Binns`_. (`#12747 `__) + + +Other changes +------------- + +- Fixed issue template links by :newcontrib:`Michal Žák` (`#12600 `__) +- Enhance documentation on decimation filtering to prevent aliasing, by :newcontrib:`Xabier de Zuazo`. (`#12650 `__) +- Added `vulture `__ as a pre-commit hook and removed related dead code, by `Eric Larson`_. (`#12569 `__) +- Add link to BEst-Python in the list of related software. by `Ilian Azz`_. (`#12659 `__) +- Improved clarity of parameter documentation for `mne.decoding.SSD.fit`, by `Thomas Binns`_. (`#12664 `__) +- Disable the "Back to top" button in the documentation, by `Richard Höchenberger`_. (`#12688 `__) +- Improve argument ``ylim`` documentation through :class:`~mne.Evoked` plotting function and validate type to :class:`dict` or ``None`` to prevent misuage, by `Mathieu Scheltienne`_. (`#12697 `__) +- Code contributions are now measured using PRs and reported on the :ref:`contributors` + page, by `Eric Larson`_. (`#12774 `__) +- Authorship headers in MNE-Python code have been standardized, by `Eric Larson`_. (`#12781 `__) + +Authors +------- + +* Alex Rockhill +* Alexandre Gramfort +* Clemens Brunner +* Daniel McCloy +* Dimitri Papadopoulos Orfanos +* Eric Larson +* Farzin Negahbani+ +* George O'Neill +* Ilian AZZ +* Marijn van Vliet +* Mathieu Scheltienne +* Michal Žák+ +* Nabil Alibou +* Nicolas Fourcaud-Trocmé+ +* Noah Markowitz+ +* Ping-Keng Jao+ +* Qian Chu +* Richard Höchenberger +* Sammi Chekroud+ +* Scott Huberty +* Stefan Appelhoff +* Thomas S. Binns +* Xabier de Zuazo+ diff --git a/doc/conf.py b/doc/conf.py index 3330146aa28..cb7510b34a7 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,8 +1,11 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html +"""Configuration file for the Sphinx documentation builder. + +This file only contains a selection of the most common options. For a full +list see the documentation: +https://www.sphinx-doc.org/en/master/usage/configuration.html +""" + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -39,7 +42,6 @@ os.environ["MNE_3D_OPTION_THEME"] = "light" # https://numba.readthedocs.io/en/latest/reference/deprecation.html#deprecation-of-old-style-numba-captured-errors # noqa: E501 os.environ["NUMBA_CAPTURED_ERRORS"] = "new_style" -sphinx_logger = sphinx.util.logging.getLogger("mne") mne.html_templates._templates._COLLAPSED = True # collapse info _repr_html_ # -- Path setup -------------------------------------------------------------- @@ -50,7 +52,8 @@ curpath = Path(__file__).parent.resolve(strict=True) sys.path.append(str(curpath / "sphinxext")) -from mne_doc_utils import report_scraper, reset_warnings # noqa: E402 +from credit_tools import generate_credit_rst # noqa: E402 +from mne_doc_utils import report_scraper, reset_warnings, sphinx_logger # noqa: E402 # -- Project information ----------------------------------------------------- @@ -206,6 +209,8 @@ "ColorbarBase": "matplotlib.colorbar.ColorbarBase", # sklearn "LeaveOneOut": "sklearn.model_selection.LeaveOneOut", + "MetadataRequest": "sklearn.utils.metadata_routing.MetadataRequest", + "estimator": "sklearn.base.BaseEstimator", # joblib "joblib.Parallel": "joblib.Parallel", # nibabel @@ -270,6 +275,7 @@ "EpochsFIF": "mne.Epochs", "EpochsEEGLAB": "mne.Epochs", "EpochsKIT": "mne.Epochs", + "RawANT": "mne.io.Raw", "RawBOXY": "mne.io.Raw", "RawBrainVision": "mne.io.Raw", "RawBTi": "mne.io.Raw", @@ -393,6 +399,9 @@ "mapping", "to", "any", + "pandas", + "polars", + "default", # unlinkable "CoregistrationUI", "mne_qt_browser.figure.MNEQtBrowser", @@ -596,6 +605,28 @@ def append_attr_meth_examples(app, what, name, obj, options, lines): """.format(name.split(".")[-1], name).split("\n") +def fix_sklearn_inherited_docstrings(app, what, name, obj, options, lines): + """Fix sklearn docstrings because they use autolink and we do not.""" + if ( + name.startswith("mne.decoding.") or name.startswith("mne.preprocessing.Xdawn") + ) and name.endswith( + ( + ".get_metadata_routing", + ".fit", + ".fit_transform", + ".set_output", + ".transform", + ) + ): + if ":Parameters:" in lines: + loc = lines.index(":Parameters:") + else: + loc = lines.index(":Returns:") + lines.insert(loc, "") + lines.insert(loc, ".. default-role:: autolink") + lines.insert(loc, "") + + # -- Other extension configuration ------------------------------------------- # Consider using http://magjac.com/graphviz-visual-editor for this @@ -616,6 +647,7 @@ def append_attr_meth_examples(app, what, name, obj, options, lines): "https://doi.org/10.1073/", # pnas.org "https://doi.org/10.1093/", # academic.oup.com/sleep/ "https://doi.org/10.1098/", # royalsocietypublishing.org + "https://doi.org/10.1101/", # www.biorxiv.org "https://doi.org/10.1111/", # onlinelibrary.wiley.com/doi/10.1111/psyp "https://doi.org/10.1126/", # www.science.org "https://doi.org/10.1137/", # epubs.siam.org @@ -1102,9 +1134,9 @@ def append_attr_meth_examples(app, what, name, obj, options, lines): size=xl, ), dict( - name="Human Neuroscience Platforn at Fondation Campus Biotech Geneva", # noqa E501 + name="Fondation Campus Biotech Geneva", img="FCBG.svg", - url="https://hnp.fcbg.ch/", + url="https://fcbg.ch/", size=sm, ), ], @@ -1654,7 +1686,9 @@ def make_version(app, exception): def setup(app): """Set up the Sphinx app.""" app.connect("autodoc-process-docstring", append_attr_meth_examples) + app.connect("autodoc-process-docstring", fix_sklearn_inherited_docstrings) # High prio, will happen before SG + app.connect("builder-inited", generate_credit_rst, priority=10) app.connect("builder-inited", report_scraper.set_dirs, priority=20) app.connect("build-finished", make_gallery_redirects) app.connect("build-finished", make_api_redirects) diff --git a/doc/conftest.py b/doc/conftest.py index 2782b6956ac..1e791fbb923 100644 --- a/doc/conftest.py +++ b/doc/conftest.py @@ -1,3 +1,5 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from mne.conftest import * # noqa diff --git a/doc/credit.rst b/doc/credit.rst new file mode 100644 index 00000000000..4d9a9957604 --- /dev/null +++ b/doc/credit.rst @@ -0,0 +1,12 @@ +:orphan: + +.. _contributors: + +============ +Contributors +============ + +There are many different ways to contribute to MNE-Python! So far we only list +code contributions below, but plan to add other metrics in the future. + +.. include:: ./code_credit.inc diff --git a/doc/development/contributing.rst b/doc/development/contributing.rst index aec32da00ac..1cca8a8608d 100644 --- a/doc/development/contributing.rst +++ b/doc/development/contributing.rst @@ -242,8 +242,8 @@ Creating the virtual environment These instructions will set up a Python environment that is separated from your system-level Python and any other managed Python environments on your computer. -This lets you switch between different versions of Python (MNE-Python requires -version 3.9 or higher) and also switch between the stable and development +This lets you switch between different versions of Python and also switch between +the stable and development versions of MNE-Python (so you can, for example, use the same computer to analyze your data with the stable release, and also work with the latest development version to fix bugs or add new features). Even if you've already diff --git a/doc/development/whats_new.rst b/doc/development/whats_new.rst index 659157e5e39..75ece13b5e0 100644 --- a/doc/development/whats_new.rst +++ b/doc/development/whats_new.rst @@ -9,6 +9,7 @@ Changes for each version of MNE-Python are listed below. :maxdepth: 1 ../changes/devel.rst + ../changes/v1.8.rst ../changes/v1.7.rst ../changes/v1.6.rst ../changes/v1.5.rst diff --git a/doc/documentation/cited.rst b/doc/documentation/cited.rst index 31c19589b16..565698d9c67 100644 --- a/doc/documentation/cited.rst +++ b/doc/documentation/cited.rst @@ -3,7 +3,7 @@ Papers citing MNE-Python ======================== -Estimates provided by Google Scholar as of 19 April 2024: +Estimates provided by Google Scholar as of 18 August 2024: -- `MNE (1730) `_ -- `MNE-Python (2570) `_ +- `MNE (1810) `_ +- `MNE-Python (2860) `_ diff --git a/doc/install/installers.rst b/doc/install/installers.rst index 93de05bd6b1..1aa352edcfb 100644 --- a/doc/install/installers.rst +++ b/doc/install/installers.rst @@ -7,14 +7,17 @@ MNE-Python installers are the easiest way to install MNE-Python and all dependencies. They also provide many additional Python packages and tools. Got any questions? Let us know on the `MNE Forum`_! +Platform-specific installers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. tab-set:: - :class: platform-selector-tabset + :class: install-selector-tabset .. tab-item:: Linux :class-content: text-center - :name: linux-installers + :name: install-linux - .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.7.1/MNE-Python-1.7.1_0-Linux.sh + .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.8.0/MNE-Python-1.8.0_0-Linux.sh :ref-type: ref :color: primary :shadow: @@ -28,14 +31,14 @@ Python packages and tools. Got any questions? Let us know on the `MNE Forum`_! .. code-block:: console - $ sh ./MNE-Python-1.7.1_0-Linux.sh + $ sh ./MNE-Python-1.8.0_0-Linux.sh .. tab-item:: macOS (Intel) :class-content: text-center - :name: macos-intel-installers + :name: install-macos-intel - .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.7.1/MNE-Python-1.7.1_0-macOS_Intel.pkg + .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.8.0/MNE-Python-1.8.0_0-macOS_Intel.pkg :ref-type: ref :color: primary :shadow: @@ -49,9 +52,9 @@ Python packages and tools. Got any questions? Let us know on the `MNE Forum`_! .. tab-item:: macOS (Apple Silicon) :class-content: text-center - :name: macos-apple-installers + :name: install-macos-apple - .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.7.1/MNE-Python-1.7.1_0-macOS_M1.pkg + .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.8.0/MNE-Python-1.8.0_0-macOS_M1.pkg :ref-type: ref :color: primary :shadow: @@ -65,9 +68,9 @@ Python packages and tools. Got any questions? Let us know on the `MNE Forum`_! .. tab-item:: Windows :class-content: text-center - :name: windows-installers + :name: install-windows - .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.7.1/MNE-Python-1.7.1_0-Windows.exe + .. button-link:: https://github.com/mne-tools/mne-installers/releases/download/v1.8.0/MNE-Python-1.8.0_0-Windows.exe :ref-type: ref :color: primary :shadow: @@ -107,3 +110,54 @@ bundles to the ``Applications`` folder on macOS. applications to start, especially on the very first run – which may take particularly long on Apple Silicon-based computers. Subsequent runs should usually be much faster. + +Uninstallation +^^^^^^^^^^^^^^ + +To remove the MNE-Python distribution provided by our installers above: + +1. Remove relevant lines from your shell initialization scripts if you + added them at installation time. To do this, you can run from the MNE Prompt: + + .. code-block:: bash + + $ conda init --reverse + + Or you can manually edit shell initialization scripts, e.g., ``~/.bashrc`` or + ``~/.bash_profile``. + +2. Follow the instructions below to remove the MNE-Python conda installation for your platform: + + .. tab-set:: + :class: uninstall-selector-tabset + + .. tab-item:: Linux + :name: uninstall-linux + + In a BASH terminal you can do: + + .. code-block:: bash + + $ which python + /home/username/mne-python/1.8.0_0/bin/python + $ rm -Rf /home/$USER/mne-python + $ rm /home/$USER/.local/share/applications/mne-python-*.desktop + + .. tab-item:: macOS + :name: uninstall-macos + + You can simply `drag the MNE-Python folder to the trash in the Finder `__. + + Alternatively, you can do something like: + + .. code-block:: bash + + $ which python + /Users/username/Applications/MNE-Python/1.8.0_0/.mne-python/bin/python + $ rm -Rf /Users/$USER/Applications/MNE-Python # if user-specific + $ rm -Rf /Applications/MNE-Python # if system-wide + + .. tab-item:: Windows + :name: uninstall-windows + + To uninstall MNE-Python, you can remove the application using the `Windows Control Panel `__. diff --git a/doc/links.inc b/doc/links.inc index 27e61c850bc..b25f5265509 100644 --- a/doc/links.inc +++ b/doc/links.inc @@ -71,6 +71,7 @@ .. _python: http://www.python.org .. _Brain Imaging Data Structure: https://bids.neuroimaging.io/ +.. _SPEC0: https://scientific-python.org/specs/spec-0000 .. python packages diff --git a/doc/sphinxext/contrib_avatars.py b/doc/sphinxext/contrib_avatars.py index 299e074dd4d..9ad00f575e4 100644 --- a/doc/sphinxext/contrib_avatars.py +++ b/doc/sphinxext/contrib_avatars.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os from pathlib import Path diff --git a/doc/sphinxext/credit_tools.py b/doc/sphinxext/credit_tools.py new file mode 100644 index 00000000000..4de9b3ffc21 --- /dev/null +++ b/doc/sphinxext/credit_tools.py @@ -0,0 +1,509 @@ +"""Create code credit RST file. + +Run ./tools/dev/update_credit_json.py first to get the latest PR JSON files. +""" + +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + +import glob +import json +import pathlib +import re +from collections import defaultdict +from pathlib import Path + +import numpy as np +import sphinx.util.logging + +import mne +from mne.utils import logger, verbose + +sphinx_logger = sphinx.util.logging.getLogger("mne") + +repo_root = Path(__file__).parents[2] +doc_root = repo_root / "doc" +data_dir = doc_root / "sphinxext" + +# TODO: For contributor names there are three sources of potential truth: +# +# 1. names.inc +# 2. GitHub profile names (that we pull dynamically here) +# 3. commit history / .mailmap. +# +# All three names can mismatch. Currently we try to defer to names.inc since this +# is assumed to have been chosen the most consciously/intentionally by contributors. +# Though it is possible that people can change their preferred names as well, so +# preferring GitHub profile info (when complete!) is probably preferable. + +# Allowed singletons +single_names = "btkcodedev buildqa sviter Akshay".split() +# Allowed abbrevitaions in first/last name +abbreviations = ["T. Wang"] +# Manual renames +manual_renames = { + "alexandra": "Alexandra Corneyllie", # 7600 + "alexandra.corneyllie": "Alexandra Corneyllie", # 7600 + "akshay0724": "Akshay", # 4046, TODO: Check singleton + "AnneSo": "Anne-Sophie Dubarry", # 4910 + "Basile": "Basile Pinsard", # 1791 + "ChristinaZhao": "Christina Zhao", # 9075 + "Drew, J.": "Jordan Drew", # 10861 + "enzo": "Enzo Altamiranda", # 11351 + "Frostime": "Yiping Zuo", # 11773 + "Gennadiy": "Gennadiy Belonosov", # 11720 + "Hamid": "Hamid Maymandi", # 10849 + "jwelzel": "Julius Welzel", # 11118 + "Martin": "Martin Billinger", # 8099, TODO: Check + "Mats": "Mats van Es", # 11068 + "Michael": "Michael Krause", # 3304 + "Naveen": "Naveen Srinivasan", # 10787 + "NoahMarkowitz": "Noah Markowitz", # 12669 + "PAB": "Pierre-Antoine Bannier", # 9430 + "Rob Luke": "Robert Luke", + "Sena": "Sena Er", # 11029 + "TzionaN": "Tziona NessAiver", # 10953 + "Valerii": "Valerii Chirkov", # 9043 + "Zhenya": "Evgenii Kalenkovich", # 6310, TODO: Check +} + + +def _good_name(name): + if name is None: + return False + assert isinstance(name, str), type(name) + if not name.strip(): + return False + if " " not in name and name not in single_names: # at least two parts + return False + if name not in abbreviations and "." in name.split()[0] or "." in name.split()[-1]: + return False + if " " in name and name not in abbreviations: + first = name.split()[0] + last = name.split()[-1] + if first == first.upper() or last == last.upper(): # e.g., KING instead of King + return False + return True + + +@verbose +def generate_credit_rst(app=None, *, verbose=False): + """Get the credit RST.""" + sphinx_logger.info("Creating code credit RST inclusion file") + ignores = [ + int(ignore.split("#", maxsplit=1)[1].strip().split()[0][:-1]) + for ignore in (repo_root / ".git-blame-ignore-revs") + .read_text("utf-8") + .splitlines() + if not ignore.strip().startswith("#") and ignore.strip() + ] + ignores = {str(ig): [] for ig in ignores} + + # Use mailmap to help translate emails to names + mailmap = dict() + # mapping from email to name + name_map: dict[str, str] = dict() + for line in (repo_root / ".mailmap").read_text("utf-8").splitlines(): + name = re.match("^([^<]+) <([^<>]+)>", line.strip()).group(1) + assert _good_name(name), repr(name) + emails = list(re.findall("<([^<>]+)>", line.strip())) + assert len(emails) > 0 + new = emails[0] + if new in name_map: + assert name_map[new] == name + else: + name_map[new] = name + if len(emails) == 1: + continue + for old in emails[1:]: + if old in mailmap: + assert new == mailmap[old] # can be different names + else: + mailmap[old] = new + if old in name_map: + assert name_map[old] == name + else: + name_map[old] = name + + unknown_emails: set[str] = set() + + # dict with (name, commit) keys, values are int change counts + # ("commits" is really "PRs" for Python mode) + commits: dict[tuple[str], int] = defaultdict(lambda: 0) + + # dict with filename keys, values are dicts with name keys and +/- ndarrays + stats: dict[str, dict[str, np.ndarray]] = defaultdict( + lambda: defaultdict( + lambda: np.zeros(2, int), + ), + ) + + bad_commits = set() + expected_bad_names = dict() + + for fname in sorted(glob.glob(str(data_dir / "prs" / "*.json"))): + commit = Path(fname).stem # PR number is in the filename + data = json.loads(Path(fname).read_text("utf-8")) + del fname + assert data != {} + authors = data["authors"] + for author in authors: + if ( + author["e"] is not None + and author["e"] not in name_map + and _good_name(author["n"]) + ): + name_map[author["e"]] = author["n"] + for file, counts in data["changes"].items(): + if commit in ignores: + ignores[commit].append([file, commit]) + continue + p, m = counts["a"], counts["d"] + used_authors = set() + for author in authors: + if author["e"] is not None: + if author["e"] not in name_map: + unknown_emails.add( + f'{author["e"].ljust(29)} ' + "https://github.com/mne-tools/mne-python/pull/" + f"{commit}/files" + ) + continue + name = name_map[author["e"]] + else: + name = author["n"] + if name in manual_renames: + assert _good_name( + manual_renames[name] + ), f"Bad manual rename: {name}" + name = manual_renames[name] + if " " in name: + first, last = name.rsplit(" ", maxsplit=1) + if last == last.upper() and len(last) > 1: + last = last.capitalize() + if first == first.upper() and len(first) > 1: + first = first.capitalize() + name = f"{first} {last}" + assert not first.upper() == first, f"Bad {name=} from {commit}" + assert _good_name(name), f"Bad {name=} from {commit}" + if "King" in name: + assert name == "Jean-Rémi King", name + + if name is None: + bad_commits.add(commit) + continue + if name in used_authors: + continue + if not _good_name(name) and name not in expected_bad_names: + expected_bad_names[name] = f"{name} from #{commit}" + if author["e"]: + expected_bad_names[name] += f" email {author['e']}" + assert name.strip(), repr(name) + used_authors.add(name) + # treat moves and permission changes like a single-line change + if p == m == 0: + p = 1 + commits[(name, commit)] += p + m + stats[file][name] += [p, m] + if bad_commits: + raise RuntimeError( + "Run:\nrm " + + " ".join(f"{bad}.json" for bad in sorted(bad_commits, key=int)) + ) + + # Check for duplicate names based on last name, and also singleton names. + # Below are surnames where we have more than one distinct contributor: + name_counts = dict( + Das=2, + Drew=2, + Li=2, + Peterson=2, + Wong=2, + Zhang=2, + ) + # Below are allowed singleton names + last_map = defaultdict(lambda: set()) + bad_names = set() + for these_stats in stats.values(): + for name in these_stats: + assert name == name.strip(), f"Un-stripped name: {repr(name)}" + last = name.split()[-1] + first = name.split()[0] + last_map[last].add(name) + name_where = expected_bad_names.get(name, name) + if last == name and name not in single_names: + bad_names.add(f"Singleton: {name_where}") + if "." in last or "." in first and name not in abbreviations: + bad_names.add(f"Abbreviation: {name_where}") + bad_names = sorted(bad_names) + for last, names in last_map.items(): + if len(names) > name_counts.get(last, 1): + bad_names.append(f"Duplicates: {sorted(names)}") + if bad_names: + raise RuntimeError( + "Unexpected possible duplicates or bad names found:\n" + + "\n".join(bad_names) + ) + + unknown_emails = set( + email + for email in unknown_emails + if "autofix-ci[bot]" not in email + and "pre-commit-ci[bot]" not in email + and "dependabot[bot]" not in email + and "github-actions[bot]" not in email + ) + assert len(unknown_emails) == 0, "Unknown emails\n" + "\n".join( + sorted(unknown_emails) + ) + + logger.info("Biggest included commits/PRs:") + commits = dict( + (k, commits[k]) + for k in sorted(commits, key=lambda k_: commits[k_], reverse=True) + ) + for ni, name in enumerate(commits, 1): + if ni > 10: + break + logger.info(f"{str(name[1]).ljust(5)} @ {commits[name]:5d} by {name[0]}") + + logger.info("\nIgnored commits:") + # Report the ignores + for commit in ignores: # should have found one of each + logger.info(f"ignored {len(ignores[commit]):3d} files for {commit}") + assert len(ignores[commit]) >= 1, (ignores[commit], commit) + globs = dict() + + # This is the mapping from changed filename globs to module names on the website. + # We need to include aliases for old stuff. Anything we want to exclude we put in + # "null" with a higher priority (i.e., in dict first): + link_overrides = dict() # overrides for links + for key in """ + *.qrc *.png *.svg *.ico *.elc *.sfp *.lout *.lay *.csd *.txt + mne/_version.py mne/externals/* */__init__.py* */resources.py paper.bib + mne/html/*.css mne/html/*.js mne/io/bti/tests/data/* */SHA1SUMS *__init__py + AUTHORS.rst CITATION.cff CONTRIBUTING.rst codemeta.json mne/tests/*.* jr-tools + */whats_new.rst */latest.inc */devel.rst */changelog.rst */manual/* doc/*.json + logo/LICENSE doc/credit.rst + """.strip().split(): + globs[key] = "null" + # Now onto the actual module organization + root_path = pathlib.Path(mne.__file__).parent + mod_file_map = dict() + for file in root_path.iterdir(): + rel = file.relative_to(root_path).with_suffix("") + mod = f"mne.{rel}" + if file.is_dir(): + globs[f"mne/{rel}/*.*"] = mod + globs[f"mne/{rel}.*"] = mod + elif file.is_file() and file.suffix == ".py": + key = f"mne/{rel}.py" + if file.stem == "conftest": + globs[key] = "maintenance" + globs["conftest.py"] = "maintenance" + else: + globs[key] = mod + mod_file_map[mod] = key + globs["mne/artifacts/*.py"] = "mne.preprocessing" + for key in """ + pick.py constants.py info.py fiff/*.* _fiff/*.* raw.py testing.py _hdf5.py + compensator.py + """.strip().split(): + globs[f"mne/{key}"] = "mne.io" + for key in ("mne/transforms/*.py", "mne/_freesurfer.py"): + globs[key] = "mne.transforms" + globs["mne/mixed_norm/*.py"] = "mne.inverse_sparse" + globs["mne/__main__.py"] = "mne.commands" + globs["bin/*"] = "mne.commands" + globs["mne/morph_map.py"] = "mne.surface" + globs["mne/baseline.py"] = "mne.epochs" + for key in """ + parallel.py rank.py misc.py data/*.* defaults.py fixes.py icons/*.* icons.* + """.strip().split(): + globs[f"mne/{key}"] = "mne.utils" + for key in ("mne/_ola.py", "mne/cuda.py"): + globs[key] = "mne.filter" + for key in """ + *digitization/*.py layouts/*.py montages/*.py selection.py + """.strip().split(): + globs[f"mne/{key}"] = "mne.channels" + globs["mne/sparse_learning/*.py"] = "mne.inverse_sparse" + globs["mne/csp.py"] = "mne.preprocessing" + globs["mne/bem_surfaces.py"] = "mne.bem" + globs["mne/coreg/*.py"] = "mne.coreg" + globs["mne/inverse.py"] = "mne.minimum_norm" + globs["mne/stc.py"] = "mne.source_estimate" + globs["mne/surfer.py"] = "mne.viz" + globs["mne/tfr.py"] = "mne.time_frequency" + globs["mne/connectivity/*.py"] = "mne-connectivity (moved)" + link_overrides["mne-connectivity (moved)"] = "mne-tools/mne-connectivity" + globs["mne/realtime/*.py"] = "mne-realtime (moved)" + link_overrides["mne-realtime (moved)"] = "mne-tools/mne-realtime" + globs["mne/html_templates/*.*"] = "mne.report" + globs[".circleci/*"] = "maintenance" + link_overrides["maintenance"] = "mne-tools/mne-python" + globs["tools/*"] = "maintenance" + globs["doc/*"] = "doc" + for key in ("*.py", "*.rst"): + for mod in ("examples", "tutorials", "doc"): + globs[f"{mod}/{key}"] = mod + for key in """ + *.yml *.md setup.* MANIFEST.in Makefile README.rst flow_diagram.py *.toml + debian/* logo/*.py *.git* .pre-commit-config.yaml .mailmap .coveragerc make/* + """.strip().split(): + globs[key] = "maintenance" + + mod_stats = defaultdict(lambda: defaultdict(lambda: np.zeros(2, int))) + other_files = set() + total_lines = np.zeros(2, int) + for fname, counts in stats.items(): + for pattern, mod in globs.items(): + if glob.fnmatch.fnmatch(fname, pattern): + break + else: + other_files.add(fname) + mod = "other" + for e, pm in counts.items(): + if mod == "mne._fiff": + raise RuntimeError + # sanity check a bit + if mod != "null" and (".png" in fname or "/manual/" in fname): + raise RuntimeError(f"Unexpected {mod} {fname}") + mod_stats[mod][e] += pm + mod_stats["mne"][e] += pm + total_lines += pm + mod_stats.pop("null") # stuff we shouldn't give credit for + mod_stats = dict( + (k, mod_stats[k]) + for k in sorted( + mod_stats, + key=lambda x: ( + not x.startswith("mne"), + x == "maintenance", + x.replace("-", "."), + ), + ) + ) # sort modules alphabetically + other_files = sorted(other_files) + if len(other_files): + raise RuntimeError( + f"{len(other_files)} misc file(s) found:\n" + "\n".join(other_files) + ) + logger.info(f"\nTotal line change count: {list(total_lines)}") + + # sphinx-design badges that we use for contributors + BADGE_KINDS = ["bdg-info-line", "bdg"] + content = f"""\ +.. THIS FILE IS AUTO-GENERATED BY {Path(__file__).stem} AND WILL BE OVERWRITTEN + +.. raw:: html + + + +.. _code_credit: + +Code credit +=========== + +Below are lists of code contributors to MNE-Python. The numbers in parentheses are the +number of lines changed in our code history. + +- :{BADGE_KINDS[0]}:`This badge` is used for the top 10% of contributors. +- :{BADGE_KINDS[1]}:`This badge` is used for the remaining 90% of contributors. + +Entire codebase +--------------- + +""" + for mi, (mod, counts) in enumerate(mod_stats.items()): + if mi == 0: + assert mod == "mne", mod + indent = " " * 3 + elif mi == 1: + indent = " " * 6 + content += """ + +By submodule +------------ + +Contributors often have domain-specific expertise, so we've broken down the +contributions by submodule as well below. + +.. grid:: 1 2 3 3 + :gutter: 1 + +""" + # if there are 10 this is 100, if there are 100 this is 100 + these_stats = dict((k, v.sum()) for k, v in counts.items()) + these_stats = dict( + (k, these_stats[k]) + for k in sorted(these_stats, key=lambda x: these_stats[x], reverse=True) + ) + if mod in link_overrides: + link = f"https://github.com/{link_overrides[mod]}" + else: + kind = "blame" if mod in mod_file_map else "tree" + link_mod = mod_file_map.get(mod, mod.replace(".", "/")) + link = f"https://github.com/mne-tools/mne-python/{kind}/main/{link_mod}" + assert "moved" not in link, (mod, link) + # Use badges because they flow nicely, inside a grid to make it more compact + stat_lines = [] + for ki, (k, v) in enumerate(these_stats.items()): + # Round to two digits, e.g. 12340 -> 12000, 12560 -> 13000 + v_round = int(float(f"{v:.2g}")) + assert v_round > 0, f"Got zero lines changed for {k} in {mod}: {v_round}" + # And then write as a max-3-char human-readable abbreviation like + # 123, 1.2k, 123k, 12m, etc. + for prefix in ("", "k", "m", "g"): + if v_round >= 1000: + v_round = v_round / 1000 + else: + if v_round >= 10 or prefix == "": # keep single digit as 1 not 1.0 + v_round = f"{int(round(v_round))}" + else: + v_round = f"{v_round:.1f}" + v_round += prefix + break + else: + raise RuntimeError(f"Too many digits in {v}") + idx = 0 if ki < (len(these_stats) - 1) // 10 + 1 else 1 + if any(b in k for b in ("[bot]", "Lumberbot", "Deleted user")): + continue + assert _good_name(k) + stat_lines.append(f":{BADGE_KINDS[idx]}:`{k} ({v_round})`") + stat_lines = f"\n{indent}".join(stat_lines) + if mi == 0: + content += f""" + +.. card:: {mod} + :class-card: overflow-auto + :link: https://github.com/mne-tools/mne-python/graphs/contributors + +{indent}{stat_lines} + +""" + else: + content += f""" + + .. grid-item-card:: {mod} + :class-card: overflow-auto + :link: {link} + +{indent}{stat_lines} + +""" + (doc_root / "code_credit.inc").write_text(content, encoding="utf-8") + + +if __name__ == "__main__": + generate_credit_rst(verbose=True) diff --git a/doc/sphinxext/flow_diagram.py b/doc/sphinxext/flow_diagram.py index e8194d2063f..3b6007c6595 100644 --- a/doc/sphinxext/flow_diagram.py +++ b/doc/sphinxext/flow_diagram.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os from os import path as op diff --git a/doc/sphinxext/gen_commands.py b/doc/sphinxext/gen_commands.py index c369bba6db0..9e9d04eca08 100644 --- a/doc/sphinxext/gen_commands.py +++ b/doc/sphinxext/gen_commands.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import glob from importlib import import_module from pathlib import Path diff --git a/doc/sphinxext/gen_names.py b/doc/sphinxext/gen_names.py index fd667ec0951..24212dd7a9b 100644 --- a/doc/sphinxext/gen_names.py +++ b/doc/sphinxext/gen_names.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os from os import path as op diff --git a/doc/sphinxext/gh_substitutions.py b/doc/sphinxext/gh_substitutions.py index 890a71f1c47..467e93c5470 100644 --- a/doc/sphinxext/gh_substitutions.py +++ b/doc/sphinxext/gh_substitutions.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from docutils.nodes import reference from docutils.parsers.rst.roles import set_classes diff --git a/doc/sphinxext/mne_doc_utils.py b/doc/sphinxext/mne_doc_utils.py index 26fa7a9a393..4811cde5f44 100644 --- a/doc/sphinxext/mne_doc_utils.py +++ b/doc/sphinxext/mne_doc_utils.py @@ -1,5 +1,9 @@ """Doc building utils.""" +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + import gc import os import time @@ -7,6 +11,7 @@ import numpy as np import pyvista +import sphinx.util.logging import mne from mne.utils import ( @@ -15,6 +20,7 @@ ) from mne.viz import Brain +sphinx_logger = sphinx.util.logging.getLogger("mne") _np_print_defaults = np.get_printoptions() @@ -155,6 +161,11 @@ def reset_warnings(gallery_conf, fname): "A worker stopped while some jobs were given to the executor.*", category=UserWarning, ) + # neo + warnings.filterwarnings( + "ignore", + "The 'copy' argument in Quantity is deprecated.*", + ) # In case we use np.set_printoptions in any tutorials, we only # want it to affect those: diff --git a/doc/sphinxext/mne_substitutions.py b/doc/sphinxext/mne_substitutions.py index 0c4f9a2f3dd..df23dbc9103 100644 --- a/doc/sphinxext/mne_substitutions.py +++ b/doc/sphinxext/mne_substitutions.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from docutils import nodes from docutils.parsers.rst import Directive from docutils.statemachine import StringList diff --git a/doc/sphinxext/newcontrib_substitutions.py b/doc/sphinxext/newcontrib_substitutions.py index c38aeb86219..85feae1ad89 100644 --- a/doc/sphinxext/newcontrib_substitutions.py +++ b/doc/sphinxext/newcontrib_substitutions.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from docutils.nodes import reference, strong, target diff --git a/doc/sphinxext/prs/12747.json b/doc/sphinxext/prs/12747.json new file mode 100644 index 00000000000..648e05d3afc --- /dev/null +++ b/doc/sphinxext/prs/12747.json @@ -0,0 +1,47 @@ +{ + "merge_commit_sha": "b08f759efd08fa060e68f0bdee45f45e3fc5347a", + "authors": [ + { + "n": "Thomas S. Binns", + "e": "t.s.binns@outlook.com" + }, + { + "n": "pre-commit-ci[bot]", + "e": "66853113+pre-commit-ci[bot]@users.noreply.github.com" + }, + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + }, + { + "n": "Daniel McCloy", + "e": "dan@mccloy.info" + }, + { + "n": "Alex Rockhill", + "e": "aprockhill@mailbox.org" + } + ], + "changes": { + "doc/changes/devel/12747.newfeature.rst": { + "a": 3, + "d": 0 + }, + "mne/time_frequency/spectrum.py": { + "a": 202, + "d": 70 + }, + "mne/time_frequency/tests/test_spectrum.py": { + "a": 294, + "d": 32 + }, + "mne/utils/docs.py": { + "a": 8, + "d": 4 + }, + "mne/utils/spectrum.py": { + "a": 4, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12774.json b/doc/sphinxext/prs/12774.json new file mode 100644 index 00000000000..8bc18f8e221 --- /dev/null +++ b/doc/sphinxext/prs/12774.json @@ -0,0 +1,103 @@ +{ + "merge_commit_sha": "879361513bdd1c14ca4e223657517fe85b6085b0", + "authors": [ + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + ".circleci/config.yml": { + "a": 1, + "d": 5 + }, + ".git-blame-ignore-revs": { + "a": 14, + "d": 7 + }, + ".github/workflows/credit.yml": { + "a": 43, + "d": 0 + }, + ".gitignore": { + "a": 1, + "d": 1 + }, + ".mailmap": { + "a": 73, + "d": 34 + }, + ".pre-commit-config.yaml": { + "a": 8, + "d": 5 + }, + "doc/.gitignore": { + "a": 1, + "d": 0 + }, + "doc/Makefile": { + "a": 1, + "d": 4 + }, + "doc/_templates/sidebar-quicklinks.html": { + "a": 1, + "d": 0 + }, + "doc/changes/devel/12774.other.rst": { + "a": 2, + "d": 0 + }, + "doc/conf.py": { + "a": 3, + "d": 0 + }, + "doc/credit.rst": { + "a": 12, + "d": 0 + }, + "doc/sphinxext/prs/12779.json": { + "a": 19, + "d": 0 + }, + "doc/sphinxext/update_credit_rst.py": { + "a": 425, + "d": 0 + }, + "ignore_words.txt": { + "a": 1, + "d": 0 + }, + "pyproject.toml": { + "a": 3, + "d": 0 + }, + "tools/check_mne_location.py": { + "a": 1, + "d": 0 + }, + "tools/dev/check_steering_committee.py": { + "a": 3, + "d": 2 + }, + "tools/dev/ensure_headers.py": { + "a": 1, + "d": 0 + }, + "tools/dev/gen_css_for_mne.py": { + "a": 2, + "d": 1 + }, + "tools/dev/generate_pyi_files.py": { + "a": 1, + "d": 0 + }, + "tools/dev/update_credit_json.py": { + "a": 88, + "d": 0 + }, + "tools/generate_codemeta.py": { + "a": 2, + "d": 1 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12778.json b/doc/sphinxext/prs/12778.json new file mode 100644 index 00000000000..995d907f6ae --- /dev/null +++ b/doc/sphinxext/prs/12778.json @@ -0,0 +1,31 @@ +{ + "merge_commit_sha": "6da505591cd76bc7f6579154475c4abb2a5cbb95", + "authors": [ + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + "doc/sphinxext/contrib_avatars.py": { + "a": 4, + "d": 1 + }, + "doc/sphinxext/gen_commands.py": { + "a": 1, + "d": 14 + }, + "mne/utils/__init__.pyi": { + "a": 2, + "d": 0 + }, + "mne/utils/numerics.py": { + "a": 13, + "d": 0 + }, + "mne/utils/tests/test_numerics.py": { + "a": 18, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12779.json b/doc/sphinxext/prs/12779.json new file mode 100644 index 00000000000..584d8132188 --- /dev/null +++ b/doc/sphinxext/prs/12779.json @@ -0,0 +1,19 @@ +{ + "merge_commit_sha": "b8b168088cb474f27833f5f9db9d60abe00dca83", + "authors": [ + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + "doc/sphinxext/prs/1.json": { + "a": 15, + "d": 0 + }, + "doc/sphinxext/prs/3732.json": { + "a": 15, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12781.json b/doc/sphinxext/prs/12781.json new file mode 100644 index 00000000000..a2b21519710 --- /dev/null +++ b/doc/sphinxext/prs/12781.json @@ -0,0 +1,2911 @@ +{ + "merge_commit_sha": "ee64eba6f345e895e3d5e7d2804fa6aa2dac2e6d", + "authors": [ + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + }, + { + "n": "autofix-ci[bot]", + "e": "114827586+autofix-ci[bot]@users.noreply.github.com" + } + ], + "changes": { + ".github/actions/rename_towncrier/rename_towncrier.py": { + "a": 4, + "d": 0 + }, + ".github/workflows/autofix.yml": { + "a": 3, + "d": 2 + }, + ".github/workflows/credit.yml": { + "a": 0, + "d": 1 + }, + "azure-pipelines.yml": { + "a": 1, + "d": 1 + }, + "doc/changes/devel/12781.other.rst": { + "a": 1, + "d": 0 + }, + "doc/conf.py": { + "a": 8, + "d": 5 + }, + "doc/conftest.py": { + "a": 2, + "d": 0 + }, + "doc/sphinxext/contrib_avatars.py": { + "a": 2, + "d": 0 + }, + "doc/sphinxext/flow_diagram.py": { + "a": 2, + "d": 0 + }, + "doc/sphinxext/gen_commands.py": { + "a": 2, + "d": 0 + }, + "doc/sphinxext/gen_names.py": { + "a": 2, + "d": 0 + }, + "doc/sphinxext/gh_substitutions.py": { + "a": 2, + "d": 0 + }, + "doc/sphinxext/mne_doc_utils.py": { + "a": 4, + "d": 0 + }, + "doc/sphinxext/mne_substitutions.py": { + "a": 2, + "d": 0 + }, + "doc/sphinxext/newcontrib_substitutions.py": { + "a": 2, + "d": 0 + }, + "doc/sphinxext/related_software.py": { + "a": 4, + "d": 0 + }, + "doc/sphinxext/unit_role.py": { + "a": 2, + "d": 0 + }, + "doc/sphinxext/update_credit_rst.py": { + "a": 4, + "d": 0 + }, + "examples/datasets/kernel_phantom.py": { + "a": 2, + "d": 0 + }, + "examples/datasets/opm_data.py": { + "a": 2, + "d": 0 + }, + "examples/inverse/custom_inverse_solver.py": { + "a": 2, + "d": 0 + }, + "examples/io/read_neo_format.py": { + "a": 2, + "d": 0 + }, + "examples/preprocessing/contralateral_referencing.py": { + "a": 2, + "d": 0 + }, + "examples/visualization/eyetracking_plot_heatmap.py": { + "a": 2, + "d": 0 + }, + "examples/visualization/mne_helmet.py": { + "a": 2, + "d": 0 + }, + "ignore_words.txt": { + "a": 1, + "d": 0 + }, + "logo/generate_mne_logos.py": { + "a": 1, + "d": 2 + }, + "mne/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/__main__.py": { + "a": 1, + "d": 1 + }, + "mne/_fiff/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/_fiff/_digitization.py": { + "a": 1, + "d": 6 + }, + "mne/_fiff/compensator.py": { + "a": 2, + "d": 0 + }, + "mne/_fiff/constants.py": { + "a": 1, + "d": 3 + }, + "mne/_fiff/ctf_comp.py": { + "a": 1, + "d": 4 + }, + "mne/_fiff/matrix.py": { + "a": 1, + "d": 3 + }, + "mne/_fiff/meas_info.py": { + "a": 1, + "d": 5 + }, + "mne/_fiff/open.py": { + "a": 1, + "d": 3 + }, + "mne/_fiff/pick.py": { + "a": 1, + "d": 4 + }, + "mne/_fiff/proc_history.py": { + "a": 1, + "d": 2 + }, + "mne/_fiff/proj.py": { + "a": 1, + "d": 5 + }, + "mne/_fiff/reference.py": { + "a": 1, + "d": 4 + }, + "mne/_fiff/tag.py": { + "a": 1, + "d": 3 + }, + "mne/_fiff/tests/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/_fiff/tests/test_compensator.py": { + "a": 1, + "d": 2 + }, + "mne/_fiff/tests/test_constants.py": { + "a": 1, + "d": 2 + }, + "mne/_fiff/tests/test_meas_info.py": { + "a": 1, + "d": 3 + }, + "mne/_fiff/tests/test_pick.py": { + "a": 2, + "d": 0 + }, + "mne/_fiff/tests/test_proc_history.py": { + "a": 1, + "d": 2 + }, + "mne/_fiff/tests/test_reference.py": { + "a": 1, + "d": 4 + }, + "mne/_fiff/tests/test_show_fiff.py": { + "a": 1, + "d": 2 + }, + "mne/_fiff/tests/test_utils.py": { + "a": 2, + "d": 2 + }, + "mne/_fiff/tests/test_what.py": { + "a": 1, + "d": 1 + }, + "mne/_fiff/tests/test_write.py": { + "a": 2, + "d": 2 + }, + "mne/_fiff/tree.py": { + "a": 1, + "d": 3 + }, + "mne/_fiff/utils.py": { + "a": 1, + "d": 9 + }, + "mne/_fiff/what.py": { + "a": 1, + "d": 2 + }, + "mne/_fiff/write.py": { + "a": 1, + "d": 3 + }, + "mne/_freesurfer.py": { + "a": 2, + "d": 3 + }, + "mne/_ola.py": { + "a": 1, + "d": 2 + }, + "mne/annotations.py": { + "a": 1, + "d": 3 + }, + "mne/baseline.py": { + "a": 1, + "d": 2 + }, + "mne/beamformer/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/beamformer/_compute_beamformer.py": { + "a": 1, + "d": 4 + }, + "mne/beamformer/_dics.py": { + "a": 2, + "d": 5 + }, + "mne/beamformer/_lcmv.py": { + "a": 2, + "d": 4 + }, + "mne/beamformer/_rap_music.py": { + "a": 1, + "d": 3 + }, + "mne/beamformer/resolution_matrix.py": { + "a": 2, + "d": 2 + }, + "mne/beamformer/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/beamformer/tests/test_dics.py": { + "a": 1, + "d": 3 + }, + "mne/beamformer/tests/test_external.py": { + "a": 1, + "d": 2 + }, + "mne/beamformer/tests/test_lcmv.py": { + "a": 2, + "d": 0 + }, + "mne/beamformer/tests/test_rap_music.py": { + "a": 1, + "d": 3 + }, + "mne/beamformer/tests/test_resolution_matrix.py": { + "a": 2, + "d": 2 + }, + "mne/bem.py": { + "a": 1, + "d": 5 + }, + "mne/channels/__init__.py": { + "a": 3, + "d": 0 + }, + "mne/channels/_dig_montage_utils.py": { + "a": 1, + "d": 11 + }, + "mne/channels/_standard_montage_utils.py": { + "a": 2, + "d": 3 + }, + "mne/channels/channels.py": { + "a": 1, + "d": 10 + }, + "mne/channels/data/neighbors/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/channels/interpolation.py": { + "a": 1, + "d": 3 + }, + "mne/channels/layout.py": { + "a": 1, + "d": 9 + }, + "mne/channels/montage.py": { + "a": 1, + "d": 11 + }, + "mne/channels/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/channels/tests/test_channels.py": { + "a": 1, + "d": 3 + }, + "mne/channels/tests/test_interpolation.py": { + "a": 2, + "d": 0 + }, + "mne/channels/tests/test_layout.py": { + "a": 1, + "d": 5 + }, + "mne/channels/tests/test_montage.py": { + "a": 1, + "d": 3 + }, + "mne/channels/tests/test_standard_montage.py": { + "a": 1, + "d": 3 + }, + "mne/channels/tests/test_unify_bads.py": { + "a": 2, + "d": 0 + }, + "mne/chpi.py": { + "a": 18, + "d": 18 + }, + "mne/commands/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/commands/mne_anonymize.py": { + "a": 1, + "d": 3 + }, + "mne/commands/mne_browse_raw.py": { + "a": 1, + "d": 2 + }, + "mne/commands/mne_bti2fiff.py": { + "a": 3, + "d": 10 + }, + "mne/commands/mne_clean_eog_ecg.py": { + "a": 2, + "d": 4 + }, + "mne/commands/mne_compare_fiff.py": { + "a": 1, + "d": 2 + }, + "mne/commands/mne_compute_proj_ecg.py": { + "a": 2, + "d": 3 + }, + "mne/commands/mne_compute_proj_eog.py": { + "a": 2, + "d": 3 + }, + "mne/commands/mne_coreg.py": { + "a": 1, + "d": 2 + }, + "mne/commands/mne_flash_bem.py": { + "a": 2, + "d": 3 + }, + "mne/commands/mne_freeview_bem_surfaces.py": { + "a": 2, + "d": 2 + }, + "mne/commands/mne_kit2fiff.py": { + "a": 1, + "d": 2 + }, + "mne/commands/mne_make_scalp_surfaces.py": { + "a": 1, + "d": 7 + }, + "mne/commands/mne_prepare_bem_model.py": { + "a": 2, + "d": 1 + }, + "mne/commands/mne_report.py": { + "a": 2, + "d": 1 + }, + "mne/commands/mne_setup_forward_model.py": { + "a": 2, + "d": 1 + }, + "mne/commands/mne_setup_source_space.py": { + "a": 2, + "d": 1 + }, + "mne/commands/mne_show_fiff.py": { + "a": 1, + "d": 2 + }, + "mne/commands/mne_show_info.py": { + "a": 1, + "d": 2 + }, + "mne/commands/mne_surf2bem.py": { + "a": 2, + "d": 3 + }, + "mne/commands/mne_sys_info.py": { + "a": 1, + "d": 2 + }, + "mne/commands/mne_watershed_bem.py": { + "a": 2, + "d": 2 + }, + "mne/commands/mne_what.py": { + "a": 1, + "d": 2 + }, + "mne/commands/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/commands/tests/test_commands.py": { + "a": 2, + "d": 0 + }, + "mne/commands/utils.py": { + "a": 1, + "d": 3 + }, + "mne/conftest.py": { + "a": 1, + "d": 2 + }, + "mne/coreg.py": { + "a": 1, + "d": 2 + }, + "mne/cov.py": { + "a": 1, + "d": 4 + }, + "mne/cuda.py": { + "a": 1, + "d": 2 + }, + "mne/data/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/__init__.py": { + "a": 3, + "d": 0 + }, + "mne/datasets/_fake/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/_fake/_fake.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/_fetch.py": { + "a": 1, + "d": 2 + }, + "mne/datasets/_fsaverage/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/datasets/_fsaverage/base.py": { + "a": 1, + "d": 1 + }, + "mne/datasets/_infant/__init__.py": { + "a": 4, + "d": 0 + }, + "mne/datasets/_infant/base.py": { + "a": 1, + "d": 1 + }, + "mne/datasets/_phantom/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/datasets/_phantom/base.py": { + "a": 1, + "d": 1 + }, + "mne/datasets/brainstorm/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/brainstorm/bst_auditory.py": { + "a": 2, + "d": 2 + }, + "mne/datasets/brainstorm/bst_phantom_ctf.py": { + "a": 2, + "d": 2 + }, + "mne/datasets/brainstorm/bst_phantom_elekta.py": { + "a": 2, + "d": 2 + }, + "mne/datasets/brainstorm/bst_raw.py": { + "a": 2, + "d": 2 + }, + "mne/datasets/brainstorm/bst_resting.py": { + "a": 2, + "d": 2 + }, + "mne/datasets/config.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/eegbci/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/eegbci/eegbci.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/eegbci/tests/test_eegbci.py": { + "a": 1, + "d": 2 + }, + "mne/datasets/epilepsy_ecog/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/epilepsy_ecog/_data.py": { + "a": 1, + "d": 2 + }, + "mne/datasets/erp_core/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/erp_core/erp_core.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/eyelink/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/eyelink/eyelink.py": { + "a": 1, + "d": 1 + }, + "mne/datasets/fieldtrip_cmc/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/fieldtrip_cmc/fieldtrip_cmc.py": { + "a": 2, + "d": 3 + }, + "mne/datasets/fnirs_motor/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/fnirs_motor/fnirs_motor.py": { + "a": 1, + "d": 1 + }, + "mne/datasets/hf_sef/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/hf_sef/hf_sef.py": { + "a": 2, + "d": 1 + }, + "mne/datasets/kiloword/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/kiloword/kiloword.py": { + "a": 1, + "d": 0 + }, + "mne/datasets/limo/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/limo/limo.py": { + "a": 1, + "d": 2 + }, + "mne/datasets/misc/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/misc/_misc.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/mtrf/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/mtrf/mtrf.py": { + "a": 1, + "d": 2 + }, + "mne/datasets/multimodal/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/multimodal/multimodal.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/opm/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/opm/opm.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/phantom_4dbti/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/phantom_4dbti/phantom_4dbti.py": { + "a": 1, + "d": 2 + }, + "mne/datasets/phantom_kernel/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/phantom_kernel/phantom_kernel.py": { + "a": 1, + "d": 2 + }, + "mne/datasets/phantom_kit/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/phantom_kit/phantom_kit.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/refmeg_noise/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/refmeg_noise/refmeg_noise.py": { + "a": 1, + "d": 1 + }, + "mne/datasets/sample/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/sample/sample.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/sleep_physionet/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/sleep_physionet/_utils.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/sleep_physionet/age.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/sleep_physionet/temazepam.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/sleep_physionet/tests/test_physionet.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/somato/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/somato/somato.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/spm_face/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/spm_face/spm_data.py": { + "a": 1, + "d": 2 + }, + "mne/datasets/ssvep/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/ssvep/ssvep.py": { + "a": 1, + "d": 1 + }, + "mne/datasets/testing/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/testing/_testing.py": { + "a": 1, + "d": 3 + }, + "mne/datasets/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/datasets/tests/test_datasets.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/ucl_opm_auditory/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/ucl_opm_auditory/ucl_opm_auditory.py": { + "a": 1, + "d": 1 + }, + "mne/datasets/utils.py": { + "a": 1, + "d": 8 + }, + "mne/datasets/visual_92_categories/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/datasets/visual_92_categories/visual_92_categories.py": { + "a": 1, + "d": 0 + }, + "mne/decoding/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/decoding/base.py": { + "a": 2, + "d": 5 + }, + "mne/decoding/csp.py": { + "a": 1, + "d": 6 + }, + "mne/decoding/ems.py": { + "a": 1, + "d": 4 + }, + "mne/decoding/mixin.py": { + "a": 3, + "d": 0 + }, + "mne/decoding/receptive_field.py": { + "a": 1, + "d": 3 + }, + "mne/decoding/search_light.py": { + "a": 2, + "d": 2 + }, + "mne/decoding/ssd.py": { + "a": 1, + "d": 3 + }, + "mne/decoding/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/decoding/tests/test_base.py": { + "a": 1, + "d": 3 + }, + "mne/decoding/tests/test_csp.py": { + "a": 1, + "d": 5 + }, + "mne/decoding/tests/test_ems.py": { + "a": 1, + "d": 2 + }, + "mne/decoding/tests/test_receptive_field.py": { + "a": 1, + "d": 2 + }, + "mne/decoding/tests/test_search_light.py": { + "a": 1, + "d": 2 + }, + "mne/decoding/tests/test_ssd.py": { + "a": 1, + "d": 3 + }, + "mne/decoding/tests/test_time_frequency.py": { + "a": 1, + "d": 2 + }, + "mne/decoding/tests/test_transformer.py": { + "a": 1, + "d": 3 + }, + "mne/decoding/time_delaying_ridge.py": { + "a": 2, + "d": 3 + }, + "mne/decoding/time_frequency.py": { + "a": 1, + "d": 2 + }, + "mne/decoding/transformer.py": { + "a": 1, + "d": 4 + }, + "mne/defaults.py": { + "a": 1, + "d": 4 + }, + "mne/dipole.py": { + "a": 1, + "d": 3 + }, + "mne/epochs.py": { + "a": 1, + "d": 7 + }, + "mne/event.py": { + "a": 1, + "d": 5 + }, + "mne/evoked.py": { + "a": 1, + "d": 7 + }, + "mne/export/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/export/_brainvision.py": { + "a": 1, + "d": 2 + }, + "mne/export/_edf.py": { + "a": 1, + "d": 2 + }, + "mne/export/_eeglab.py": { + "a": 1, + "d": 2 + }, + "mne/export/_egimff.py": { + "a": 1, + "d": 2 + }, + "mne/export/_export.py": { + "a": 1, + "d": 2 + }, + "mne/export/tests/test_export.py": { + "a": 2, + "d": 2 + }, + "mne/filter.py": { + "a": 2, + "d": 0 + }, + "mne/fixes.py": { + "a": 2, + "d": 4 + }, + "mne/forward/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/forward/_compute_forward.py": { + "a": 1, + "d": 6 + }, + "mne/forward/_field_interpolation.py": { + "a": 1, + "d": 3 + }, + "mne/forward/_lead_dots.py": { + "a": 1, + "d": 4 + }, + "mne/forward/_make_forward.py": { + "a": 1, + "d": 5 + }, + "mne/forward/forward.py": { + "a": 1, + "d": 4 + }, + "mne/forward/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/forward/tests/test_field_interpolation.py": { + "a": 2, + "d": 0 + }, + "mne/forward/tests/test_forward.py": { + "a": 2, + "d": 0 + }, + "mne/forward/tests/test_make_forward.py": { + "a": 7, + "d": 1 + }, + "mne/gui/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/gui/_coreg.py": { + "a": 2, + "d": 0 + }, + "mne/gui/_gui.py": { + "a": 1, + "d": 2 + }, + "mne/gui/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/gui/tests/test_coreg.py": { + "a": 1, + "d": 2 + }, + "mne/gui/tests/test_gui_api.py": { + "a": 1, + "d": 2 + }, + "mne/html_templates/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/html_templates/_templates.py": { + "a": 1, + "d": 0 + }, + "mne/inverse_sparse/__init__.py": { + "a": 3, + "d": 2 + }, + "mne/inverse_sparse/_gamma_map.py": { + "a": 1, + "d": 2 + }, + "mne/inverse_sparse/mxne_debiasing.py": { + "a": 1, + "d": 3 + }, + "mne/inverse_sparse/mxne_inverse.py": { + "a": 1, + "d": 3 + }, + "mne/inverse_sparse/mxne_optim.py": { + "a": 1, + "d": 3 + }, + "mne/inverse_sparse/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/inverse_sparse/tests/test_gamma_map.py": { + "a": 1, + "d": 2 + }, + "mne/inverse_sparse/tests/test_mxne_debiasing.py": { + "a": 1, + "d": 3 + }, + "mne/inverse_sparse/tests/test_mxne_inverse.py": { + "a": 1, + "d": 3 + }, + "mne/inverse_sparse/tests/test_mxne_optim.py": { + "a": 1, + "d": 3 + }, + "mne/io/__init__.py": { + "a": 3, + "d": 3 + }, + "mne/io/_fiff_wrap.py": { + "a": 1, + "d": 0 + }, + "mne/io/_read_raw.py": { + "a": 1, + "d": 2 + }, + "mne/io/array/__init__.py": { + "a": 1, + "d": 1 + }, + "mne/io/array/array.py": { + "a": 1, + "d": 2 + }, + "mne/io/array/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/array/tests/test_array.py": { + "a": 1, + "d": 2 + }, + "mne/io/artemis123/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/artemis123/artemis123.py": { + "a": 1, + "d": 2 + }, + "mne/io/artemis123/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/artemis123/tests/test_artemis123.py": { + "a": 1, + "d": 2 + }, + "mne/io/artemis123/utils.py": { + "a": 2, + "d": 0 + }, + "mne/io/base.py": { + "a": 1, + "d": 9 + }, + "mne/io/besa/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/besa/besa.py": { + "a": 2, + "d": 0 + }, + "mne/io/besa/tests/test_besa.py": { + "a": 2, + "d": 0 + }, + "mne/io/boxy/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/boxy/boxy.py": { + "a": 1, + "d": 2 + }, + "mne/io/boxy/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/boxy/tests/test_boxy.py": { + "a": 1, + "d": 2 + }, + "mne/io/brainvision/__init__.py": { + "a": 1, + "d": 3 + }, + "mne/io/brainvision/brainvision.py": { + "a": 2, + "d": 8 + }, + "mne/io/brainvision/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/brainvision/tests/test_brainvision.py": { + "a": 2, + "d": 3 + }, + "mne/io/bti/__init__.py": { + "a": 1, + "d": 1 + }, + "mne/io/bti/bti.py": { + "a": 1, + "d": 9 + }, + "mne/io/bti/constants.py": { + "a": 1, + "d": 2 + }, + "mne/io/bti/read.py": { + "a": 1, + "d": 2 + }, + "mne/io/bti/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/bti/tests/test_bti.py": { + "a": 1, + "d": 2 + }, + "mne/io/cnt/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/io/cnt/_utils.py": { + "a": 1, + "d": 2 + }, + "mne/io/cnt/cnt.py": { + "a": 2, + "d": 3 + }, + "mne/io/cnt/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/cnt/tests/test_cnt.py": { + "a": 1, + "d": 3 + }, + "mne/io/constants.py": { + "a": 1, + "d": 2 + }, + "mne/io/ctf/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/ctf/constants.py": { + "a": 1, + "d": 3 + }, + "mne/io/ctf/ctf.py": { + "a": 1, + "d": 3 + }, + "mne/io/ctf/eeg.py": { + "a": 1, + "d": 2 + }, + "mne/io/ctf/hc.py": { + "a": 1, + "d": 2 + }, + "mne/io/ctf/info.py": { + "a": 1, + "d": 2 + }, + "mne/io/ctf/markers.py": { + "a": 1, + "d": 2 + }, + "mne/io/ctf/res4.py": { + "a": 1, + "d": 3 + }, + "mne/io/ctf/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/ctf/tests/test_ctf.py": { + "a": 1, + "d": 2 + }, + "mne/io/ctf/trans.py": { + "a": 1, + "d": 2 + }, + "mne/io/curry/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/curry/curry.py": { + "a": 1, + "d": 4 + }, + "mne/io/curry/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/curry/tests/test_curry.py": { + "a": 1, + "d": 3 + }, + "mne/io/edf/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/edf/edf.py": { + "a": 1, + "d": 8 + }, + "mne/io/edf/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/edf/tests/test_edf.py": { + "a": 1, + "d": 7 + }, + "mne/io/edf/tests/test_gdf.py": { + "a": 1, + "d": 3 + }, + "mne/io/eeglab/__init__.py": { + "a": 1, + "d": 1 + }, + "mne/io/eeglab/_eeglab.py": { + "a": 2, + "d": 0 + }, + "mne/io/eeglab/eeglab.py": { + "a": 1, + "d": 4 + }, + "mne/io/eeglab/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/eeglab/tests/test_eeglab.py": { + "a": 1, + "d": 4 + }, + "mne/io/egi/__init__.py": { + "a": 1, + "d": 1 + }, + "mne/io/egi/egi.py": { + "a": 1, + "d": 4 + }, + "mne/io/egi/egimff.py": { + "a": 2, + "d": 0 + }, + "mne/io/egi/events.py": { + "a": 1, + "d": 0 + }, + "mne/io/egi/general.py": { + "a": 1, + "d": 0 + }, + "mne/io/egi/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/egi/tests/test_egi.py": { + "a": 1, + "d": 2 + }, + "mne/io/eximia/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/eximia/eximia.py": { + "a": 1, + "d": 3 + }, + "mne/io/eximia/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/eximia/tests/test_eximia.py": { + "a": 1, + "d": 2 + }, + "mne/io/eyelink/__init__.py": { + "a": 1, + "d": 3 + }, + "mne/io/eyelink/_utils.py": { + "a": 2, + "d": 1 + }, + "mne/io/eyelink/eyelink.py": { + "a": 1, + "d": 4 + }, + "mne/io/eyelink/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/eyelink/tests/test_eyelink.py": { + "a": 2, + "d": 0 + }, + "mne/io/fieldtrip/__init__.py": { + "a": 1, + "d": 4 + }, + "mne/io/fieldtrip/fieldtrip.py": { + "a": 1, + "d": 4 + }, + "mne/io/fieldtrip/tests/__init__.py": { + "a": 1, + "d": 4 + }, + "mne/io/fieldtrip/tests/helpers.py": { + "a": 2, + "d": 4 + }, + "mne/io/fieldtrip/tests/test_fieldtrip.py": { + "a": 1, + "d": 4 + }, + "mne/io/fieldtrip/utils.py": { + "a": 2, + "d": 4 + }, + "mne/io/fiff/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/io/fiff/raw.py": { + "a": 1, + "d": 6 + }, + "mne/io/fiff/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/fiff/tests/test_raw_fiff.py": { + "a": 1, + "d": 3 + }, + "mne/io/fil/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/fil/fil.py": { + "a": 1, + "d": 2 + }, + "mne/io/fil/sensors.py": { + "a": 1, + "d": 2 + }, + "mne/io/fil/tests/test_fil.py": { + "a": 1, + "d": 2 + }, + "mne/io/hitachi/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/hitachi/hitachi.py": { + "a": 1, + "d": 2 + }, + "mne/io/hitachi/tests/test_hitachi.py": { + "a": 1, + "d": 2 + }, + "mne/io/kit/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/kit/constants.py": { + "a": 1, + "d": 3 + }, + "mne/io/kit/coreg.py": { + "a": 1, + "d": 2 + }, + "mne/io/kit/kit.py": { + "a": 1, + "d": 4 + }, + "mne/io/kit/tests/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/io/kit/tests/test_coreg.py": { + "a": 1, + "d": 2 + }, + "mne/io/kit/tests/test_kit.py": { + "a": 1, + "d": 2 + }, + "mne/io/nedf/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/nedf/nedf.py": { + "a": 2, + "d": 0 + }, + "mne/io/nedf/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/nedf/tests/test_nedf.py": { + "a": 2, + "d": 2 + }, + "mne/io/neuralynx/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/io/neuralynx/neuralynx.py": { + "a": 2, + "d": 0 + }, + "mne/io/neuralynx/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/neuralynx/tests/test_neuralynx.py": { + "a": 2, + "d": 0 + }, + "mne/io/nicolet/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/nicolet/nicolet.py": { + "a": 1, + "d": 2 + }, + "mne/io/nicolet/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/nicolet/tests/test_nicolet.py": { + "a": 1, + "d": 2 + }, + "mne/io/nihon/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/nihon/nihon.py": { + "a": 1, + "d": 2 + }, + "mne/io/nihon/tests/test_nihon.py": { + "a": 1, + "d": 2 + }, + "mne/io/nirx/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/nirx/_localized_abbr.py": { + "a": 2, + "d": 2 + }, + "mne/io/nirx/nirx.py": { + "a": 1, + "d": 2 + }, + "mne/io/nirx/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/nirx/tests/test_nirx.py": { + "a": 1, + "d": 3 + }, + "mne/io/nsx/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/nsx/nsx.py": { + "a": 2, + "d": 2 + }, + "mne/io/nsx/tests/test_nsx.py": { + "a": 2, + "d": 2 + }, + "mne/io/persyst/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/persyst/persyst.py": { + "a": 2, + "d": 2 + }, + "mne/io/persyst/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/persyst/tests/test_persyst.py": { + "a": 1, + "d": 2 + }, + "mne/io/pick.py": { + "a": 1, + "d": 2 + }, + "mne/io/snirf/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/io/snirf/_snirf.py": { + "a": 1, + "d": 2 + }, + "mne/io/snirf/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/snirf/tests/test_snirf.py": { + "a": 1, + "d": 2 + }, + "mne/io/tests/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/io/tests/data/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/io/tests/test_apply_function.py": { + "a": 1, + "d": 2 + }, + "mne/io/tests/test_raw.py": { + "a": 2, + "d": 3 + }, + "mne/io/tests/test_read_raw.py": { + "a": 1, + "d": 2 + }, + "mne/label.py": { + "a": 1, + "d": 4 + }, + "mne/minimum_norm/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/minimum_norm/_eloreta.py": { + "a": 1, + "d": 2 + }, + "mne/minimum_norm/inverse.py": { + "a": 1, + "d": 4 + }, + "mne/minimum_norm/resolution_matrix.py": { + "a": 2, + "d": 2 + }, + "mne/minimum_norm/spatial_resolution.py": { + "a": 2, + "d": 2 + }, + "mne/minimum_norm/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/minimum_norm/tests/test_inverse.py": { + "a": 2, + "d": 0 + }, + "mne/minimum_norm/tests/test_resolution_matrix.py": { + "a": 1, + "d": 4 + }, + "mne/minimum_norm/tests/test_resolution_metrics.py": { + "a": 2, + "d": 3 + }, + "mne/minimum_norm/tests/test_snr.py": { + "a": 1, + "d": 3 + }, + "mne/minimum_norm/tests/test_time_frequency.py": { + "a": 2, + "d": 0 + }, + "mne/minimum_norm/time_frequency.py": { + "a": 1, + "d": 3 + }, + "mne/misc.py": { + "a": 1, + "d": 3 + }, + "mne/morph.py": { + "a": 1, + "d": 4 + }, + "mne/morph_map.py": { + "a": 1, + "d": 5 + }, + "mne/parallel.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/__init__.py": { + "a": 3, + "d": 5 + }, + "mne/preprocessing/_annotate_amplitude.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/_annotate_nan.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/_csd.py": { + "a": 1, + "d": 3 + }, + "mne/preprocessing/_css.py": { + "a": 1, + "d": 1 + }, + "mne/preprocessing/_fine_cal.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/_lof.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/_peak_finder.py": { + "a": 2, + "d": 0 + }, + "mne/preprocessing/_regress.py": { + "a": 1, + "d": 3 + }, + "mne/preprocessing/artifact_detection.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/bads.py": { + "a": 1, + "d": 1 + }, + "mne/preprocessing/ctps_.py": { + "a": 2, + "d": 3 + }, + "mne/preprocessing/ecg.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/eog.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/eyetracking/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/eyetracking/_pupillometry.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/eyetracking/calibration.py": { + "a": 1, + "d": 3 + }, + "mne/preprocessing/eyetracking/eyetracking.py": { + "a": 1, + "d": 3 + }, + "mne/preprocessing/eyetracking/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/preprocessing/eyetracking/tests/test_calibration.py": { + "a": 2, + "d": 0 + }, + "mne/preprocessing/eyetracking/tests/test_eyetracking.py": { + "a": 4, + "d": 0 + }, + "mne/preprocessing/eyetracking/tests/test_pupillometry.py": { + "a": 1, + "d": 1 + }, + "mne/preprocessing/eyetracking/utils.py": { + "a": 4, + "d": 0 + }, + "mne/preprocessing/hfc.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/ica.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/ieeg/__init__.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/ieeg/_projection.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/ieeg/_volume.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/ieeg/tests/test_projection.py": { + "a": 2, + "d": 2 + }, + "mne/preprocessing/ieeg/tests/test_volume.py": { + "a": 2, + "d": 2 + }, + "mne/preprocessing/infomax_.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/interpolate.py": { + "a": 1, + "d": 1 + }, + "mne/preprocessing/maxwell.py": { + "a": 1, + "d": 5 + }, + "mne/preprocessing/nirs/__init__.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/nirs/_beer_lambert_law.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/nirs/_optical_density.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/nirs/_scalp_coupling_index.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/nirs/_tddr.py": { + "a": 1, + "d": 3 + }, + "mne/preprocessing/nirs/nirs.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/nirs/tests/test_beer_lambert_law.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/nirs/tests/test_nirs.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/nirs/tests/test_optical_density.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/nirs/tests/test_scalp_coupling_index.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/nirs/tests/test_temporal_derivative_distribution_repair.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/otp.py": { + "a": 1, + "d": 3 + }, + "mne/preprocessing/realign.py": { + "a": 1, + "d": 3 + }, + "mne/preprocessing/ssp.py": { + "a": 1, + "d": 4 + }, + "mne/preprocessing/stim.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/preprocessing/tests/test_annotate_amplitude.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_annotate_nan.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_artifact_detection.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_csd.py": { + "a": 2, + "d": 2 + }, + "mne/preprocessing/tests/test_css.py": { + "a": 1, + "d": 1 + }, + "mne/preprocessing/tests/test_ctps.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_ecg.py": { + "a": 2, + "d": 0 + }, + "mne/preprocessing/tests/test_eeglab_infomax.py": { + "a": 2, + "d": 0 + }, + "mne/preprocessing/tests/test_eog.py": { + "a": 2, + "d": 0 + }, + "mne/preprocessing/tests/test_fine_cal.py": { + "a": 2, + "d": 3 + }, + "mne/preprocessing/tests/test_hfc.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_ica.py": { + "a": 1, + "d": 3 + }, + "mne/preprocessing/tests/test_infomax.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_interpolate.py": { + "a": 2, + "d": 0 + }, + "mne/preprocessing/tests/test_lof.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_maxwell.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_otp.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_peak_finder.py": { + "a": 2, + "d": 0 + }, + "mne/preprocessing/tests/test_realign.py": { + "a": 1, + "d": 3 + }, + "mne/preprocessing/tests/test_regress.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_ssp.py": { + "a": 2, + "d": 0 + }, + "mne/preprocessing/tests/test_stim.py": { + "a": 1, + "d": 2 + }, + "mne/preprocessing/tests/test_xdawn.py": { + "a": 1, + "d": 3 + }, + "mne/preprocessing/xdawn.py": { + "a": 1, + "d": 4 + }, + "mne/proj.py": { + "a": 1, + "d": 2 + }, + "mne/rank.py": { + "a": 2, + "d": 2 + }, + "mne/report/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/report/report.py": { + "a": 1, + "d": 4 + }, + "mne/report/tests/test_report.py": { + "a": 1, + "d": 3 + }, + "mne/simulation/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/simulation/_metrics.py": { + "a": 1, + "d": 3 + }, + "mne/simulation/evoked.py": { + "a": 2, + "d": 4 + }, + "mne/simulation/metrics/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/simulation/metrics/metrics.py": { + "a": 1, + "d": 5 + }, + "mne/simulation/metrics/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/simulation/metrics/tests/test_metrics.py": { + "a": 1, + "d": 3 + }, + "mne/simulation/raw.py": { + "a": 1, + "d": 4 + }, + "mne/simulation/source.py": { + "a": 1, + "d": 8 + }, + "mne/simulation/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/simulation/tests/test_evoked.py": { + "a": 1, + "d": 2 + }, + "mne/simulation/tests/test_metrics.py": { + "a": 1, + "d": 3 + }, + "mne/simulation/tests/test_raw.py": { + "a": 1, + "d": 4 + }, + "mne/simulation/tests/test_source.py": { + "a": 1, + "d": 3 + }, + "mne/source_estimate.py": { + "a": 1, + "d": 5 + }, + "mne/source_space/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/source_space/_source_space.py": { + "a": 1, + "d": 3 + }, + "mne/source_space/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/source_space/tests/test_source_space.py": { + "a": 1, + "d": 3 + }, + "mne/stats/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/stats/_adjacency.py": { + "a": 1, + "d": 3 + }, + "mne/stats/cluster_level.py": { + "a": 1, + "d": 7 + }, + "mne/stats/erp.py": { + "a": 1, + "d": 0 + }, + "mne/stats/multi_comp.py": { + "a": 1, + "d": 5 + }, + "mne/stats/parametric.py": { + "a": 1, + "d": 4 + }, + "mne/stats/permutations.py": { + "a": 1, + "d": 2 + }, + "mne/stats/regression.py": { + "a": 1, + "d": 6 + }, + "mne/stats/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/stats/tests/test_adjacency.py": { + "a": 1, + "d": 2 + }, + "mne/stats/tests/test_cluster_level.py": { + "a": 1, + "d": 3 + }, + "mne/stats/tests/test_erp.py": { + "a": 4, + "d": 0 + }, + "mne/stats/tests/test_multi_comp.py": { + "a": 2, + "d": 0 + }, + "mne/stats/tests/test_parametric.py": { + "a": 2, + "d": 0 + }, + "mne/stats/tests/test_permutations.py": { + "a": 1, + "d": 2 + }, + "mne/stats/tests/test_regression.py": { + "a": 1, + "d": 4 + }, + "mne/surface.py": { + "a": 1, + "d": 5 + }, + "mne/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/tests/test_annotations.py": { + "a": 1, + "d": 3 + }, + "mne/tests/test_bem.py": { + "a": 1, + "d": 2 + }, + "mne/tests/test_chpi.py": { + "a": 1, + "d": 2 + }, + "mne/tests/test_coreg.py": { + "a": 2, + "d": 0 + }, + "mne/tests/test_cov.py": { + "a": 1, + "d": 3 + }, + "mne/tests/test_defaults.py": { + "a": 2, + "d": 0 + }, + "mne/tests/test_dipole.py": { + "a": 1, + "d": 2 + }, + "mne/tests/test_docstring_parameters.py": { + "a": 1, + "d": 2 + }, + "mne/tests/test_epochs.py": { + "a": 1, + "d": 4 + }, + "mne/tests/test_event.py": { + "a": 2, + "d": 3 + }, + "mne/tests/test_evoked.py": { + "a": 1, + "d": 5 + }, + "mne/tests/test_filter.py": { + "a": 2, + "d": 0 + }, + "mne/tests/test_freesurfer.py": { + "a": 2, + "d": 0 + }, + "mne/tests/test_import_nesting.py": { + "a": 1, + "d": 2 + }, + "mne/tests/test_label.py": { + "a": 1, + "d": 2 + }, + "mne/tests/test_line_endings.py": { + "a": 1, + "d": 3 + }, + "mne/tests/test_misc.py": { + "a": 1, + "d": 2 + }, + "mne/tests/test_morph.py": { + "a": 2, + "d": 2 + }, + "mne/tests/test_morph_map.py": { + "a": 1, + "d": 2 + }, + "mne/tests/test_ola.py": { + "a": 2, + "d": 0 + }, + "mne/tests/test_parallel.py": { + "a": 1, + "d": 2 + }, + "mne/tests/test_proj.py": { + "a": 2, + "d": 0 + }, + "mne/tests/test_rank.py": { + "a": 2, + "d": 0 + }, + "mne/tests/test_read_vectorview_selection.py": { + "a": 2, + "d": 0 + }, + "mne/tests/test_source_estimate.py": { + "a": 1, + "d": 0 + }, + "mne/tests/test_surface.py": { + "a": 1, + "d": 2 + }, + "mne/tests/test_transforms.py": { + "a": 1, + "d": 2 + }, + "mne/time_frequency/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/time_frequency/_stft.py": { + "a": 2, + "d": 0 + }, + "mne/time_frequency/_stockwell.py": { + "a": 1, + "d": 4 + }, + "mne/time_frequency/ar.py": { + "a": 1, + "d": 3 + }, + "mne/time_frequency/csd.py": { + "a": 1, + "d": 4 + }, + "mne/time_frequency/multitaper.py": { + "a": 1, + "d": 2 + }, + "mne/time_frequency/psd.py": { + "a": 1, + "d": 3 + }, + "mne/time_frequency/spectrum.py": { + "a": 2, + "d": 0 + }, + "mne/time_frequency/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/time_frequency/tests/test_ar.py": { + "a": 2, + "d": 0 + }, + "mne/time_frequency/tests/test_csd.py": { + "a": 2, + "d": 0 + }, + "mne/time_frequency/tests/test_multitaper.py": { + "a": 2, + "d": 0 + }, + "mne/time_frequency/tests/test_psd.py": { + "a": 2, + "d": 0 + }, + "mne/time_frequency/tests/test_spectrum.py": { + "a": 1, + "d": 0 + }, + "mne/time_frequency/tests/test_stft.py": { + "a": 1, + "d": 4 + }, + "mne/time_frequency/tests/test_stockwell.py": { + "a": 1, + "d": 4 + }, + "mne/time_frequency/tests/test_tfr.py": { + "a": 2, + "d": 0 + }, + "mne/time_frequency/tfr.py": { + "a": 2, + "d": 6 + }, + "mne/transforms.py": { + "a": 1, + "d": 3 + }, + "mne/utils/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/utils/_bunch.py": { + "a": 2, + "d": 4 + }, + "mne/utils/_logging.py": { + "a": 2, + "d": 2 + }, + "mne/utils/_testing.py": { + "a": 2, + "d": 2 + }, + "mne/utils/_typing.py": { + "a": 4, + "d": 0 + }, + "mne/utils/check.py": { + "a": 2, + "d": 2 + }, + "mne/utils/config.py": { + "a": 2, + "d": 2 + }, + "mne/utils/dataframe.py": { + "a": 2, + "d": 2 + }, + "mne/utils/docs.py": { + "a": 2, + "d": 2 + }, + "mne/utils/fetching.py": { + "a": 2, + "d": 2 + }, + "mne/utils/linalg.py": { + "a": 2, + "d": 2 + }, + "mne/utils/misc.py": { + "a": 2, + "d": 2 + }, + "mne/utils/mixin.py": { + "a": 2, + "d": 2 + }, + "mne/utils/numerics.py": { + "a": 2, + "d": 3 + }, + "mne/utils/progressbar.py": { + "a": 2, + "d": 2 + }, + "mne/utils/spectrum.py": { + "a": 2, + "d": 0 + }, + "mne/utils/tests/test_bunch.py": { + "a": 1, + "d": 3 + }, + "mne/utils/tests/test_check.py": { + "a": 2, + "d": 3 + }, + "mne/utils/tests/test_config.py": { + "a": 2, + "d": 0 + }, + "mne/utils/tests/test_docs.py": { + "a": 2, + "d": 0 + }, + "mne/utils/tests/test_linalg.py": { + "a": 2, + "d": 2 + }, + "mne/utils/tests/test_logging.py": { + "a": 2, + "d": 0 + }, + "mne/utils/tests/test_misc.py": { + "a": 2, + "d": 0 + }, + "mne/utils/tests/test_mixin.py": { + "a": 1, + "d": 2 + }, + "mne/utils/tests/test_numerics.py": { + "a": 2, + "d": 0 + }, + "mne/utils/tests/test_progressbar.py": { + "a": 1, + "d": 2 + }, + "mne/utils/tests/test_testing.py": { + "a": 1, + "d": 2 + }, + "mne/viz/_3d.py": { + "a": 1, + "d": 7 + }, + "mne/viz/_3d_overlay.py": { + "a": 1, + "d": 3 + }, + "mne/viz/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/viz/_brain/__init__.py": { + "a": 1, + "d": 7 + }, + "mne/viz/_brain/_brain.py": { + "a": 1, + "d": 7 + }, + "mne/viz/_brain/_linkviewer.py": { + "a": 2, + "d": 4 + }, + "mne/viz/_brain/_scraper.py": { + "a": 2, + "d": 0 + }, + "mne/viz/_brain/colormap.py": { + "a": 1, + "d": 5 + }, + "mne/viz/_brain/surface.py": { + "a": 1, + "d": 6 + }, + "mne/viz/_brain/tests/test_brain.py": { + "a": 1, + "d": 6 + }, + "mne/viz/_brain/tests/test_notebook.py": { + "a": 1, + "d": 2 + }, + "mne/viz/_brain/view.py": { + "a": 1, + "d": 6 + }, + "mne/viz/_dipole.py": { + "a": 1, + "d": 2 + }, + "mne/viz/_figure.py": { + "a": 2, + "d": 3 + }, + "mne/viz/_mpl_figure.py": { + "a": 1, + "d": 2 + }, + "mne/viz/_proj.py": { + "a": 1, + "d": 2 + }, + "mne/viz/_scraper.py": { + "a": 1, + "d": 2 + }, + "mne/viz/backends/__init__.py": { + "a": 2, + "d": 0 + }, + "mne/viz/backends/_abstract.py": { + "a": 1, + "d": 4 + }, + "mne/viz/backends/_notebook.py": { + "a": 1, + "d": 3 + }, + "mne/viz/backends/_pyvista.py": { + "a": 1, + "d": 5 + }, + "mne/viz/backends/_qt.py": { + "a": 1, + "d": 4 + }, + "mne/viz/backends/_utils.py": { + "a": 2, + "d": 5 + }, + "mne/viz/backends/renderer.py": { + "a": 1, + "d": 5 + }, + "mne/viz/backends/tests/_utils.py": { + "a": 1, + "d": 5 + }, + "mne/viz/backends/tests/test_abstract.py": { + "a": 1, + "d": 2 + }, + "mne/viz/backends/tests/test_renderer.py": { + "a": 1, + "d": 5 + }, + "mne/viz/backends/tests/test_utils.py": { + "a": 1, + "d": 5 + }, + "mne/viz/circle.py": { + "a": 1, + "d": 4 + }, + "mne/viz/conftest.py": { + "a": 1, + "d": 4 + }, + "mne/viz/epochs.py": { + "a": 1, + "d": 9 + }, + "mne/viz/evoked.py": { + "a": 1, + "d": 8 + }, + "mne/viz/evoked_field.py": { + "a": 2, + "d": 0 + }, + "mne/viz/eyetracking/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/viz/eyetracking/heatmap.py": { + "a": 1, + "d": 2 + }, + "mne/viz/eyetracking/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/viz/eyetracking/tests/test_heatmap.py": { + "a": 1, + "d": 2 + }, + "mne/viz/ica.py": { + "a": 1, + "d": 5 + }, + "mne/viz/misc.py": { + "a": 1, + "d": 7 + }, + "mne/viz/montage.py": { + "a": 2, + "d": 0 + }, + "mne/viz/raw.py": { + "a": 1, + "d": 4 + }, + "mne/viz/tests/__init__.py": { + "a": 1, + "d": 0 + }, + "mne/viz/tests/test_3d.py": { + "a": 1, + "d": 7 + }, + "mne/viz/tests/test_3d_mpl.py": { + "a": 1, + "d": 7 + }, + "mne/viz/tests/test_circle.py": { + "a": 1, + "d": 4 + }, + "mne/viz/tests/test_epochs.py": { + "a": 1, + "d": 7 + }, + "mne/viz/tests/test_evoked.py": { + "a": 1, + "d": 9 + }, + "mne/viz/tests/test_figure.py": { + "a": 1, + "d": 2 + }, + "mne/viz/tests/test_ica.py": { + "a": 1, + "d": 3 + }, + "mne/viz/tests/test_misc.py": { + "a": 1, + "d": 7 + }, + "mne/viz/tests/test_montage.py": { + "a": 1, + "d": 4 + }, + "mne/viz/tests/test_proj.py": { + "a": 1, + "d": 2 + }, + "mne/viz/tests/test_raw.py": { + "a": 1, + "d": 2 + }, + "mne/viz/tests/test_scraper.py": { + "a": 1, + "d": 2 + }, + "mne/viz/tests/test_topo.py": { + "a": 1, + "d": 6 + }, + "mne/viz/tests/test_topomap.py": { + "a": 1, + "d": 6 + }, + "mne/viz/tests/test_ui_events.py": { + "a": 2, + "d": 2 + }, + "mne/viz/tests/test_utils.py": { + "a": 1, + "d": 2 + }, + "mne/viz/topo.py": { + "a": 1, + "d": 5 + }, + "mne/viz/topomap.py": { + "a": 1, + "d": 8 + }, + "mne/viz/ui_events.py": { + "a": 2, + "d": 0 + }, + "mne/viz/utils.py": { + "a": 2, + "d": 9 + }, + "tools/check_mne_location.py": { + "a": 2, + "d": 0 + }, + "tools/dev/check_steering_committee.py": { + "a": 9, + "d": 4 + }, + "tools/dev/ensure_headers.py": { + "a": 125, + "d": 51 + }, + "tools/dev/gen_css_for_mne.py": { + "a": 1, + "d": 2 + }, + "tools/dev/generate_pyi_files.py": { + "a": 2, + "d": 0 + }, + "tools/dev/update_credit_json.py": { + "a": 4, + "d": 0 + }, + "tools/generate_codemeta.py": { + "a": 2, + "d": 0 + }, + "tools/vulture_allowlist.py": { + "a": 11, + "d": 1 + }, + "tutorials/epochs/10_epochs_overview.py": { + "a": 2, + "d": 0 + }, + "tutorials/epochs/20_visualize_epochs.py": { + "a": 2, + "d": 0 + }, + "tutorials/epochs/30_epochs_metadata.py": { + "a": 2, + "d": 0 + }, + "tutorials/epochs/40_autogenerate_metadata.py": { + "a": 2, + "d": 0 + }, + "tutorials/epochs/50_epochs_to_data_frame.py": { + "a": 2, + "d": 0 + }, + "tutorials/epochs/60_make_fixed_length_epochs.py": { + "a": 2, + "d": 0 + }, + "tutorials/evoked/10_evoked_overview.py": { + "a": 2, + "d": 0 + }, + "tutorials/evoked/20_visualize_evoked.py": { + "a": 2, + "d": 0 + }, + "tutorials/evoked/30_eeg_erp.py": { + "a": 2, + "d": 0 + }, + "tutorials/evoked/40_whitened.py": { + "a": 2, + "d": 0 + }, + "tutorials/forward/10_background_freesurfer.py": { + "a": 2, + "d": 0 + }, + "tutorials/forward/20_source_alignment.py": { + "a": 2, + "d": 0 + }, + "tutorials/forward/30_forward.py": { + "a": 2, + "d": 0 + }, + "tutorials/forward/50_background_freesurfer_mne.py": { + "a": 2, + "d": 0 + }, + "tutorials/forward/90_compute_covariance.py": { + "a": 2, + "d": 0 + }, + "tutorials/intro/10_overview.py": { + "a": 2, + "d": 0 + }, + "tutorials/intro/15_inplace.py": { + "a": 2, + "d": 0 + }, + "tutorials/intro/20_events_from_raw.py": { + "a": 2, + "d": 0 + }, + "tutorials/intro/30_info.py": { + "a": 2, + "d": 0 + }, + "tutorials/intro/40_sensor_locations.py": { + "a": 2, + "d": 0 + }, + "tutorials/intro/50_configure_mne.py": { + "a": 2, + "d": 0 + }, + "tutorials/intro/70_report.py": { + "a": 2, + "d": 0 + }, + "tutorials/inverse/10_stc_class.py": { + "a": 2, + "d": 0 + }, + "tutorials/inverse/20_dipole_fit.py": { + "a": 2, + "d": 0 + }, + "tutorials/inverse/30_mne_dspm_loreta.py": { + "a": 2, + "d": 0 + }, + "tutorials/inverse/35_dipole_orientations.py": { + "a": 2, + "d": 0 + }, + "tutorials/inverse/60_visualize_stc.py": { + "a": 2, + "d": 0 + }, + "tutorials/io/10_reading_meg_data.py": { + "a": 2, + "d": 0 + }, + "tutorials/io/20_reading_eeg_data.py": { + "a": 2, + "d": 0 + }, + "tutorials/io/30_reading_fnirs_data.py": { + "a": 2, + "d": 0 + }, + "tutorials/io/70_reading_eyetracking_data.py": { + "a": 2, + "d": 0 + }, + "tutorials/machine-learning/50_decoding.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/10_preprocessing_overview.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/15_handling_bad_channels.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/20_rejecting_bad_data.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/25_background_filtering.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/30_filtering_resampling.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/35_artifact_correction_regression.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/40_artifact_correction_ica.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/45_projectors_background.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/50_artifact_correction_ssp.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/55_setting_eeg_reference.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/60_maxwell_filtering_sss.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/70_fnirs_processing.py": { + "a": 2, + "d": 0 + }, + "tutorials/preprocessing/80_opm_processing.py": { + "a": 2, + "d": 0 + }, + "tutorials/raw/10_raw_overview.py": { + "a": 2, + "d": 0 + }, + "tutorials/raw/20_event_arrays.py": { + "a": 2, + "d": 0 + }, + "tutorials/raw/30_annotate_raw.py": { + "a": 2, + "d": 0 + }, + "tutorials/raw/40_visualize_raw.py": { + "a": 2, + "d": 0 + }, + "tutorials/simulation/10_array_objs.py": { + "a": 2, + "d": 0 + }, + "tutorials/simulation/70_point_spread.py": { + "a": 2, + "d": 0 + }, + "tutorials/stats-sensor-space/20_erp_stats.py": { + "a": 2, + "d": 0 + }, + "tutorials/time-freq/10_spectrum_class.py": { + "a": 2, + "d": 0 + }, + "tutorials/visualization/20_ui_events.py": { + "a": 1, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12783.json b/doc/sphinxext/prs/12783.json new file mode 100644 index 00000000000..3d4f0664e07 --- /dev/null +++ b/doc/sphinxext/prs/12783.json @@ -0,0 +1,15 @@ +{ + "merge_commit_sha": "01a1c1e40e81ef22ec8ee4d1564c3bdf87adfc88", + "authors": [ + { + "n": "pre-commit-ci[bot]", + "e": "66853113+pre-commit-ci[bot]@users.noreply.github.com" + } + ], + "changes": { + ".pre-commit-config.yaml": { + "a": 1, + "d": 1 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12786.json b/doc/sphinxext/prs/12786.json new file mode 100644 index 00000000000..fbe4032ee0f --- /dev/null +++ b/doc/sphinxext/prs/12786.json @@ -0,0 +1,15 @@ +{ + "merge_commit_sha": "c9f8ee2998e6a47d667076a9c76ee48da480e4e1", + "authors": [ + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + "tutorials/stats-sensor-space/70_cluster_rmANOVA_time_freq.py": { + "a": 4, + "d": 2 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12792.json b/doc/sphinxext/prs/12792.json new file mode 100644 index 00000000000..df21223b9d3 --- /dev/null +++ b/doc/sphinxext/prs/12792.json @@ -0,0 +1,75 @@ +{ + "merge_commit_sha": "ab69d3e235de846b53ac2052b33faddce9ffd4f9", + "authors": [ + { + "n": "Mathieu Scheltienne", + "e": "mathieu.scheltienne@fcbg.ch" + }, + { + "n": "autofix-ci[bot]", + "e": "114827586+autofix-ci[bot]@users.noreply.github.com" + }, + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + "doc/api/reading_raw_data.rst": { + "a": 14, + "d": 13 + }, + "doc/changes/devel/12792.newfeature.rst": { + "a": 1, + "d": 0 + }, + "doc/conf.py": { + "a": 1, + "d": 0 + }, + "mne/io/__init__.pyi": { + "a": 2, + "d": 0 + }, + "mne/io/_read_raw.py": { + "a": 34, + "d": 10 + }, + "mne/io/ant/__init__.py": { + "a": 5, + "d": 0 + }, + "mne/io/ant/ant.py": { + "a": 293, + "d": 0 + }, + "mne/io/ant/tests/__init__.py": { + "a": 3, + "d": 0 + }, + "mne/io/ant/tests/test_ant.py": { + "a": 138, + "d": 0 + }, + "mne/io/cnt/cnt.py": { + "a": 18, + "d": 15 + }, + "mne/io/nsx/nsx.py": { + "a": 8, + "d": 5 + }, + "mne/io/tests/test_read_raw.py": { + "a": 58, + "d": 1 + }, + "mne/tests/test_import_nesting.py": { + "a": 1, + "d": 1 + }, + "pyproject.toml": { + "a": 1, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12793.json b/doc/sphinxext/prs/12793.json new file mode 100644 index 00000000000..90d06e08527 --- /dev/null +++ b/doc/sphinxext/prs/12793.json @@ -0,0 +1,15 @@ +{ + "merge_commit_sha": "450acb1c33d19b2fe054be9c6b01f8a83f8c7a9b", + "authors": [ + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + ".github/workflows/credit.yml": { + "a": 3, + "d": 2 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12794.json b/doc/sphinxext/prs/12794.json new file mode 100644 index 00000000000..a83bcc71056 --- /dev/null +++ b/doc/sphinxext/prs/12794.json @@ -0,0 +1,39 @@ +{ + "merge_commit_sha": "09696542308a8745b9a7d245bc5af00f8284d706", + "authors": [ + { + "n": "github-actions[bot]", + "e": "41898282+github-actions[bot]@users.noreply.github.com" + } + ], + "changes": { + "doc/sphinxext/prs/12747.json": { + "a": 47, + "d": 0 + }, + "doc/sphinxext/prs/12774.json": { + "a": 103, + "d": 0 + }, + "doc/sphinxext/prs/12778.json": { + "a": 31, + "d": 0 + }, + "doc/sphinxext/prs/12781.json": { + "a": 2911, + "d": 0 + }, + "doc/sphinxext/prs/12783.json": { + "a": 15, + "d": 0 + }, + "doc/sphinxext/prs/12786.json": { + "a": 15, + "d": 0 + }, + "doc/sphinxext/prs/12793.json": { + "a": 15, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12796.json b/doc/sphinxext/prs/12796.json new file mode 100644 index 00000000000..76455afaccd --- /dev/null +++ b/doc/sphinxext/prs/12796.json @@ -0,0 +1,15 @@ +{ + "merge_commit_sha": "e108241dbc0392100cf1b5df1598bda2f1645459", + "authors": [ + { + "n": "github-actions[bot]", + "e": "41898282+github-actions[bot]@users.noreply.github.com" + } + ], + "changes": { + "doc/sphinxext/prs/12794.json": { + "a": 39, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12797.json b/doc/sphinxext/prs/12797.json new file mode 100644 index 00000000000..050912edf23 --- /dev/null +++ b/doc/sphinxext/prs/12797.json @@ -0,0 +1,311 @@ +{ + "merge_commit_sha": "bf5173b3cdc69d86fb7db1f2fc2edd3b57fbc2a2", + "authors": [ + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + ".github/workflows/credit.yml": { + "a": 1, + "d": 1 + }, + ".mailmap": { + "a": 2, + "d": 1 + }, + "CITATION.cff": { + "a": 39, + "d": 23 + }, + "codemeta.json": { + "a": 122, + "d": 74 + }, + "doc/_static/versions.json": { + "a": 7, + "d": 2 + }, + "doc/changes/devel.rst": { + "a": 0, + "d": 5 + }, + "doc/changes/devel/12300.apichange.rst": { + "a": 0, + "d": 3 + }, + "doc/changes/devel/12300.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12338.newfeature.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12554.dependency.rst": { + "a": 0, + "d": 6 + }, + "doc/changes/devel/12556.newfeature.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12561.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12562.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12569.other.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12573.newfeature.rst": { + "a": 0, + "d": 3 + }, + "doc/changes/devel/12576.newfeature.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12578.bugfix.rst": { + "a": 0, + "d": 3 + }, + "doc/changes/devel/12583.apichange.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12583.newfeature.rst": { + "a": 0, + "d": 4 + }, + "doc/changes/devel/12584.newfeature.rst": { + "a": 0, + "d": 4 + }, + "doc/changes/devel/12593.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12597.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12600.other.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12605.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12609.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12612.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12616.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12620.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12628.newfeature.rst": { + "a": 0, + "d": 4 + }, + "doc/changes/devel/12633.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12646.bugfix.rst": { + "a": 0, + "d": 10 + }, + "doc/changes/devel/12649.newfeature.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12650.other.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12652.newfeature.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12655.newfeature.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12659.other.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12661.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12664.other.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12669.newfeature.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12676.bugfix.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12686.newfeature.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12687.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12688.other.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12694.bugfix.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12697.other.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12699.apichange.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12703.newfeature.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12707.newfeature.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12719.apichange.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12720.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12720.newfeature.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12721.bugfix.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12724.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12725.newfeature.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12727.bugfix.rst": { + "a": 0, + "d": 3 + }, + "doc/changes/devel/12727.newfeature.rst": { + "a": 0, + "d": 3 + }, + "doc/changes/devel/12730.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12733.newfeature.rst": { + "a": 0, + "d": 3 + }, + "doc/changes/devel/12734.newfeature.rst": { + "a": 0, + "d": 3 + }, + "doc/changes/devel/12735.bugfix.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12742.dependency.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12747.newfeature.rst": { + "a": 0, + "d": 3 + }, + "doc/changes/devel/12754.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12759.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12760.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12763.bugfix.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/devel/12771.apichange.rst": { + "a": 0, + "d": 4 + }, + "doc/changes/devel/12774.other.rst": { + "a": 0, + "d": 2 + }, + "doc/changes/devel/12781.other.rst": { + "a": 0, + "d": 1 + }, + "doc/changes/v1.8.rst": { + "a": 173, + "d": 0 + }, + "doc/development/whats_new.rst": { + "a": 1, + "d": 1 + }, + "doc/documentation/cited.rst": { + "a": 3, + "d": 3 + }, + "doc/sphinxext/update_credit_rst.py": { + "a": 1, + "d": 0 + }, + "mne/beamformer/tests/test_dics.py": { + "a": 1, + "d": 1 + }, + "mne/decoding/tests/test_ssd.py": { + "a": 4, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12798.json b/doc/sphinxext/prs/12798.json new file mode 100644 index 00000000000..4bdcbf6adfe --- /dev/null +++ b/doc/sphinxext/prs/12798.json @@ -0,0 +1,99 @@ +{ + "merge_commit_sha": "a82528d35c655b693b23143a88850fe7a851fa10", + "authors": [ + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + }, + { + "n": "autofix-ci[bot]", + "e": "114827586+autofix-ci[bot]@users.noreply.github.com" + } + ], + "changes": { + ".github/workflows/tests.yml": { + "a": 2, + "d": 2 + }, + "README.rst": { + "a": 8, + "d": 8 + }, + "doc/changes/devel.rst": { + "a": 5, + "d": 0 + }, + "doc/changes/devel/12798.dependency.rst": { + "a": 1, + "d": 0 + }, + "doc/development/contributing.rst": { + "a": 2, + "d": 2 + }, + "doc/development/whats_new.rst": { + "a": 1, + "d": 0 + }, + "doc/install/installers.rst": { + "a": 5, + "d": 5 + }, + "doc/links.inc": { + "a": 1, + "d": 0 + }, + "mne/datasets/_fsaverage/base.py": { + "a": 3, + "d": 34 + }, + "mne/datasets/tests/test_datasets.py": { + "a": 0, + "d": 4 + }, + "mne/export/_edf.py": { + "a": 1, + "d": 1 + }, + "mne/fixes.py": { + "a": 1, + "d": 1 + }, + "mne/io/egi/egi.py": { + "a": 3, + "d": 9 + }, + "mne/io/egi/egimff.py": { + "a": 1, + "d": 1 + }, + "mne/io/egi/tests/test_egi.py": { + "a": 3, + "d": 1 + }, + "mne/time_frequency/tfr.py": { + "a": 5, + "d": 131 + }, + "mne/utils/_logging.py": { + "a": 2, + "d": 1 + }, + "mne/utils/docs.py": { + "a": 0, + "d": 8 + }, + "mne/viz/_brain/_brain.py": { + "a": 0, + "d": 27 + }, + "pyproject.toml": { + "a": 2, + "d": 1 + }, + "tools/environment_old.yml": { + "a": 5, + "d": 5 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12799.json b/doc/sphinxext/prs/12799.json new file mode 100644 index 00000000000..72fd0c1a174 --- /dev/null +++ b/doc/sphinxext/prs/12799.json @@ -0,0 +1,251 @@ +{ + "merge_commit_sha": "362f9330925fb79a6adc19a42243672676dec63e", + "authors": [ + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + "mne/_fiff/meas_info.py": { + "a": 1, + "d": 1 + }, + "mne/_fiff/open.py": { + "a": 1, + "d": 1 + }, + "mne/_fiff/pick.py": { + "a": 2, + "d": 2 + }, + "mne/_fiff/proj.py": { + "a": 1, + "d": 1 + }, + "mne/_fiff/reference.py": { + "a": 2, + "d": 2 + }, + "mne/_fiff/write.py": { + "a": 1, + "d": 1 + }, + "mne/_ola.py": { + "a": 2, + "d": 2 + }, + "mne/annotations.py": { + "a": 1, + "d": 1 + }, + "mne/bem.py": { + "a": 1, + "d": 1 + }, + "mne/channels/channels.py": { + "a": 1, + "d": 1 + }, + "mne/channels/layout.py": { + "a": 4, + "d": 4 + }, + "mne/cov.py": { + "a": 2, + "d": 2 + }, + "mne/decoding/base.py": { + "a": 1, + "d": 1 + }, + "mne/decoding/ssd.py": { + "a": 1, + "d": 1 + }, + "mne/decoding/transformer.py": { + "a": 1, + "d": 1 + }, + "mne/epochs.py": { + "a": 6, + "d": 6 + }, + "mne/event.py": { + "a": 1, + "d": 1 + }, + "mne/evoked.py": { + "a": 1, + "d": 1 + }, + "mne/filter.py": { + "a": 3, + "d": 3 + }, + "mne/forward/forward.py": { + "a": 3, + "d": 3 + }, + "mne/gui/_coreg.py": { + "a": 1, + "d": 1 + }, + "mne/inverse_sparse/mxne_inverse.py": { + "a": 2, + "d": 2 + }, + "mne/io/base.py": { + "a": 3, + "d": 3 + }, + "mne/io/edf/edf.py": { + "a": 1, + "d": 1 + }, + "mne/io/eeglab/eeglab.py": { + "a": 4, + "d": 4 + }, + "mne/io/fil/fil.py": { + "a": 1, + "d": 1 + }, + "mne/io/hitachi/hitachi.py": { + "a": 1, + "d": 1 + }, + "mne/io/kit/coreg.py": { + "a": 3, + "d": 3 + }, + "mne/io/kit/kit.py": { + "a": 2, + "d": 2 + }, + "mne/io/tests/test_raw.py": { + "a": 1, + "d": 1 + }, + "mne/label.py": { + "a": 1, + "d": 1 + }, + "mne/minimum_norm/inverse.py": { + "a": 2, + "d": 2 + }, + "mne/minimum_norm/time_frequency.py": { + "a": 4, + "d": 4 + }, + "mne/morph.py": { + "a": 2, + "d": 4 + }, + "mne/preprocessing/artifact_detection.py": { + "a": 2, + "d": 2 + }, + "mne/preprocessing/ica.py": { + "a": 7, + "d": 7 + }, + "mne/preprocessing/maxwell.py": { + "a": 1, + "d": 1 + }, + "mne/preprocessing/xdawn.py": { + "a": 1, + "d": 1 + }, + "mne/rank.py": { + "a": 1, + "d": 1 + }, + "mne/report/report.py": { + "a": 5, + "d": 5 + }, + "mne/simulation/raw.py": { + "a": 3, + "d": 3 + }, + "mne/source_estimate.py": { + "a": 4, + "d": 4 + }, + "mne/stats/regression.py": { + "a": 3, + "d": 3 + }, + "mne/tests/test_import_nesting.py": { + "a": 1, + "d": 1 + }, + "mne/time_frequency/tfr.py": { + "a": 6, + "d": 6 + }, + "mne/transforms.py": { + "a": 1, + "d": 1 + }, + "mne/utils/_logging.py": { + "a": 1, + "d": 1 + }, + "mne/utils/check.py": { + "a": 3, + "d": 3 + }, + "mne/utils/misc.py": { + "a": 2, + "d": 2 + }, + "mne/utils/mixin.py": { + "a": 5, + "d": 5 + }, + "mne/utils/numerics.py": { + "a": 11, + "d": 11 + }, + "mne/viz/_3d.py": { + "a": 4, + "d": 4 + }, + "mne/viz/_brain/_brain.py": { + "a": 5, + "d": 5 + }, + "mne/viz/backends/_qt.py": { + "a": 1, + "d": 1 + }, + "mne/viz/evoked.py": { + "a": 11, + "d": 11 + }, + "mne/viz/ica.py": { + "a": 3, + "d": 3 + }, + "mne/viz/misc.py": { + "a": 2, + "d": 2 + }, + "mne/viz/topomap.py": { + "a": 5, + "d": 5 + }, + "mne/viz/utils.py": { + "a": 3, + "d": 3 + }, + "pyproject.toml": { + "a": 0, + "d": 1 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12800.json b/doc/sphinxext/prs/12800.json new file mode 100644 index 00000000000..ea5fadc2ff1 --- /dev/null +++ b/doc/sphinxext/prs/12800.json @@ -0,0 +1,15 @@ +{ + "merge_commit_sha": "de72aae04118d77afbf5e4f3c0a8b0037e5bc38b", + "authors": [ + { + "n": "Mathieu Scheltienne", + "e": "mathieu.scheltienne@fcbg.ch" + } + ], + "changes": { + "mne/datasets/config.py": { + "a": 2, + "d": 2 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12801.json b/doc/sphinxext/prs/12801.json new file mode 100644 index 00000000000..d5cf5ceb9e4 --- /dev/null +++ b/doc/sphinxext/prs/12801.json @@ -0,0 +1,23 @@ +{ + "merge_commit_sha": "dcd34d4e588e24c2f5de2995417407aa115c59d9", + "authors": [ + { + "n": "Mathieu Scheltienne", + "e": "mathieu.scheltienne@fcbg.ch" + } + ], + "changes": { + "doc/changes/devel/12801.newfeature.rst": { + "a": 1, + "d": 0 + }, + "mne/gui/_coreg.py": { + "a": 8, + "d": 7 + }, + "mne/gui/_gui.py": { + "a": 2, + "d": 2 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12802.json b/doc/sphinxext/prs/12802.json new file mode 100644 index 00000000000..3d68a76c3a0 --- /dev/null +++ b/doc/sphinxext/prs/12802.json @@ -0,0 +1,19 @@ +{ + "merge_commit_sha": "966121be5931918ec63497aa4e9ba1404858007e", + "authors": [ + { + "n": "pre-commit-ci[bot]", + "e": "66853113+pre-commit-ci[bot]@users.noreply.github.com" + }, + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + ".pre-commit-config.yaml": { + "a": 1, + "d": 1 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12803.json b/doc/sphinxext/prs/12803.json new file mode 100644 index 00000000000..67c3cc3f4e7 --- /dev/null +++ b/doc/sphinxext/prs/12803.json @@ -0,0 +1,27 @@ +{ + "merge_commit_sha": "223d4aa9ebd1b7942329912a057b349912792d2c", + "authors": [ + { + "n": "Mathieu Scheltienne", + "e": "mathieu.scheltienne@fcbg.ch" + } + ], + "changes": { + "doc/changes/devel/12803.bugfix.rst": { + "a": 1, + "d": 0 + }, + "mne/_freesurfer.py": { + "a": 19, + "d": 16 + }, + "mne/source_space/_source_space.py": { + "a": 3, + "d": 4 + }, + "mne/utils/check.py": { + "a": 29, + "d": 1 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12804.json b/doc/sphinxext/prs/12804.json new file mode 100644 index 00000000000..1a714b42ba2 --- /dev/null +++ b/doc/sphinxext/prs/12804.json @@ -0,0 +1,31 @@ +{ + "merge_commit_sha": "99dd0e1c24856aaaca7289e7e14d7a1390496134", + "authors": [ + { + "n": "Mathieu Scheltienne", + "e": "mathieu.scheltienne@fcbg.ch" + }, + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + "doc/_includes/institutional-partners.rst": { + "a": 1, + "d": 1 + }, + "doc/changes/devel/12804.bugfix.rst": { + "a": 1, + "d": 0 + }, + "doc/conf.py": { + "a": 2, + "d": 2 + }, + "mne/forward/forward.py": { + "a": 5, + "d": 1 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12805.json b/doc/sphinxext/prs/12805.json new file mode 100644 index 00000000000..a3dfd555637 --- /dev/null +++ b/doc/sphinxext/prs/12805.json @@ -0,0 +1,51 @@ +{ + "merge_commit_sha": "0aae72dda030242d992866ce6d551206749474b2", + "authors": [ + { + "n": "Alex lepauvre", + "e": "alex.lepauvre@ae.mpg.de" + }, + { + "n": "pre-commit-ci[bot]", + "e": "66853113+pre-commit-ci[bot]@users.noreply.github.com" + }, + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + "doc/changes/devel/12805.newfeature.rst": { + "a": 1, + "d": 0 + }, + "doc/changes/names.inc": { + "a": 1, + "d": 0 + }, + "mne/decoding/tests/test_base.py": { + "a": 1, + "d": 0 + }, + "mne/utils/docs.py": { + "a": 13, + "d": 0 + }, + "mne/viz/_3d.py": { + "a": 71, + "d": 5 + }, + "mne/viz/_brain/_brain.py": { + "a": 5, + "d": 0 + }, + "mne/viz/_brain/tests/test_brain.py": { + "a": 111, + "d": 0 + }, + "mne/viz/tests/test_3d.py": { + "a": 156, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12806.json b/doc/sphinxext/prs/12806.json new file mode 100644 index 00000000000..c15a965b71f --- /dev/null +++ b/doc/sphinxext/prs/12806.json @@ -0,0 +1,47 @@ +{ + "merge_commit_sha": "ac2c4c0d72f9843690aad70e63b48269f5269a0f", + "authors": [ + { + "n": "Mathieu Scheltienne", + "e": "mathieu.scheltienne@fcbg.ch" + }, + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + "doc/_includes/institutional-partners.rst": { + "a": 1, + "d": 1 + }, + "doc/changes/devel/12803.bugfix.rst": { + "a": 1, + "d": 0 + }, + "doc/changes/devel/12804.bugfix.rst": { + "a": 1, + "d": 0 + }, + "doc/conf.py": { + "a": 2, + "d": 2 + }, + "mne/_freesurfer.py": { + "a": 19, + "d": 16 + }, + "mne/forward/forward.py": { + "a": 5, + "d": 1 + }, + "mne/source_space/_source_space.py": { + "a": 3, + "d": 4 + }, + "mne/utils/check.py": { + "a": 29, + "d": 1 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12810.json b/doc/sphinxext/prs/12810.json new file mode 100644 index 00000000000..d091af61277 --- /dev/null +++ b/doc/sphinxext/prs/12810.json @@ -0,0 +1,35 @@ +{ + "merge_commit_sha": "af19be0a123735fd6b85e82e01adba86d6574188", + "authors": [ + { + "n": "Proloy Das", + "e": "proloy@umd.edu" + }, + { + "n": "Mathieu Scheltienne", + "e": "mathieu.scheltienne@gmail.com" + }, + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + "mne/datasets/config.py": { + "a": 2, + "d": 2 + }, + "mne/io/ant/ant.py": { + "a": 57, + "d": 6 + }, + "mne/io/ant/tests/test_ant.py": { + "a": 188, + "d": 21 + }, + "tools/vulture_allowlist.py": { + "a": 3, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12811.json b/doc/sphinxext/prs/12811.json new file mode 100644 index 00000000000..3cf0b022e14 --- /dev/null +++ b/doc/sphinxext/prs/12811.json @@ -0,0 +1,51 @@ +{ + "merge_commit_sha": "bd8f9cbd2cb3d520d9671ad445eb81c8fb85b942", + "authors": [ + { + "n": "Victor Férat", + "e": "victor.ferat@live.Fr" + }, + { + "n": "pre-commit-ci[bot]", + "e": "66853113+pre-commit-ci[bot]@users.noreply.github.com" + }, + { + "n": "Mathieu Scheltienne", + "e": "mathieu.scheltienne@gmail.com" + }, + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + } + ], + "changes": { + "doc/changes/devel/12811.newfeature.rst": { + "a": 1, + "d": 0 + }, + "mne/_fiff/utils.py": { + "a": 6, + "d": 2 + }, + "mne/epochs.py": { + "a": 7, + "d": 0 + }, + "mne/io/base.py": { + "a": 13, + "d": 1 + }, + "mne/io/fiff/tests/test_raw_fiff.py": { + "a": 13, + "d": 6 + }, + "mne/io/tests/test_raw.py": { + "a": 5, + "d": 2 + }, + "mne/tests/test_epochs.py": { + "a": 7, + "d": 5 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12812.json b/doc/sphinxext/prs/12812.json new file mode 100644 index 00000000000..8111f32ed6b --- /dev/null +++ b/doc/sphinxext/prs/12812.json @@ -0,0 +1,15 @@ +{ + "merge_commit_sha": "08a383126bcf9bfc7b98e5462d5803dc1fa239a1", + "authors": [ + { + "n": "Stefan Appelhoff", + "e": "stefan.appelhoff@mailbox.org" + } + ], + "changes": { + "mne/annotations.py": { + "a": 2, + "d": 2 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12813.json b/doc/sphinxext/prs/12813.json new file mode 100644 index 00000000000..30a9de7df4d --- /dev/null +++ b/doc/sphinxext/prs/12813.json @@ -0,0 +1,15 @@ +{ + "merge_commit_sha": "b1203ada6f1a3ecaac4e8b67df45b9124a34dcd7", + "authors": [ + { + "n": "Mathieu Scheltienne", + "e": "mathieu.scheltienne@fcbg.ch" + } + ], + "changes": { + "mne/io/ant/tests/test_ant.py": { + "a": 5, + "d": 0 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12814.json b/doc/sphinxext/prs/12814.json new file mode 100644 index 00000000000..8ddb8f3403b --- /dev/null +++ b/doc/sphinxext/prs/12814.json @@ -0,0 +1,15 @@ +{ + "merge_commit_sha": "20871ff2286935a564a9db5320afa7437df18458", + "authors": [ + { + "n": "pre-commit-ci[bot]", + "e": "66853113+pre-commit-ci[bot]@users.noreply.github.com" + } + ], + "changes": { + ".pre-commit-config.yaml": { + "a": 1, + "d": 1 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12815.json b/doc/sphinxext/prs/12815.json new file mode 100644 index 00000000000..6b0f7fd1f1b --- /dev/null +++ b/doc/sphinxext/prs/12815.json @@ -0,0 +1,19 @@ +{ + "merge_commit_sha": "f27bac8b5a128667d7f946f0089132fa5d0da9ba", + "authors": [ + { + "n": "Mathieu Scheltienne", + "e": "mathieu.scheltienne@fcbg.ch" + } + ], + "changes": { + "examples/io/read_neo_format.py": { + "a": 1, + "d": 3 + }, + "mne/_fiff/meas_info.py": { + "a": 2, + "d": 1 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/prs/12820.json b/doc/sphinxext/prs/12820.json new file mode 100644 index 00000000000..73fa2132a68 --- /dev/null +++ b/doc/sphinxext/prs/12820.json @@ -0,0 +1,159 @@ +{ + "merge_commit_sha": "13852f58bced5a49434d06e50d98efcf6b4292de", + "authors": [ + { + "n": "Eric Larson", + "e": "larson.eric.d@gmail.com" + }, + { + "n": "Daniel McCloy", + "e": "dan@mccloy.info" + } + ], + "changes": { + ".github/workflows/credit.yml": { + "a": 1, + "d": 1 + }, + ".mailmap": { + "a": 10, + "d": 8 + }, + "doc/changes/names.inc": { + "a": 2, + "d": 2 + }, + "doc/changes/v0.10.rst": { + "a": 2, + "d": 2 + }, + "doc/changes/v0.11.rst": { + "a": 3, + "d": 3 + }, + "doc/changes/v0.12.rst": { + "a": 10, + "d": 10 + }, + "doc/changes/v0.13.rst": { + "a": 13, + "d": 13 + }, + "doc/changes/v0.14.rst": { + "a": 7, + "d": 7 + }, + "doc/changes/v0.15.rst": { + "a": 8, + "d": 8 + }, + "doc/changes/v0.16.rst": { + "a": 2, + "d": 2 + }, + "doc/changes/v0.18.rst": { + "a": 2, + "d": 2 + }, + "doc/changes/v0.20.rst": { + "a": 1, + "d": 1 + }, + "doc/changes/v0.21.rst": { + "a": 1, + "d": 1 + }, + "doc/changes/v0.22.rst": { + "a": 2, + "d": 2 + }, + "doc/changes/v0.23.rst": { + "a": 3, + "d": 3 + }, + "doc/changes/v0.24.rst": { + "a": 2, + "d": 2 + }, + "doc/changes/v0.8.rst": { + "a": 2, + "d": 2 + }, + "doc/changes/v0.9.rst": { + "a": 2, + "d": 2 + }, + "doc/changes/v1.1.rst": { + "a": 2, + "d": 2 + }, + "doc/changes/v1.7.rst": { + "a": 90, + "d": 90 + }, + "doc/changes/v1.8.rst": { + "a": 63, + "d": 63 + }, + "doc/conf.py": { + "a": 2, + "d": 3 + }, + "doc/sphinxext/credit_tools.py": { + "a": 88, + "d": 9 + }, + "doc/sphinxext/mne_doc_utils.py": { + "a": 7, + "d": 0 + }, + "doc/sphinxext/related_software.py": { + "a": 10, + "d": 2 + }, + "examples/decoding/decoding_csp_timefreq.py": { + "a": 1, + "d": 1 + }, + "examples/decoding/decoding_rsa_sgskip.py": { + "a": 1, + "d": 1 + }, + "examples/decoding/decoding_spatio_temporal_source.py": { + "a": 1, + "d": 1 + }, + "examples/decoding/decoding_spoc_CMC.py": { + "a": 1, + "d": 1 + }, + "examples/decoding/decoding_time_generalization_conditions.py": { + "a": 1, + "d": 1 + }, + "examples/decoding/decoding_unsupervised_spatial_filter.py": { + "a": 1, + "d": 1 + }, + "examples/decoding/ems_filtering.py": { + "a": 1, + "d": 1 + }, + "examples/decoding/linear_model_patterns.py": { + "a": 1, + "d": 1 + }, + "examples/io/read_neo_format.py": { + "a": 4, + "d": 4 + }, + "mne/conftest.py": { + "a": 2, + "d": 0 + }, + "pyproject.toml": { + "a": 1, + "d": 1 + } + } +} \ No newline at end of file diff --git a/doc/sphinxext/related_software.py b/doc/sphinxext/related_software.py index 71dff39a75c..c88782be171 100644 --- a/doc/sphinxext/related_software.py +++ b/doc/sphinxext/related_software.py @@ -7,15 +7,21 @@ 3. If it's not on PyPI, add it to the MANUAL_PACKAGES dictionary. """ +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + import functools import importlib.metadata import os import pathlib +import urllib.error import urllib.request import joblib from docutils import nodes from docutils.parsers.rst import Directive +from mne_doc_utils import sphinx_logger from sphinx.errors import ExtensionError from sphinx.util.display import status_iterator @@ -138,8 +144,14 @@ def _get_installer_packages(): @functools.lru_cache -def _get_packages(): - packages = _get_installer_packages() +def _get_packages() -> dict[str, str]: + try: + packages = _get_installer_packages() + except urllib.error.URLError as exc: # e.g., bad internet connection + if not REQUIRE_METADATA: + sphinx_logger.warning(f"Could not fetch package list, got: {exc}") + return dict() + raise # There can be duplicates in manual and installer packages because some of the # PyPI entries for installer packages are incorrect or unusable (see above), so # we don't enforce that. But PyPI and manual should be disjoint: diff --git a/doc/sphinxext/unit_role.py b/doc/sphinxext/unit_role.py index 4d9c9d94252..b52665e8321 100644 --- a/doc/sphinxext/unit_role.py +++ b/doc/sphinxext/unit_role.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from docutils import nodes diff --git a/examples/datasets/kernel_phantom.py b/examples/datasets/kernel_phantom.py index d29e9196d66..da17f708454 100644 --- a/examples/datasets/kernel_phantom.py +++ b/examples/datasets/kernel_phantom.py @@ -8,8 +8,10 @@ stimulated with 7 modules active (121 channels). Here we show some example traces. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np import mne diff --git a/examples/datasets/opm_data.py b/examples/datasets/opm_data.py index fcc60d80934..ebecec603fb 100644 --- a/examples/datasets/opm_data.py +++ b/examples/datasets/opm_data.py @@ -10,8 +10,10 @@ we demonstrate how to localize these custom OPM data in MNE. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # sphinx_gallery_thumbnail_number = 4 import numpy as np diff --git a/examples/decoding/decoding_csp_timefreq.py b/examples/decoding/decoding_csp_timefreq.py index c389645d668..9c26bf05444 100644 --- a/examples/decoding/decoding_csp_timefreq.py +++ b/examples/decoding/decoding_csp_timefreq.py @@ -12,7 +12,7 @@ signals. """ # Authors: Laura Gwilliams -# Jean-Remi King +# Jean-Rémi King # Alex Barachant # Alexandre Gramfort # diff --git a/examples/decoding/decoding_rsa_sgskip.py b/examples/decoding/decoding_rsa_sgskip.py index bf6a5294624..1daaabb9619 100644 --- a/examples/decoding/decoding_rsa_sgskip.py +++ b/examples/decoding/decoding_rsa_sgskip.py @@ -21,7 +21,7 @@ build the images below. """ -# Authors: Jean-Remi King +# Authors: Jean-Rémi King # Jaakko Leppakangas # Alexandre Gramfort # diff --git a/examples/decoding/decoding_spatio_temporal_source.py b/examples/decoding/decoding_spatio_temporal_source.py index 696eab955af..f724ea97b3b 100644 --- a/examples/decoding/decoding_spatio_temporal_source.py +++ b/examples/decoding/decoding_spatio_temporal_source.py @@ -14,7 +14,7 @@ # Author: Denis A. Engemann # Alexandre Gramfort -# Jean-Remi King +# Jean-Rémi King # Eric Larson # # License: BSD-3-Clause diff --git a/examples/decoding/decoding_spoc_CMC.py b/examples/decoding/decoding_spoc_CMC.py index 0a02a61052c..2f85138d2b3 100644 --- a/examples/decoding/decoding_spoc_CMC.py +++ b/examples/decoding/decoding_spoc_CMC.py @@ -18,7 +18,7 @@ """ # Author: Alexandre Barachant -# Jean-Remi King +# Jean-Rémi King # # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/examples/decoding/decoding_time_generalization_conditions.py b/examples/decoding/decoding_time_generalization_conditions.py index 71ce7b1f076..e71112e8375 100644 --- a/examples/decoding/decoding_time_generalization_conditions.py +++ b/examples/decoding/decoding_time_generalization_conditions.py @@ -11,7 +11,7 @@ instant and subsequently assess whether this linear model can accurately predict all of the time samples of a second set of conditions. """ -# Authors: Jean-Remi King +# Authors: Jean-Rémi King # Alexandre Gramfort # Denis Engemann # diff --git a/examples/decoding/decoding_unsupervised_spatial_filter.py b/examples/decoding/decoding_unsupervised_spatial_filter.py index 33b286be21b..2fb1a8fec46 100644 --- a/examples/decoding/decoding_unsupervised_spatial_filter.py +++ b/examples/decoding/decoding_unsupervised_spatial_filter.py @@ -10,7 +10,7 @@ the channel data to new sources / virtual channels. The output is visualized on the average of all the epochs. """ -# Authors: Jean-Remi King +# Authors: Jean-Rémi King # Asish Panda # # License: BSD-3-Clause diff --git a/examples/decoding/ems_filtering.py b/examples/decoding/ems_filtering.py index 1f96bd349a6..d1e04e2e096 100644 --- a/examples/decoding/ems_filtering.py +++ b/examples/decoding/ems_filtering.py @@ -19,7 +19,7 @@ evolution of the spatial filters. """ # Author: Denis Engemann -# Jean-Remi King +# Jean-Rémi King # # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/examples/decoding/linear_model_patterns.py b/examples/decoding/linear_model_patterns.py index d4758b97dae..c1390cbb0d3 100644 --- a/examples/decoding/linear_model_patterns.py +++ b/examples/decoding/linear_model_patterns.py @@ -16,7 +16,7 @@ """ # Authors: Alexandre Gramfort # Romain Trachel -# Jean-Remi King +# Jean-Rémi King # # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/examples/inverse/custom_inverse_solver.py b/examples/inverse/custom_inverse_solver.py index 64add6b8d25..e8444dcd046 100644 --- a/examples/inverse/custom_inverse_solver.py +++ b/examples/inverse/custom_inverse_solver.py @@ -19,8 +19,10 @@ in order to try out another inverse algorithm. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import numpy as np diff --git a/examples/inverse/morph_volume_stc.py b/examples/inverse/morph_volume_stc.py index 7a9db303e90..24b23fc374e 100644 --- a/examples/inverse/morph_volume_stc.py +++ b/examples/inverse/morph_volume_stc.py @@ -20,6 +20,7 @@ result will be plotted, showing the fsaverage T1 weighted anatomical MRI, overlaid with the morphed volumetric source estimate. """ + # Author: Tommy Clausner # # License: BSD-3-Clause diff --git a/examples/io/read_neo_format.py b/examples/io/read_neo_format.py index a22fec663aa..a34ff0cd4f4 100644 --- a/examples/io/read_neo_format.py +++ b/examples/io/read_neo_format.py @@ -6,24 +6,24 @@ =============================================== This example shows how to create an MNE-Python `~mne.io.Raw` object from data -in the `neural ensemble `__ format. For general +in the `neural ensemble `_ format. For general information on creating MNE-Python's data objects from NumPy arrays, see :ref:`tut-creating-data-structures`. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. -# %% import neo import mne # %% -# This example uses NEO's ``ExampleIO`` object for creating fake data. The data -# will be all zeros, so the plot won't be very interesting, but it should -# demonstrate the steps to using NEO data. For actual data and different file -# formats, consult the NEO documentation. +# This example uses NEO's ``ExampleIO`` object for creating fake data. The data will be +# all zeros, so the plot won't be very interesting, but it should demonstrate the steps +# to using NEO data. For actual data and different file formats, consult the NEO +# documentation. reader = neo.io.ExampleIO("fakedata.nof") block = reader.read(lazy=False)[0] # get the first block diff --git a/examples/preprocessing/contralateral_referencing.py b/examples/preprocessing/contralateral_referencing.py index e9c8818c8e5..b2ae199817d 100644 --- a/examples/preprocessing/contralateral_referencing.py +++ b/examples/preprocessing/contralateral_referencing.py @@ -12,8 +12,10 @@ contralateral EEG reference. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import mne ssvep_folder = mne.datasets.ssvep.data_path() diff --git a/examples/visualization/evoked_whitening.py b/examples/visualization/evoked_whitening.py index 9a474d9ea36..ed05ae3ba11 100644 --- a/examples/visualization/evoked_whitening.py +++ b/examples/visualization/evoked_whitening.py @@ -16,6 +16,7 @@ ---------- .. footbibliography:: """ + # Authors: Alexandre Gramfort # Denis A. Engemann # diff --git a/examples/visualization/eyetracking_plot_heatmap.py b/examples/visualization/eyetracking_plot_heatmap.py index 9225493ef88..07983685b5e 100644 --- a/examples/visualization/eyetracking_plot_heatmap.py +++ b/examples/visualization/eyetracking_plot_heatmap.py @@ -14,8 +14,10 @@ """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% # Data loading # ------------ @@ -66,6 +68,10 @@ cmap = plt.get_cmap("viridis") plot_gaze(epochs["natural"], calibration=calibration, cmap=cmap, sigma=50) +# %% +# .. note:: The (0, 0) pixel coordinates are at the top-left of the +# trackable area of the screen for many eye trackers. + # %% # Overlaying plots with images # ---------------------------- diff --git a/examples/visualization/mne_helmet.py b/examples/visualization/mne_helmet.py index 944d1c387cc..bbf340a4da4 100644 --- a/examples/visualization/mne_helmet.py +++ b/examples/visualization/mne_helmet.py @@ -8,8 +8,10 @@ This tutorial shows how to make the MNE helmet + brain image. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import mne diff --git a/ignore_words.txt b/ignore_words.txt index cc0edd4fcc4..150a32058e2 100644 --- a/ignore_words.txt +++ b/ignore_words.txt @@ -39,3 +39,5 @@ aas vor connec sme +tim +whitelists diff --git a/logo/generate_mne_logos.py b/logo/generate_mne_logos.py index 7b08325bf85..3dbca9918aa 100644 --- a/logo/generate_mne_logos.py +++ b/logo/generate_mne_logos.py @@ -1,7 +1,6 @@ """Generate the MNE-Python logos.""" -# @author: drmccloy -# Created on Mon Jul 20 11:28:16 2015 +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/__init__.py b/mne/__init__.py index 10ff0c23738..6abe2bccb62 100644 --- a/mne/__init__.py +++ b/mne/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """MNE software for MEG and EEG data analysis.""" # PEP0440 compatible formatted version, see: # https://www.python.org/dev/peps/pep-0440/ diff --git a/mne/__main__.py b/mne/__main__.py index 955c7af4936..e0a0dc552d2 100644 --- a/mne/__main__.py +++ b/mne/__main__.py @@ -1,4 +1,4 @@ -# Authors: Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/__init__.py b/mne/_fiff/__init__.py index 877068fe54d..48a5871c58b 100644 --- a/mne/_fiff/__init__.py +++ b/mne/_fiff/__init__.py @@ -1,7 +1,6 @@ """Private module for FIF basic I/O routines.""" -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/_digitization.py b/mne/_fiff/_digitization.py index f3f238449cd..6b14701d0b8 100644 --- a/mne/_fiff/_digitization.py +++ b/mne/_fiff/_digitization.py @@ -1,9 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Teon Brooks -# Stefan Appelhoff -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/compensator.py b/mne/_fiff/compensator.py index e068a236c6d..914dc1bb82b 100644 --- a/mne/_fiff/compensator.py +++ b/mne/_fiff/compensator.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np from ..utils import fill_doc diff --git a/mne/_fiff/constants.py b/mne/_fiff/constants.py index 116b9662bc5..7020e87b97b 100644 --- a/mne/_fiff/constants.py +++ b/mne/_fiff/constants.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/ctf_comp.py b/mne/_fiff/ctf_comp.py index 4d896039e84..87269badb8e 100644 --- a/mne/_fiff/ctf_comp.py +++ b/mne/_fiff/ctf_comp.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Denis Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/matrix.py b/mne/_fiff/matrix.py index 422c13ce490..6c8bdd4b157 100644 --- a/mne/_fiff/matrix.py +++ b/mne/_fiff/matrix.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index 263cb112ec0..2759d2332a3 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -1,8 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Teon Brooks -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -2803,7 +2799,8 @@ def write_meas_info(fid, info, data_type=None, reset_range=True): if info.get("device_info") is not None: start_block(fid, FIFF.FIFFB_DEVICE) di = info["device_info"] - write_string(fid, FIFF.FIFF_DEVICE_TYPE, di["type"]) + if di.get("type") is not None: + write_string(fid, FIFF.FIFF_DEVICE_TYPE, di["type"]) for key in ("model", "serial", "site"): if di.get(key) is not None: write_string(fid, getattr(FIFF, "FIFF_DEVICE_" + key.upper()), di[key]) @@ -3173,7 +3170,7 @@ def create_info(ch_names, sfreq, ch_types="misc", verbose=None): this_ch_dict = ch_types_dict[ch_type] kind = this_ch_dict["kind"] # handle chpi, where kind is a *list* of FIFF constants: - kind = kind[0] if isinstance(kind, (list, tuple)) else kind + kind = kind[0] if isinstance(kind, list | tuple) else kind # mirror what tag.py does here coord_frame = _ch_coord_dict.get(kind, FIFF.FIFFV_COORD_UNKNOWN) coil_type = this_ch_dict.get("coil_type", FIFF.FIFFV_COIL_NONE) diff --git a/mne/_fiff/open.py b/mne/_fiff/open.py index abc32aab687..92d3c088d4a 100644 --- a/mne/_fiff/open.py +++ b/mne/_fiff/open.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -345,7 +343,7 @@ def _show_tree( postpend += " ... dict len=" + str(len(tag.data)) elif isinstance(tag.data, str): postpend += " ... str len=" + str(len(tag.data)) - elif isinstance(tag.data, (list, tuple)): + elif isinstance(tag.data, list | tuple): postpend += " ... list len=" + str(len(tag.data)) elif issparse(tag.data): postpend += ( diff --git a/mne/_fiff/pick.py b/mne/_fiff/pick.py index 9024cf1c796..ec3479f8a26 100644 --- a/mne/_fiff/pick.py +++ b/mne/_fiff/pick.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Martin Luessi -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -422,7 +419,7 @@ def _check_info_exclude(info, exclude): raise ValueError('exclude must be a list of strings or "bads"') elif exclude == "bads": exclude = info.get("bads", []) - elif not isinstance(exclude, (list, tuple)): + elif not isinstance(exclude, list | tuple): raise ValueError( 'exclude must either be "bads" or a list of strings.' " If only one channel is to be excluded, use " @@ -1052,7 +1049,7 @@ def _check_excludes_includes(chs, info=None, allow_bads=False): """ from .meas_info import Info - if not isinstance(chs, (list, tuple, set, np.ndarray)): + if not isinstance(chs, list | tuple | set | np.ndarray): if allow_bads is True: if not isinstance(info, Info): raise ValueError("Supply an info object if allow_bads is true") diff --git a/mne/_fiff/proc_history.py b/mne/_fiff/proc_history.py index b2f6541243d..86a094cfa41 100644 --- a/mne/_fiff/proc_history.py +++ b/mne/_fiff/proc_history.py @@ -1,5 +1,4 @@ -# Authors: Denis A. Engemann -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/proj.py b/mne/_fiff/proj.py index 6011f322cfc..0376826138a 100644 --- a/mne/_fiff/proj.py +++ b/mne/_fiff/proj.py @@ -1,8 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Denis Engemann -# Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -341,7 +337,7 @@ def apply_proj(self, verbose=None): logger.info("The projections don't apply to these data. Doing nothing.") return self self._projector, self.info = _projector, info - if isinstance(self, (BaseRaw, Evoked)): + if isinstance(self, BaseRaw | Evoked): if self.preload: self._data = np.dot(self._projector, self._data) else: # BaseEpochs diff --git a/mne/_fiff/reference.py b/mne/_fiff/reference.py index 2cf15977848..c5b81709d54 100644 --- a/mne/_fiff/reference.py +++ b/mne/_fiff/reference.py @@ -1,7 +1,4 @@ -# Authors: Marijn van Vliet -# Alexandre Gramfort -# Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -178,7 +175,7 @@ def add_reference_channels(inst, ref_channels, copy=True): if copy: inst = inst.copy() - if isinstance(inst, (BaseRaw, Evoked)): + if isinstance(inst, BaseRaw | Evoked): data = inst._data refs = np.zeros((len(ref_channels), data.shape[1])) data = np.vstack((data, refs)) @@ -413,7 +410,7 @@ def _get_ch_type(inst, ch_type): _check_option("ch_type", ch_type, valid_ch_types) if ch_type != "auto": ch_type = [ch_type] - elif isinstance(ch_type, (list, tuple)): + elif isinstance(ch_type, list | tuple): for type_ in ch_type: _validate_type(type_, str, "ch_type") _check_option("ch_type", type_, valid_ch_types[1:]) diff --git a/mne/_fiff/tag.py b/mne/_fiff/tag.py index a2b8fe481bd..abc7d32036b 100644 --- a/mne/_fiff/tag.py +++ b/mne/_fiff/tag.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/tests/__init__.py b/mne/_fiff/tests/__init__.py index f5523f5d662..c45203dcc03 100644 --- a/mne/_fiff/tests/__init__.py +++ b/mne/_fiff/tests/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os.path as op data_dir = op.join(op.dirname(__file__), "data") diff --git a/mne/_fiff/tests/test_compensator.py b/mne/_fiff/tests/test_compensator.py index d743c7ad7f2..4854cc1831c 100644 --- a/mne/_fiff/tests/test_compensator.py +++ b/mne/_fiff/tests/test_compensator.py @@ -1,5 +1,4 @@ -# Author: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/tests/test_constants.py b/mne/_fiff/tests/test_constants.py index 703a32fd333..3d2e8e6b5b2 100644 --- a/mne/_fiff/tests/test_constants.py +++ b/mne/_fiff/tests/test_constants.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/tests/test_meas_info.py b/mne/_fiff/tests/test_meas_info.py index 6fb81a913e1..c68a0ca730a 100644 --- a/mne/_fiff/tests/test_meas_info.py +++ b/mne/_fiff/tests/test_meas_info.py @@ -1,6 +1,4 @@ -# # Authors: MNE Developers -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/tests/test_pick.py b/mne/_fiff/tests/test_pick.py index ab9edeaec15..9318479e6d4 100644 --- a/mne/_fiff/tests/test_pick.py +++ b/mne/_fiff/tests/test_pick.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from copy import deepcopy from pathlib import Path diff --git a/mne/_fiff/tests/test_proc_history.py b/mne/_fiff/tests/test_proc_history.py index eb0880271b0..82f2d6262be 100644 --- a/mne/_fiff/tests/test_proc_history.py +++ b/mne/_fiff/tests/test_proc_history.py @@ -1,5 +1,4 @@ -# Authors: Denis A. Engemann -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/tests/test_reference.py b/mne/_fiff/tests/test_reference.py index 7303c731052..3a9a752776f 100644 --- a/mne/_fiff/tests/test_reference.py +++ b/mne/_fiff/tests/test_reference.py @@ -1,7 +1,4 @@ -# Authors: Marijn van Vliet -# Alexandre Gramfort -# Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/tests/test_show_fiff.py b/mne/_fiff/tests/test_show_fiff.py index e25f248b02c..b771d3bd081 100644 --- a/mne/_fiff/tests/test_show_fiff.py +++ b/mne/_fiff/tests/test_show_fiff.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/tests/test_utils.py b/mne/_fiff/tests/test_utils.py index c8cac9a6cae..ba6748826a3 100644 --- a/mne/_fiff/tests/test_utils.py +++ b/mne/_fiff/tests/test_utils.py @@ -1,6 +1,6 @@ """Run tests for the utilities.""" -# Author: Stefan Appelhoff -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/tests/test_what.py b/mne/_fiff/tests/test_what.py index f8d86b637f0..9665b64523b 100644 --- a/mne/_fiff/tests/test_what.py +++ b/mne/_fiff/tests/test_what.py @@ -1,4 +1,4 @@ -# Authors: Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/tests/test_write.py b/mne/_fiff/tests/test_write.py index 95639a4e0ba..43087ec0dc8 100644 --- a/mne/_fiff/tests/test_write.py +++ b/mne/_fiff/tests/test_write.py @@ -1,6 +1,6 @@ """Run tests for writing.""" -# Author: Eric Larson -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/tree.py b/mne/_fiff/tree.py index dcb99e6fe74..16ad60cf3a0 100644 --- a/mne/_fiff/tree.py +++ b/mne/_fiff/tree.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/utils.py b/mne/_fiff/utils.py index e77f8a29194..6171062351a 100644 --- a/mne/_fiff/utils.py +++ b/mne/_fiff/utils.py @@ -1,17 +1,10 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Martin Luessi -# Denis Engemann -# Teon Brooks -# Marijn van Vliet -# Mainak Jas -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import os import os.path as op +from pathlib import Path import numpy as np @@ -323,13 +316,16 @@ def _construct_bids_filename(base, ext, part_idx, validate=True): def _make_split_fnames(fname, n_splits, split_naming): """Make a list of split filenames.""" if n_splits == 1: + fname = Path(fname) return [fname] res = [] base, ext = op.splitext(fname) for i in range(n_splits): if split_naming == "neuromag": - res.append(f"{base}-{i:d}{ext}" if i else fname) + path = Path(f"{base}-{i:d}{ext}" if i else fname) + res.append(path) else: assert split_naming == "bids" - res.append(_construct_bids_filename(base, ext, i)) + path = Path(_construct_bids_filename(base, ext, i)) + res.append(path) return res diff --git a/mne/_fiff/what.py b/mne/_fiff/what.py index 5c248fe2c8f..6f7e0ef995e 100644 --- a/mne/_fiff/what.py +++ b/mne/_fiff/what.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/_fiff/write.py b/mne/_fiff/write.py index 0b8108ef3db..ec8dddfd41a 100644 --- a/mne/_fiff/write.py +++ b/mne/_fiff/write.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -156,7 +154,7 @@ def write_name_list_sanitized(fid, kind, lst, name): def _safe_name_list(lst, operation, name): if operation == "write": - assert isinstance(lst, (list, tuple, np.ndarray)), type(lst) + assert isinstance(lst, list | tuple | np.ndarray), type(lst) if any("{COLON}" in val for val in lst): raise ValueError(f'The substring "{{COLON}}" in {name} not supported.') return ":".join(val.replace(":", "{COLON}") for val in lst) diff --git a/mne/_freesurfer.py b/mne/_freesurfer.py index 3f3a2fcbaae..9b4ec3d4a74 100644 --- a/mne/_freesurfer.py +++ b/mne/_freesurfer.py @@ -1,7 +1,6 @@ """Freesurfer handling functions.""" -# Authors: Alex Rockhill -# Eric Larson -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -600,27 +599,30 @@ def read_talxfm(subject, subjects_dir=None, verbose=None): return mri_mni_t -def _check_mri(mri, subject, subjects_dir): +def _check_mri(mri, subject, subjects_dir) -> str: """Check whether an mri exists in the Freesurfer subject directory.""" - _validate_type(mri, "path-like", "mri") - if op.isfile(mri) and op.basename(mri) != mri: - return mri - if not op.isfile(mri): + _validate_type(mri, "path-like", mri) + mri = Path(mri) + if mri.is_file() and mri.name != mri: + return str(mri) + elif not mri.is_file(): if subject is None: raise FileNotFoundError( - f"MRI file {mri!r} not found and no subject provided" + f"MRI file {mri!r} not found and no subject provided." + ) + subjects_dir = get_subjects_dir(subjects_dir, raise_error=True) + mri = subjects_dir / subject / "mri" / mri + if not mri.is_file(): + raise FileNotFoundError( + f"MRI file {mri!r} not found in the subjects directory " + f"{subjects_dir!r} for subject {subject}." ) - subjects_dir = str(get_subjects_dir(subjects_dir, raise_error=True)) - mri = op.join(subjects_dir, subject, "mri", mri) - if not op.isfile(mri): - raise FileNotFoundError(f"MRI file {mri!r} not found") - if op.basename(mri) == mri: - err = ( - f"Ambiguous filename - found {mri!r} in current folder.\n" - "If this is correct prefix name with relative or absolute path" + if mri.name == mri: + raise OSError( + f"Ambiguous filename - found {mri!r} in current folder. " + "If this is correct prefix name with relative or absolute path." ) - raise OSError(err) - return mri + return str(mri) def _read_mri_info(path, units="m", return_img=False, use_nibabel=False): diff --git a/mne/_ola.py b/mne/_ola.py index eb289273760..03910a3a188 100644 --- a/mne/_ola.py +++ b/mne/_ola.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson - +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -56,7 +55,7 @@ def __init__(self, control_points, values, interp="hann"): ) if isinstance(values, np.ndarray): values = [values] - if isinstance(values, (list, tuple)): + if isinstance(values, list | tuple): for v in values: if not (v is None or isinstance(v, np.ndarray)): raise TypeError( @@ -213,7 +212,7 @@ def feed(self, n_pts): def _check_store(store): if isinstance(store, np.ndarray): store = [store] - if isinstance(store, (list, tuple)) and all( + if isinstance(store, list | tuple) and all( isinstance(s, np.ndarray) for s in store ): store = _Storer(*store) diff --git a/mne/annotations.py b/mne/annotations.py index 81ee78b7294..9a9a82848f0 100644 --- a/mne/annotations.py +++ b/mne/annotations.py @@ -1,6 +1,4 @@ -# Authors: Jaakko Leppakangas -# Robert Luke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1148,8 +1146,8 @@ def read_annotations( r"""Read annotations from a file. This function reads a ``.fif``, ``.fif.gz``, ``.vmrk``, ``.amrk``, - ``.edf``, ``.txt``, ``.csv``, ``.cnt``, ``.cef``, or ``.set`` file and - makes an :class:`mne.Annotations` object. + ``.edf``, ``.bdf``, ``.gdf``, ``.txt``, ``.csv``, ``.cnt``, ``.cef``, or + ``.set`` file and makes an :class:`mne.Annotations` object. Parameters ---------- @@ -1481,7 +1479,7 @@ def _check_event_id(event_id, raw): elif event_id == "auto": if isinstance(raw, RawBrainVision): return _BVEventParser() - elif isinstance(raw, (Raw, RawArray)) and _check_bv_annot( + elif isinstance(raw, Raw | RawArray) and _check_bv_annot( raw.annotations.description ): logger.info("Non-RawBrainVision raw using branvision markers") diff --git a/mne/baseline.py b/mne/baseline.py index 37e3d8df72a..4e73ed0ce95 100644 --- a/mne/baseline.py +++ b/mne/baseline.py @@ -1,7 +1,6 @@ """Utility functions to baseline-correct data.""" -# Authors: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/beamformer/__init__.py b/mne/beamformer/__init__.py index cc00feae76f..16a5b363eb6 100644 --- a/mne/beamformer/__init__.py +++ b/mne/beamformer/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Beamformers for source localization.""" import lazy_loader as lazy diff --git a/mne/beamformer/_compute_beamformer.py b/mne/beamformer/_compute_beamformer.py index a35285328e6..bb947cdd757 100644 --- a/mne/beamformer/_compute_beamformer.py +++ b/mne/beamformer/_compute_beamformer.py @@ -1,9 +1,6 @@ """Functions shared between different beamformer types.""" -# Authors: Alexandre Gramfort -# Roman Goj -# Britta Westner -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/beamformer/_dics.py b/mne/beamformer/_dics.py index 0a5e1b07a35..20c89e7a1dd 100644 --- a/mne/beamformer/_dics.py +++ b/mne/beamformer/_dics.py @@ -1,12 +1,9 @@ """Dynamic Imaging of Coherent Sources (DICS).""" -# Authors: Marijn van Vliet -# Britta Westner -# Susanna Aro -# Roman Goj -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np from .._fiff.pick import pick_channels, pick_info diff --git a/mne/beamformer/_lcmv.py b/mne/beamformer/_lcmv.py index c07b1dd22c3..cd3b2910cce 100644 --- a/mne/beamformer/_lcmv.py +++ b/mne/beamformer/_lcmv.py @@ -1,11 +1,9 @@ """Compute Linearly constrained minimum variance (LCMV) beamformer.""" -# Authors: Alexandre Gramfort -# Roman Goj -# Britta Westner -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np from .._fiff.meas_info import _simplify_info diff --git a/mne/beamformer/_rap_music.py b/mne/beamformer/_rap_music.py index dfc35de85cd..b09e1d23a87 100644 --- a/mne/beamformer/_rap_music.py +++ b/mne/beamformer/_rap_music.py @@ -1,8 +1,6 @@ """Compute a Recursively Applied and Projected MUltiple Signal Classification (RAP-MUSIC).""" # noqa -# Authors: Yousra Bekhti -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/beamformer/resolution_matrix.py b/mne/beamformer/resolution_matrix.py index 63876604c24..e2dd258a2ab 100644 --- a/mne/beamformer/resolution_matrix.py +++ b/mne/beamformer/resolution_matrix.py @@ -1,9 +1,9 @@ """Compute resolution matrix for beamformers.""" -# Authors: olaf.hauk@mrc-cbu.cam.ac.uk -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np from .._fiff.pick import pick_channels, pick_channels_forward, pick_info diff --git a/mne/beamformer/tests/__init__.py b/mne/beamformer/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/beamformer/tests/__init__.py +++ b/mne/beamformer/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/beamformer/tests/test_dics.py b/mne/beamformer/tests/test_dics.py index 0a3fc128136..7d5800a597c 100644 --- a/mne/beamformer/tests/test_dics.py +++ b/mne/beamformer/tests/test_dics.py @@ -1,6 +1,4 @@ -# Authors: Marijn van Vliet -# Britta Westner -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -676,7 +674,7 @@ def test_apply_dics_timeseries(_load_forward, idx): proj_matrix = make_projector(p, evoked_proj.ch_names)[0] evoked_proj.add_proj(p) filters_proj = make_dics(evoked_proj.info, fwd_surf, csd20, label=label) - assert_array_equal(filters_proj["proj"], proj_matrix) + assert_allclose(filters_proj["proj"], proj_matrix, rtol=1e-7) stc_proj = apply_dics(evoked_proj, filters_proj) assert np.any(np.not_equal(stc_noproj.data, stc_proj.data)) diff --git a/mne/beamformer/tests/test_external.py b/mne/beamformer/tests/test_external.py index d159632594f..e4373693496 100644 --- a/mne/beamformer/tests/test_external.py +++ b/mne/beamformer/tests/test_external.py @@ -1,5 +1,4 @@ -# Authors: Britta Westner -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/beamformer/tests/test_lcmv.py b/mne/beamformer/tests/test_lcmv.py index 30cc3db8294..957dbaf5284 100644 --- a/mne/beamformer/tests/test_lcmv.py +++ b/mne/beamformer/tests/test_lcmv.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from contextlib import nullcontext from copy import deepcopy from inspect import signature diff --git a/mne/beamformer/tests/test_rap_music.py b/mne/beamformer/tests/test_rap_music.py index de6f047def8..594e11bca09 100644 --- a/mne/beamformer/tests/test_rap_music.py +++ b/mne/beamformer/tests/test_rap_music.py @@ -1,6 +1,4 @@ -# Authors: Yousra Bekhti -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/beamformer/tests/test_resolution_matrix.py b/mne/beamformer/tests/test_resolution_matrix.py index 5ce552cb1c9..a02222a86f2 100755 --- a/mne/beamformer/tests/test_resolution_matrix.py +++ b/mne/beamformer/tests/test_resolution_matrix.py @@ -1,7 +1,7 @@ -# Authors: Olaf Hauk -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """ Test computation of resolution matrix for LCMV beamformers. diff --git a/mne/bem.py b/mne/bem.py index 1be66aceff7..d361272fd49 100644 --- a/mne/bem.py +++ b/mne/bem.py @@ -1,8 +1,4 @@ -# Authors: Matti Hämäläinen -# Alexandre Gramfort -# Eric Larson -# Lorenzo De Santis -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -607,7 +603,7 @@ def _surfaces_to_bem( "number of elements (1 or 3)" ) for si, surf in enumerate(surfs): - if isinstance(surf, (str, Path, os.PathLike)): + if isinstance(surf, str | Path | os.PathLike): surfs[si] = surf = read_surface(surf, return_dict=True)[-1] # Downsampling if the surface is isomorphic with a subdivided icosahedron if ico is not None: diff --git a/mne/channels/__init__.py b/mne/channels/__init__.py index ddf274c39aa..901a237da24 100644 --- a/mne/channels/__init__.py +++ b/mne/channels/__init__.py @@ -2,8 +2,11 @@ Can be used for setting of sensor locations used for processing and plotting. """ + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import lazy_loader as lazy (__getattr__, __dir__, __all__) = lazy.attach_stub(__name__, __file__) diff --git a/mne/channels/_dig_montage_utils.py b/mne/channels/_dig_montage_utils.py index 81cf2b0a542..e462b0208dc 100644 --- a/mne/channels/_dig_montage_utils.py +++ b/mne/channels/_dig_montage_utils.py @@ -1,14 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Marijn van Vliet -# Jona Sassenhagen -# Teon Brooks -# Christian Brodbeck -# Stefan Appelhoff -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/channels/_standard_montage_utils.py b/mne/channels/_standard_montage_utils.py index 20c5da9e0c2..eb3dc10d10e 100644 --- a/mne/channels/_standard_montage_utils.py +++ b/mne/channels/_standard_montage_utils.py @@ -1,8 +1,7 @@ -# Authors: Joan Massich -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import csv import os.path as op from collections import OrderedDict @@ -231,6 +230,11 @@ def _check_dupes_odict(ch_names, pos): def _read_elc(fname, head_size): """Read .elc files. + The `.elc` files are so-called "asa electrode files". ASA here stands for + Advances Source Analysis, and is a software package developed and sold by + the ANT Neuro company. They provide a device for sensor digitization, called + 'xensor', which produces the `.elc` files. + Parameters ---------- fname : str @@ -242,12 +246,12 @@ def _read_elc(fname, head_size): Returns ------- montage : instance of DigMontage - The montage in [m]. + The montage units are [m]. """ fid_names = ("Nz", "LPA", "RPA") - ch_names_, pos = [], [] with open(fname) as fid: + # Read units # _read_elc does require to detect the units. (see _mgh_or_standard) for line in fid: if "UnitPosition" in line: @@ -259,15 +263,33 @@ def _read_elc(fname, head_size): for line in fid: if "Positions\n" in line: break + + # Read positions + new_style = False pos = [] for line in fid: if "Labels\n" in line: break - pos.append(list(map(float, line.split()))) + if ":" in line: + # Of the 'new' format: `E01 : 5.288 -3.658 119.693` + pos.append(list(map(float, line.split(":")[1].split()))) + new_style = True + else: + # Of the 'old' format: `5.288 -3.658 119.693` + pos.append(list(map(float, line.split()))) + + # Read labels + ch_names_ = [] for line in fid: if not line or not set(line) - {" "}: break - ch_names_.append(line.strip(" ").strip("\n")) + if new_style: + # Not sure how this format would deal with spaces in channel labels, + # but none of my test files had this, so let's wait until it comes up. + parsed = line.strip(" ").strip("\n").split() + else: + parsed = [line.strip(" ").strip("\n")] + ch_names_.extend(parsed) pos = np.array(pos) * scale if head_size is not None: diff --git a/mne/channels/channels.py b/mne/channels/channels.py index 92ddb7a9779..f000f9ad00b 100644 --- a/mne/channels/channels.py +++ b/mne/channels/channels.py @@ -1,13 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Martin Luessi -# Denis Engemann -# Andrew Dykstra -# Teon Brooks -# Daniel McCloy -# Ana Radanovic -# Erica Peterson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -2106,7 +2097,7 @@ def read_vectorview_selection(name, fname=None, info=None, verbose=None): List with channel names in the selection. """ # convert name to list of string - if not isinstance(name, (list, tuple)): + if not isinstance(name, list | tuple): name = [name] if isinstance(info, Info): picks = pick_types(info, meg=True, exclude=()) diff --git a/mne/channels/data/neighbors/__init__.py b/mne/channels/data/neighbors/__init__.py index d7a601ac8a8..a07b13441ad 100644 --- a/mne/channels/data/neighbors/__init__.py +++ b/mne/channels/data/neighbors/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Neighbor definitions for clustering permutation analysis.""" # This is a selection of files from http://fieldtrip.fcdonders.nl/template # Additional definitions can be obtained through the FieldTrip software. diff --git a/mne/channels/interpolation.py b/mne/channels/interpolation.py index 28a5058b3ac..7d5d1a981b7 100644 --- a/mne/channels/interpolation.py +++ b/mne/channels/interpolation.py @@ -1,6 +1,4 @@ -# Authors: Denis Engemann -# Ana Radanovic -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/channels/layout.py b/mne/channels/layout.py index bcfefe5cf2c..eebc6214aee 100644 --- a/mne/channels/layout.py +++ b/mne/channels/layout.py @@ -1,12 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Marijn van Vliet -# Jona Sassenhagen -# Teon Brooks -# Robert Luke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -197,7 +189,7 @@ def pick(self, picks=None, exclude=(), *, verbose=None): picks = [_ensure_int(picks)] except TypeError: picks = ( - list(picks) if isinstance(picks, (tuple, set)) else deepcopy(picks) + list(picks) if isinstance(picks, tuple | set) else deepcopy(picks) ) apply_exclude = False if apply_exclude: @@ -209,13 +201,13 @@ def pick(self, picks=None, exclude=(), *, verbose=None): except TypeError: exclude = ( list(exclude) - if isinstance(exclude, (tuple, set)) + if isinstance(exclude, tuple | set) else deepcopy(exclude) ) for var, var_name in ((picks, "picks"), (exclude, "exclude")): if var_name == "exclude" and not apply_exclude: continue - if not isinstance(var, (list, tuple, set, np.ndarray)): + if not isinstance(var, list | tuple | set | np.ndarray): raise TypeError( f"'{var_name}' must be a list, tuple, set or ndarray. " f"Got {type(var)} instead." @@ -631,7 +623,7 @@ def find_layout(info, ch_type=None, exclude="bads"): elif (has_eeg_coils_only and ch_type in [None, "eeg"]) or ( has_eeg_coils_and_meg and ch_type == "eeg" ): - if not isinstance(info, (dict, Info)): + if not isinstance(info, dict | Info): raise RuntimeError( "Cannot make EEG layout, no measurement info " "was passed to `find_layout`" diff --git a/mne/channels/montage.py b/mne/channels/montage.py index 8ebbce0cfc0..bb2f2006ee4 100644 --- a/mne/channels/montage.py +++ b/mne/channels/montage.py @@ -1,14 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Marijn van Vliet -# Jona Sassenhagen -# Teon Brooks -# Christian Brodbeck -# Stefan Appelhoff -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1547,7 +1537,10 @@ def _read_eeglab_locations(fname): return ch_names, pos -def read_custom_montage(fname, head_size=HEAD_SIZE_DEFAULT, coord_frame=None): +@verbose +def read_custom_montage( + fname, head_size=HEAD_SIZE_DEFAULT, coord_frame=None, *, verbose=None +): """Read a montage from a file. Parameters @@ -1568,6 +1561,7 @@ def read_custom_montage(fname, head_size=HEAD_SIZE_DEFAULT, coord_frame=None): for most readers but ``"head"`` for EEGLAB. .. versionadded:: 0.20 + %(verbose)s Returns ------- diff --git a/mne/channels/tests/__init__.py b/mne/channels/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/channels/tests/__init__.py +++ b/mne/channels/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/channels/tests/test_channels.py b/mne/channels/tests/test_channels.py index 61fe7277156..f51b551a1c8 100644 --- a/mne/channels/tests/test_channels.py +++ b/mne/channels/tests/test_channels.py @@ -1,6 +1,4 @@ -# Author: Daniel G Wakeman -# Denis A. Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/channels/tests/test_interpolation.py b/mne/channels/tests/test_interpolation.py index 31315343ddc..a881a41edcc 100644 --- a/mne/channels/tests/test_interpolation.py +++ b/mne/channels/tests/test_interpolation.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from itertools import compress from pathlib import Path diff --git a/mne/channels/tests/test_layout.py b/mne/channels/tests/test_layout.py index 6dd6bc630be..ad44a6873a4 100644 --- a/mne/channels/tests/test_layout.py +++ b/mne/channels/tests/test_layout.py @@ -1,8 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/channels/tests/test_montage.py b/mne/channels/tests/test_montage.py index 3c756e7262a..d0c406473e8 100644 --- a/mne/channels/tests/test_montage.py +++ b/mne/channels/tests/test_montage.py @@ -1,6 +1,4 @@ -# Author: Teon Brooks -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -302,7 +300,66 @@ def test_documented(): ), "elc", None, - id="ASA electrode", + id="old ASA electrode (elc)", + ), + pytest.param( + partial(read_custom_montage, head_size=None), + ( + "NumberPositions= 96\n" + "UnitPosition mm\n" + "Positions\n" + "E01 : 5.288 -3.658 119.693\n" + "E02 : 59.518 -4.031 101.404\n" + "E03 : 29.949 -50.988 98.145\n" + "Labels\n" + "E01 E02 E03\n" + ), + make_dig_montage( + ch_pos={ + "E01": [0.005288, -0.003658, 0.119693], + "E02": [0.059518, -0.004031, 0.101404], + "E03": [0.029949, -0.050988, 0.098145], + }, + ), + "elc", + None, + id="new ASA electrode (elc)", + ), + pytest.param( + partial(read_custom_montage, head_size=None), + ( + "ReferenceLabel\n" + "avg\n" + "UnitPosition mm\n" + "NumberPositions= 6\n" + "Positions\n" + "-69.2574 10.5895 -25.0009\n" + "3.3791 94.6594 32.2592\n" + "77.2856 12.0537 -30.2488\n" + "4.6147 121.8858 8.6370\n" + "-31.3669 54.0269 94.9191\n" + "-8.7495 56.5653 99.6655\n" + "Labels\n" + "LPA\n" + "Nz\n" + "RPA\n" + "EEG 000\n" + "EEG 001\n" + "EEG 002\n" + ), + make_dig_montage( + ch_pos={ + "EEG 000": [0.004615, 0.121886, 0.008637], + "EEG 001": [-0.031367, 0.054027, 0.094919], + "EEG 002": [-0.00875, 0.056565, 0.099665], + }, + nasion=[0.003379, 0.094659, 0.032259], + lpa=[-0.069257, 0.010589, -0.025001], + rpa=[0.077286, 0.012054, -0.030249], + ), + "elc", + None, + id="another old ASA electrode (elc)", ), pytest.param( partial(read_custom_montage, head_size=1), @@ -524,8 +581,26 @@ def test_montage_readers(reader, file_content, expected_dig, ext, warning, tmp_p actual_ch_pos = dig_montage._get_ch_pos() expected_ch_pos = expected_dig._get_ch_pos() for kk in actual_ch_pos: - assert_allclose(actual_ch_pos[kk], expected_ch_pos[kk], atol=1e-5) + assert_allclose(actual_ch_pos[kk], expected_ch_pos[kk], atol=1e-5, err_msg=kk) assert len(dig_montage.dig) == len(expected_dig.dig) + for key in ("nasion", "lpa", "rpa"): + expected = [ + d + for d in expected_dig.dig + if d["kind"] == FIFF.FIFFV_POINT_CARDINAL + and d["ident"] == getattr(FIFF, f"FIFFV_POINT_{key.upper()}") + ] + got = [ + d + for d in dig_montage.dig + if d["kind"] == FIFF.FIFFV_POINT_CARDINAL + and d["ident"] == getattr(FIFF, f"FIFFV_POINT_{key.upper()}") + ] + assert len(expected) in (0, 1), key + assert len(got) in (0, 1), key + assert len(expected) == len(got) + if len(expected): + assert_allclose(got[0]["r"], expected[0]["r"], atol=1e-5, err_msg=key) for d1, d2 in zip(dig_montage.dig, expected_dig.dig): assert d1["coord_frame"] == d2["coord_frame"] for key in ("coord_frame", "ident", "kind"): diff --git a/mne/channels/tests/test_standard_montage.py b/mne/channels/tests/test_standard_montage.py index 67b57c5cc75..b12b416643d 100644 --- a/mne/channels/tests/test_standard_montage.py +++ b/mne/channels/tests/test_standard_montage.py @@ -1,6 +1,4 @@ -# Authors: Joan Massich -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/channels/tests/test_unify_bads.py b/mne/channels/tests/test_unify_bads.py index f87c7e3ed8d..5575b5dce5b 100644 --- a/mne/channels/tests/test_unify_bads.py +++ b/mne/channels/tests/test_unify_bads.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import pytest from mne.channels import unify_bad_channels diff --git a/mne/chpi.py b/mne/chpi.py index df3069faae7..22909415aaa 100644 --- a/mne/chpi.py +++ b/mne/chpi.py @@ -1,21 +1,21 @@ -"""Functions for fitting head positions with (c)HPI coils.""" - -# Next, ``compute_head_pos`` can be used to: -# -# 1. Drop coils whose GOF are below ``gof_limit``. If fewer than 3 coils -# remain, abandon fitting for the chunk. -# 2. Fit dev_head_t quaternion (using ``_fit_chpi_quat_subset``), -# iteratively dropping coils (as long as 3 remain) to find the best GOF -# (using ``_fit_chpi_quat``). -# 3. If fewer than 3 coils meet the ``dist_limit`` criteria following -# projection of the fitted device coil locations into the head frame, -# abandon fitting for the chunk. -# -# The function ``filter_chpi`` uses the same linear model to filter cHPI -# and (optionally) line frequencies from the data. - -# Authors: Eric Larson -# +"""Functions for fitting head positions with (c)HPI coils. + +``compute_head_pos`` can be used to: + +1. Drop coils whose GOF are below ``gof_limit``. If fewer than 3 coils + remain, abandon fitting for the chunk. +2. Fit dev_head_t quaternion (using ``_fit_chpi_quat_subset``), + iteratively dropping coils (as long as 3 remain) to find the best GOF + (using ``_fit_chpi_quat``). +3. If fewer than 3 coils meet the ``dist_limit`` criteria following + projection of the fitted device coil locations into the head frame, + abandon fitting for the chunk. + +The function ``filter_chpi`` uses the same linear model to filter cHPI +and (optionally) line frequencies from the data. +""" + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/__init__.py b/mne/commands/__init__.py index e331bc0a1cc..1c7134ea78b 100644 --- a/mne/commands/__init__.py +++ b/mne/commands/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Command-line utilities.""" import lazy_loader as lazy diff --git a/mne/commands/mne_anonymize.py b/mne/commands/mne_anonymize.py index 8a66472f1a6..28fae42c82b 100644 --- a/mne/commands/mne_anonymize.py +++ b/mne/commands/mne_anonymize.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python -# Authors : Dominik Krzeminski -# Luke Bloy +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_browse_raw.py b/mne/commands/mne_browse_raw.py index d6a9367ccbd..a6db0e2d6ea 100644 --- a/mne/commands/mne_browse_raw.py +++ b/mne/commands/mne_browse_raw.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python r"""Browse raw data. This uses :func:`mne.io.read_raw` so it supports the same formats @@ -13,7 +12,7 @@ --eve sample_audvis_raw-eve.fif """ -# Authors : Eric Larson, PhD +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_bti2fiff.py b/mne/commands/mne_bti2fiff.py index 2c4e4083df1..8a0606444aa 100644 --- a/mne/commands/mne_bti2fiff.py +++ b/mne/commands/mne_bti2fiff.py @@ -1,10 +1,9 @@ -#!/usr/bin/env python -r"""Import BTi / 4D MagnesWH3600 data to fif file. +"""Import BTi / 4D MagnesWH3600 data to fif file. Notes ----- 1. Currently direct inclusion of reference channel weights - is not supported. Please use \'mne_create_comp_data\' to include + is not supported. Please use 'mne_create_comp_data' to include the weights or use the low level functions from this module to include them by yourself. 2. The informed guess for the 4D name is E31 for the ECG channel and @@ -20,13 +19,7 @@ """ -# Authors: Denis A. Engemann -# Martin Luessi -# Alexandre Gramfort -# Matti Hämäläinen -# Yuval Harpaz -# -# simplified bsd-3 license +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_clean_eog_ecg.py b/mne/commands/mne_clean_eog_ecg.py index d8d2ce2660f..add6e3830af 100644 --- a/mne/commands/mne_clean_eog_ecg.py +++ b/mne/commands/mne_clean_eog_ecg.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """Clean a raw file from EOG and ECG artifacts with PCA (ie SSP). Examples @@ -8,9 +7,8 @@ $ mne clean_eog_ecg -i in_raw.fif -o clean_raw.fif -e -c """ -# Authors : Dr Engr. Sheraz Khan, P.Eng, Ph.D. -# Engr. Nandita Shetty, MS. -# Alexandre Gramfort, Ph.D. + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_compare_fiff.py b/mne/commands/mne_compare_fiff.py index 89aad23cb5c..c619aa57345 100644 --- a/mne/commands/mne_compare_fiff.py +++ b/mne/commands/mne_compare_fiff.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """Compare FIFF files. Examples @@ -9,7 +8,7 @@ """ -# Authors : Eric Larson, PhD +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_compute_proj_ecg.py b/mne/commands/mne_compute_proj_ecg.py index 45c333585ba..42038cf1d60 100644 --- a/mne/commands/mne_compute_proj_ecg.py +++ b/mne/commands/mne_compute_proj_ecg.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python r"""Compute SSP/PCA projections for ECG artifacts. Examples @@ -10,8 +9,8 @@ --rej-grad 3000 --rej-mag 4000 --rej-eeg 100 """ -# Authors : Alexandre Gramfort, Ph.D. -# Martin Luessi, Ph.D. + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_compute_proj_eog.py b/mne/commands/mne_compute_proj_eog.py index eba417b039c..a1e2679646b 100644 --- a/mne/commands/mne_compute_proj_eog.py +++ b/mne/commands/mne_compute_proj_eog.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python r"""Compute SSP/PCA projections for EOG artifacts. Examples @@ -20,8 +19,8 @@ to exclude ECG artifacts from projection computation. """ -# Authors : Alexandre Gramfort, Ph.D. -# Martin Luessi, Ph.D. + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_coreg.py b/mne/commands/mne_coreg.py index c7c2b9287d8..d288c7b53db 100644 --- a/mne/commands/mne_coreg.py +++ b/mne/commands/mne_coreg.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python -# Authors: Christian Brodbeck +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_flash_bem.py b/mne/commands/mne_flash_bem.py index 2d907da9c44..b6c7a1b795d 100644 --- a/mne/commands/mne_flash_bem.py +++ b/mne/commands/mne_flash_bem.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """Create 3-layer BEM model from Flash MRI images. Examples @@ -22,8 +21,8 @@ should be, as usual, in the subject's mri directory. """ # noqa E501 -# Authors: Lorenzo De Santis -# Alexandre Gramfort + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_freeview_bem_surfaces.py b/mne/commands/mne_freeview_bem_surfaces.py index 32fc21d2d24..4edf1465a8a 100644 --- a/mne/commands/mne_freeview_bem_surfaces.py +++ b/mne/commands/mne_freeview_bem_surfaces.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """View the 3-Layers BEM model using Freeview. Examples @@ -8,7 +7,8 @@ $ mne freeview_bem_surfaces -s sample """ -# Authors: Alexandre Gramfort + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_kit2fiff.py b/mne/commands/mne_kit2fiff.py index 5fa770825a2..a6874fecf05 100644 --- a/mne/commands/mne_kit2fiff.py +++ b/mne/commands/mne_kit2fiff.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python -# Authors: Teon Brooks +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_make_scalp_surfaces.py b/mne/commands/mne_make_scalp_surfaces.py index 0d810a41339..5b7d020b98d 100644 --- a/mne/commands/mne_make_scalp_surfaces.py +++ b/mne/commands/mne_make_scalp_surfaces.py @@ -1,10 +1,4 @@ -#!/usr/bin/env python - -# Authors: Denis A. Engemann -# Alexandre Gramfort -# Matti Hämäläinen -# -# simplified bsd-3 license +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_prepare_bem_model.py b/mne/commands/mne_prepare_bem_model.py index 1c1ae874355..3a830e5ec27 100644 --- a/mne/commands/mne_prepare_bem_model.py +++ b/mne/commands/mne_prepare_bem_model.py @@ -1,6 +1,7 @@ -#!/usr/bin/env python +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Create a BEM solution using the linear collocation approach. Examples diff --git a/mne/commands/mne_report.py b/mne/commands/mne_report.py index ce3e1b42805..eec37c445c7 100644 --- a/mne/commands/mne_report.py +++ b/mne/commands/mne_report.py @@ -1,6 +1,7 @@ -#!/usr/bin/env python +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + r"""Create mne report for a folder. Examples diff --git a/mne/commands/mne_setup_forward_model.py b/mne/commands/mne_setup_forward_model.py index f5dda2d061c..29e8616f571 100644 --- a/mne/commands/mne_setup_forward_model.py +++ b/mne/commands/mne_setup_forward_model.py @@ -1,6 +1,7 @@ -#!/usr/bin/env python +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Create a BEM model for a subject. Examples diff --git a/mne/commands/mne_setup_source_space.py b/mne/commands/mne_setup_source_space.py index 723a1ee67d8..e536a59f90b 100644 --- a/mne/commands/mne_setup_source_space.py +++ b/mne/commands/mne_setup_source_space.py @@ -1,6 +1,7 @@ -#!/usr/bin/env python +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Set up bilateral hemisphere surface-based source space with subsampling. Examples diff --git a/mne/commands/mne_show_fiff.py b/mne/commands/mne_show_fiff.py index de1623393f0..2f9e73d2dc1 100644 --- a/mne/commands/mne_show_fiff.py +++ b/mne/commands/mne_show_fiff.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """Show the contents of a FIFF file. Examples @@ -16,7 +15,7 @@ """ -# Authors : Eric Larson, PhD +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_show_info.py b/mne/commands/mne_show_info.py index 96db7734abd..b9448011206 100644 --- a/mne/commands/mne_show_info.py +++ b/mne/commands/mne_show_info.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """Show measurement info from .fif file. Examples @@ -9,7 +8,7 @@ """ -# Authors : Alexandre Gramfort, Ph.D. +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_surf2bem.py b/mne/commands/mne_surf2bem.py index 0dbcba0c55f..5d6426986e8 100644 --- a/mne/commands/mne_surf2bem.py +++ b/mne/commands/mne_surf2bem.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python r"""Convert surface to BEM FIF file. Examples @@ -10,8 +9,8 @@ --id=4 """ -# Authors: Alexandre Gramfort -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_sys_info.py b/mne/commands/mne_sys_info.py index b216cb8db3a..70c56e42f3e 100644 --- a/mne/commands/mne_sys_info.py +++ b/mne/commands/mne_sys_info.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """Show system information. Examples @@ -9,7 +8,7 @@ """ -# Authors : Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/mne_watershed_bem.py b/mne/commands/mne_watershed_bem.py index caf06378f27..4f872b90dac 100644 --- a/mne/commands/mne_watershed_bem.py +++ b/mne/commands/mne_watershed_bem.py @@ -1,7 +1,7 @@ -#!/usr/bin/env python -# Authors: Lorenzo De Santis +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Create BEM surfaces using the watershed algorithm included with FreeSurfer. Examples diff --git a/mne/commands/mne_what.py b/mne/commands/mne_what.py index c899887048d..f6ee1683ba9 100644 --- a/mne/commands/mne_what.py +++ b/mne/commands/mne_what.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python r"""Check type of FIF file. Examples @@ -9,7 +8,7 @@ raw """ -# Authors : Eric Larson, PhD +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/tests/__init__.py b/mne/commands/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/commands/tests/__init__.py +++ b/mne/commands/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/commands/tests/test_commands.py b/mne/commands/tests/test_commands.py index fced5272efc..ac98ef50ad6 100644 --- a/mne/commands/tests/test_commands.py +++ b/mne/commands/tests/test_commands.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import glob import os import shutil diff --git a/mne/commands/utils.py b/mne/commands/utils.py index b3ed3d1d213..beb3a4e98c4 100644 --- a/mne/commands/utils.py +++ b/mne/commands/utils.py @@ -1,8 +1,6 @@ """Some utility functions for commands (e.g., for cmdline handling).""" -# Authors: Yaroslav Halchenko -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/conftest.py b/mne/conftest.py index 9e3637b8208..2a54d1396c8 100644 --- a/mne/conftest.py +++ b/mne/conftest.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -176,6 +175,8 @@ def pytest_configure(config): ignore:__array_wrap__ must accept context and return_scalar arguments.*:DeprecationWarning # nibabel <-> NumPy 2.0 ignore:__array__ implementation doesn't accept a copy.*:DeprecationWarning + # quantities via neo + ignore:The 'copy' argument in Quantity is deprecated.*: """ # noqa: E501 for warning_line in warning_lines.split("\n"): warning_line = warning_line.strip() diff --git a/mne/coreg.py b/mne/coreg.py index ddd7dbb2e7d..f28c6142c96 100644 --- a/mne/coreg.py +++ b/mne/coreg.py @@ -1,7 +1,6 @@ """Coregistration between different coordinate frames.""" -# Authors: Christian Brodbeck -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/cov.py b/mne/cov.py index 0fc03baed16..8dba6f9b8a3 100644 --- a/mne/cov.py +++ b/mne/cov.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Denis A. Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -52,8 +49,8 @@ from .event import make_fixed_length_events from .evoked import EvokedArray from .fixes import ( - BaseEstimator, EmpiricalCovariance, + _EstimatorMixin, _logdet, _safe_svd, empirical_covariance, @@ -834,7 +831,7 @@ def _check_method_params( was_auto = True method = ["shrunk", "diagonal_fixed", "empirical", "factor_analysis"] - if not isinstance(method, (list, tuple)): + if not isinstance(method, list | tuple): method = [method] if not all(k in accepted_methods for k in method): @@ -1515,7 +1512,7 @@ def _auto_low_rank_model( # Sklearn Estimators -class _RegCovariance(BaseEstimator): +class _RegCovariance(_EstimatorMixin): """Aux class.""" def __init__( @@ -1598,7 +1595,7 @@ def get_precision(self): return self.estimator_.get_precision() -class _ShrunkCovariance(BaseEstimator): +class _ShrunkCovariance(_EstimatorMixin): """Aux class.""" def __init__(self, store_precision, assume_centered, shrinkage=0.1): @@ -1616,7 +1613,7 @@ def fit(self, X): cov = self.estimator_.fit(X).covariance_ - if not isinstance(self.shrinkage, (list, tuple)): + if not isinstance(self.shrinkage, list | tuple): shrinkage = [("all", self.shrinkage, np.arange(len(cov)))] else: shrinkage = self.shrinkage diff --git a/mne/cuda.py b/mne/cuda.py index 6941e3f1fc6..f44dc653a1e 100644 --- a/mne/cuda.py +++ b/mne/cuda.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/data/__init__.py b/mne/data/__init__.py index 4f61734f57d..a48c2d63753 100644 --- a/mne/data/__init__.py +++ b/mne/data/__init__.py @@ -1,3 +1,5 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """MNE-Python data.""" diff --git a/mne/datasets/__init__.py b/mne/datasets/__init__.py index 3cc4db8cfc0..700dab0608e 100644 --- a/mne/datasets/__init__.py +++ b/mne/datasets/__init__.py @@ -2,8 +2,11 @@ See :ref:`datasets` for more information. """ + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import lazy_loader as lazy (__getattr__, __dir__, __all__) = lazy.attach_stub(__name__, __file__) diff --git a/mne/datasets/_fake/__init__.py b/mne/datasets/_fake/__init__.py index 511caee1aee..fb116510033 100644 --- a/mne/datasets/_fake/__init__.py +++ b/mne/datasets/_fake/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Fake dataset for testing.""" from ._fake import data_path, get_version diff --git a/mne/datasets/_fake/_fake.py b/mne/datasets/_fake/_fake.py index 155c636f9fc..e983153ef31 100644 --- a/mne/datasets/_fake/_fake.py +++ b/mne/datasets/_fake/_fake.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/_fetch.py b/mne/datasets/_fetch.py index f4d99e329ce..1e38606f908 100644 --- a/mne/datasets/_fetch.py +++ b/mne/datasets/_fetch.py @@ -1,5 +1,4 @@ -# Authors: Adam Li -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/_fsaverage/__init__.py b/mne/datasets/_fsaverage/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/datasets/_fsaverage/__init__.py +++ b/mne/datasets/_fsaverage/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/_fsaverage/base.py b/mne/datasets/_fsaverage/base.py index d027cd6920b..b15a8c7a94c 100644 --- a/mne/datasets/_fsaverage/base.py +++ b/mne/datasets/_fsaverage/base.py @@ -1,11 +1,10 @@ -# Authors: Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. -import os -from pathlib import Path, PosixPath, WindowsPath +from pathlib import Path -from ...utils import get_subjects_dir, set_config, verbose, warn +from ...utils import get_subjects_dir, set_config, verbose from ..utils import _get_path, _manifest_check_download FSAVERAGE_MANIFEST_PATH = Path(__file__).parent @@ -83,7 +82,7 @@ def fetch_fsaverage(subjects_dir=None, *, verbose=None): url="https://osf.io/7ve8g/download?version=4", hash_="b31509cdcf7908af6a83dc5ee8f49fb1", ) - return _mne_path(fs_dir) + return fs_dir def _get_create_subjects_dir(subjects_dir): @@ -102,33 +101,3 @@ def _set_montage_coreg_path(subjects_dir=None): if old_subjects_dir is None: set_config("SUBJECTS_DIR", subjects_dir) return subjects_dir - - -# Adapted from pathlib.Path.__new__ -def _mne_path(path): - klass = MNEWindowsPath if os.name == "nt" else MNEPosixPath - out = klass(path) - assert isinstance(out, klass) - return out - - -class _PathAdd: - def __add__(self, other): - if isinstance(other, str): - warn( - "data_path functions now return pathlib.Path objects which " - "do not natively support the plus (+) operator, switch to " - "using forward slash (/) instead. Support for plus will be " - "removed in 1.2.", - FutureWarning, - ) - return f"{str(self)}{other}" - raise NotImplementedError - - -class MNEWindowsPath(_PathAdd, WindowsPath): # noqa: D101 - pass - - -class MNEPosixPath(_PathAdd, PosixPath): # noqa: D101 - pass diff --git a/mne/datasets/_infant/__init__.py b/mne/datasets/_infant/__init__.py index 7347d36fcd0..d787cc63511 100644 --- a/mne/datasets/_infant/__init__.py +++ b/mne/datasets/_infant/__init__.py @@ -1 +1,5 @@ +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + from .base import fetch_infant_template diff --git a/mne/datasets/_infant/base.py b/mne/datasets/_infant/base.py index 2c75cf234b1..6c4d038aa72 100644 --- a/mne/datasets/_infant/base.py +++ b/mne/datasets/_infant/base.py @@ -1,4 +1,4 @@ -# Authors: Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/_phantom/__init__.py b/mne/datasets/_phantom/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/datasets/_phantom/__init__.py +++ b/mne/datasets/_phantom/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/_phantom/base.py b/mne/datasets/_phantom/base.py index 911ac54a073..52fa6bfaf1f 100644 --- a/mne/datasets/_phantom/base.py +++ b/mne/datasets/_phantom/base.py @@ -1,4 +1,4 @@ -# Authors: Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/brainstorm/__init__.py b/mne/datasets/brainstorm/__init__.py index d9b73e48df3..90a0eaa8e3e 100644 --- a/mne/datasets/brainstorm/__init__.py +++ b/mne/datasets/brainstorm/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Brainstorm datasets.""" from . import bst_raw, bst_resting, bst_auditory, bst_phantom_ctf, bst_phantom_elekta diff --git a/mne/datasets/brainstorm/bst_auditory.py b/mne/datasets/brainstorm/bst_auditory.py index b5b0ba0509c..230fd679870 100644 --- a/mne/datasets/brainstorm/bst_auditory.py +++ b/mne/datasets/brainstorm/bst_auditory.py @@ -1,7 +1,7 @@ -# Authors: Mainak Jas -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from ...utils import verbose from ..utils import ( _data_path_doc_accept, diff --git a/mne/datasets/brainstorm/bst_phantom_ctf.py b/mne/datasets/brainstorm/bst_phantom_ctf.py index b522a60a132..328a7748924 100644 --- a/mne/datasets/brainstorm/bst_phantom_ctf.py +++ b/mne/datasets/brainstorm/bst_phantom_ctf.py @@ -1,7 +1,7 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from ...utils import verbose from ..utils import ( _data_path_doc_accept, diff --git a/mne/datasets/brainstorm/bst_phantom_elekta.py b/mne/datasets/brainstorm/bst_phantom_elekta.py index 31f9efadb63..1a7e3ac1f31 100644 --- a/mne/datasets/brainstorm/bst_phantom_elekta.py +++ b/mne/datasets/brainstorm/bst_phantom_elekta.py @@ -1,7 +1,7 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from ...utils import verbose from ..utils import ( _data_path_doc_accept, diff --git a/mne/datasets/brainstorm/bst_raw.py b/mne/datasets/brainstorm/bst_raw.py index 7d35a89ce5f..13a4aa3e5cc 100644 --- a/mne/datasets/brainstorm/bst_raw.py +++ b/mne/datasets/brainstorm/bst_raw.py @@ -1,7 +1,7 @@ -# Authors: Mainak Jas -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from functools import partial from ...utils import get_config, verbose diff --git a/mne/datasets/brainstorm/bst_resting.py b/mne/datasets/brainstorm/bst_resting.py index 59aabea690b..d740cf1a6bc 100644 --- a/mne/datasets/brainstorm/bst_resting.py +++ b/mne/datasets/brainstorm/bst_resting.py @@ -1,7 +1,7 @@ -# Authors: Mainak Jas -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from ...utils import verbose from ..utils import ( _data_path_doc_accept, diff --git a/mne/datasets/config.py b/mne/datasets/config.py index a2f2d7781b7..ccd4babacd9 100644 --- a/mne/datasets/config.py +++ b/mne/datasets/config.py @@ -1,6 +1,4 @@ -# Authors: Adam Li -# Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -89,7 +87,7 @@ # update the checksum in the MNE_DATASETS dict below, and change version # here: ↓↓↓↓↓↓↓↓ RELEASES = dict( - testing="0.152", + testing="0.156", misc="0.27", phantom_kit="0.2", ucl_opm_auditory="0.2", @@ -117,7 +115,7 @@ # Testing and misc are at the top as they're updated most often MNE_DATASETS["testing"] = dict( archive_name=f"{TESTING_VERSIONED}.tar.gz", - hash="md5:df48cdabcf13ebeaafc617cb8e55b6fc", + hash="md5:d94fe9f3abe949a507eaeb865fb84a3f", url=( "https://codeload.github.com/mne-tools/mne-testing-data/" f'tar.gz/{RELEASES["testing"]}' diff --git a/mne/datasets/eegbci/__init__.py b/mne/datasets/eegbci/__init__.py index 98e79db1c80..ac2a7179596 100644 --- a/mne/datasets/eegbci/__init__.py +++ b/mne/datasets/eegbci/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """EEG Motor Movement/Imagery Dataset.""" from .eegbci import data_path, load_data, standardize diff --git a/mne/datasets/eegbci/eegbci.py b/mne/datasets/eegbci/eegbci.py index 93c6c731932..83dde035d1b 100644 --- a/mne/datasets/eegbci/eegbci.py +++ b/mne/datasets/eegbci/eegbci.py @@ -1,6 +1,4 @@ -# Author: Martin Billinger -# Adam Li -# Daniel McCloy +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/eegbci/tests/test_eegbci.py b/mne/datasets/eegbci/tests/test_eegbci.py index 9912587c836..6ce58861c44 100644 --- a/mne/datasets/eegbci/tests/test_eegbci.py +++ b/mne/datasets/eegbci/tests/test_eegbci.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/epilepsy_ecog/__init__.py b/mne/datasets/epilepsy_ecog/__init__.py index 76d7426d07b..6ecb3379302 100644 --- a/mne/datasets/epilepsy_ecog/__init__.py +++ b/mne/datasets/epilepsy_ecog/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Clinical epilepsy datasets.""" from ._data import data_path, get_version diff --git a/mne/datasets/epilepsy_ecog/_data.py b/mne/datasets/epilepsy_ecog/_data.py index c3f1863994b..20abb9fd8be 100644 --- a/mne/datasets/epilepsy_ecog/_data.py +++ b/mne/datasets/epilepsy_ecog/_data.py @@ -1,5 +1,4 @@ -# Authors: Adam Li -# Alex Rockhill +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/erp_core/__init__.py b/mne/datasets/erp_core/__init__.py index 55164bee284..b16989af413 100644 --- a/mne/datasets/erp_core/__init__.py +++ b/mne/datasets/erp_core/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """ERP-CORE EEG dataset.""" from .erp_core import data_path, get_version diff --git a/mne/datasets/erp_core/erp_core.py b/mne/datasets/erp_core/erp_core.py index 5a9ec38e3b6..2771b17dfe3 100644 --- a/mne/datasets/erp_core/erp_core.py +++ b/mne/datasets/erp_core/erp_core.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from ...utils import verbose from ..utils import _data_path_doc, _download_mne_dataset, _get_version, _version_doc diff --git a/mne/datasets/eyelink/__init__.py b/mne/datasets/eyelink/__init__.py index 686881d34dc..db3ea545b58 100644 --- a/mne/datasets/eyelink/__init__.py +++ b/mne/datasets/eyelink/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Eyelink test dataset.""" from .eyelink import data_path, get_version diff --git a/mne/datasets/eyelink/eyelink.py b/mne/datasets/eyelink/eyelink.py index 1d99596a28e..918ac86f1e8 100644 --- a/mne/datasets/eyelink/eyelink.py +++ b/mne/datasets/eyelink/eyelink.py @@ -1,4 +1,4 @@ -# Authors: Dominik Welke +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/fieldtrip_cmc/__init__.py b/mne/datasets/fieldtrip_cmc/__init__.py index 41aa6c4696b..0ed74466be8 100644 --- a/mne/datasets/fieldtrip_cmc/__init__.py +++ b/mne/datasets/fieldtrip_cmc/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """fieldtrip Cortico-Muscular Coherence (CMC) Dataset.""" from .fieldtrip_cmc import data_path, get_version diff --git a/mne/datasets/fieldtrip_cmc/fieldtrip_cmc.py b/mne/datasets/fieldtrip_cmc/fieldtrip_cmc.py index 9fc0a3eca3a..b61b1d7d188 100644 --- a/mne/datasets/fieldtrip_cmc/fieldtrip_cmc.py +++ b/mne/datasets/fieldtrip_cmc/fieldtrip_cmc.py @@ -1,8 +1,7 @@ -# Authors: Chris Holdgraf -# Alexandre Barachant -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from ...utils import verbose from ..utils import _data_path_doc, _download_mne_dataset, _get_version, _version_doc diff --git a/mne/datasets/fnirs_motor/__init__.py b/mne/datasets/fnirs_motor/__init__.py index 3ce6e67c508..61808bb9fdf 100644 --- a/mne/datasets/fnirs_motor/__init__.py +++ b/mne/datasets/fnirs_motor/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """fNIRS motor dataset.""" from .fnirs_motor import data_path, get_version diff --git a/mne/datasets/fnirs_motor/fnirs_motor.py b/mne/datasets/fnirs_motor/fnirs_motor.py index 81a8dd0de7b..43a4ffc9b96 100644 --- a/mne/datasets/fnirs_motor/fnirs_motor.py +++ b/mne/datasets/fnirs_motor/fnirs_motor.py @@ -1,4 +1,4 @@ -# Authors: Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/hf_sef/__init__.py b/mne/datasets/hf_sef/__init__.py index abb6e43b341..3834a1279b1 100644 --- a/mne/datasets/hf_sef/__init__.py +++ b/mne/datasets/hf_sef/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """HF-SEF dataset.""" from .hf_sef import data_path diff --git a/mne/datasets/hf_sef/hf_sef.py b/mne/datasets/hf_sef/hf_sef.py index 1e07a66522b..aff18315970 100644 --- a/mne/datasets/hf_sef/hf_sef.py +++ b/mne/datasets/hf_sef/hf_sef.py @@ -1,5 +1,6 @@ #!/usr/bin/env python2 -# Authors: Jussi Nurminen + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/kiloword/__init__.py b/mne/datasets/kiloword/__init__.py index 783cac5eb1f..17b54adacf3 100644 --- a/mne/datasets/kiloword/__init__.py +++ b/mne/datasets/kiloword/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """MNE visual_92_categories dataset.""" from .kiloword import data_path, get_version diff --git a/mne/datasets/kiloword/kiloword.py b/mne/datasets/kiloword/kiloword.py index 794bf7758c2..37fd3f1ee6d 100644 --- a/mne/datasets/kiloword/kiloword.py +++ b/mne/datasets/kiloword/kiloword.py @@ -1,3 +1,4 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/limo/__init__.py b/mne/datasets/limo/__init__.py index abf7aa14289..b5622d90302 100644 --- a/mne/datasets/limo/__init__.py +++ b/mne/datasets/limo/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """LIMO Dataset.""" from .limo import data_path, load_data diff --git a/mne/datasets/limo/limo.py b/mne/datasets/limo/limo.py index b5778419474..f0696a78b1e 100644 --- a/mne/datasets/limo/limo.py +++ b/mne/datasets/limo/limo.py @@ -1,5 +1,4 @@ -# Authors: Jose C. Garcia Alanis -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/misc/__init__.py b/mne/datasets/misc/__init__.py index d7a473559a7..25377ca9ceb 100644 --- a/mne/datasets/misc/__init__.py +++ b/mne/datasets/misc/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """MNE misc dataset.""" from ._misc import data_path, _pytest_mark diff --git a/mne/datasets/misc/_misc.py b/mne/datasets/misc/_misc.py index 152ad7dda47..ba7fd2341b1 100644 --- a/mne/datasets/misc/_misc.py +++ b/mne/datasets/misc/_misc.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/mtrf/__init__.py b/mne/datasets/mtrf/__init__.py index 33d5d76e150..13828c026a8 100644 --- a/mne/datasets/mtrf/__init__.py +++ b/mne/datasets/mtrf/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """mTRF Dataset.""" from .mtrf import data_path, get_version diff --git a/mne/datasets/mtrf/mtrf.py b/mne/datasets/mtrf/mtrf.py index b5e404a58f3..78c50027f43 100644 --- a/mne/datasets/mtrf/mtrf.py +++ b/mne/datasets/mtrf/mtrf.py @@ -1,5 +1,4 @@ -# Authors: Chris Holdgraf -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/multimodal/__init__.py b/mne/datasets/multimodal/__init__.py index ba6c658ab0e..7bc3e5571a5 100644 --- a/mne/datasets/multimodal/__init__.py +++ b/mne/datasets/multimodal/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Multimodal dataset.""" from .multimodal import data_path, get_version diff --git a/mne/datasets/multimodal/multimodal.py b/mne/datasets/multimodal/multimodal.py index 1cf58def1cc..60aa7d21bfc 100644 --- a/mne/datasets/multimodal/multimodal.py +++ b/mne/datasets/multimodal/multimodal.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/opm/__init__.py b/mne/datasets/opm/__init__.py index e70077c7086..a587c5f1006 100644 --- a/mne/datasets/opm/__init__.py +++ b/mne/datasets/opm/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """OPM dataset.""" from .opm import data_path, get_version diff --git a/mne/datasets/opm/opm.py b/mne/datasets/opm/opm.py index a7047e0ebdd..a5245ea02d8 100644 --- a/mne/datasets/opm/opm.py +++ b/mne/datasets/opm/opm.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/phantom_4dbti/__init__.py b/mne/datasets/phantom_4dbti/__init__.py index fc36bbede64..c5426171998 100644 --- a/mne/datasets/phantom_4dbti/__init__.py +++ b/mne/datasets/phantom_4dbti/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Multimodal dataset.""" from .phantom_4dbti import data_path, get_version diff --git a/mne/datasets/phantom_4dbti/phantom_4dbti.py b/mne/datasets/phantom_4dbti/phantom_4dbti.py index 96bd04d0f8e..59906a9c110 100644 --- a/mne/datasets/phantom_4dbti/phantom_4dbti.py +++ b/mne/datasets/phantom_4dbti/phantom_4dbti.py @@ -1,5 +1,4 @@ -# Authors: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/phantom_kernel/__init__.py b/mne/datasets/phantom_kernel/__init__.py index ca49adb6f45..ad4aecf0ff8 100644 --- a/mne/datasets/phantom_kernel/__init__.py +++ b/mne/datasets/phantom_kernel/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Multimodal dataset.""" from .phantom_kernel import data_path, get_version diff --git a/mne/datasets/phantom_kernel/phantom_kernel.py b/mne/datasets/phantom_kernel/phantom_kernel.py index a83da820e08..ed44a78977b 100644 --- a/mne/datasets/phantom_kernel/phantom_kernel.py +++ b/mne/datasets/phantom_kernel/phantom_kernel.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/phantom_kit/__init__.py b/mne/datasets/phantom_kit/__init__.py index 684cf36a4c8..7fcc361e073 100644 --- a/mne/datasets/phantom_kit/__init__.py +++ b/mne/datasets/phantom_kit/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """KIT phantom dataset.""" from .phantom_kit import data_path, get_version diff --git a/mne/datasets/phantom_kit/phantom_kit.py b/mne/datasets/phantom_kit/phantom_kit.py index d57ca875f2c..150e08dc435 100644 --- a/mne/datasets/phantom_kit/phantom_kit.py +++ b/mne/datasets/phantom_kit/phantom_kit.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from ...utils import verbose from ..utils import _data_path_doc, _download_mne_dataset, _get_version, _version_doc diff --git a/mne/datasets/refmeg_noise/__init__.py b/mne/datasets/refmeg_noise/__init__.py index 38d4c5f5518..7437aaad6a3 100644 --- a/mne/datasets/refmeg_noise/__init__.py +++ b/mne/datasets/refmeg_noise/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """MEG reference-noise data set.""" from .refmeg_noise import data_path, get_version diff --git a/mne/datasets/refmeg_noise/refmeg_noise.py b/mne/datasets/refmeg_noise/refmeg_noise.py index 69b1cc47f4b..c6c24ff3942 100644 --- a/mne/datasets/refmeg_noise/refmeg_noise.py +++ b/mne/datasets/refmeg_noise/refmeg_noise.py @@ -1,4 +1,4 @@ -# Authors: Jeff Hanna +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/sample/__init__.py b/mne/datasets/sample/__init__.py index 0e6f9e94b15..2c465adb13c 100644 --- a/mne/datasets/sample/__init__.py +++ b/mne/datasets/sample/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """MNE sample dataset.""" from .sample import data_path, get_version diff --git a/mne/datasets/sample/sample.py b/mne/datasets/sample/sample.py index da83c4f0e7e..8dde8c67047 100644 --- a/mne/datasets/sample/sample.py +++ b/mne/datasets/sample/sample.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/sleep_physionet/__init__.py b/mne/datasets/sleep_physionet/__init__.py index 9736f45961e..aff3f92d440 100644 --- a/mne/datasets/sleep_physionet/__init__.py +++ b/mne/datasets/sleep_physionet/__init__.py @@ -1,3 +1,5 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from . import age, temazepam, _utils diff --git a/mne/datasets/sleep_physionet/_utils.py b/mne/datasets/sleep_physionet/_utils.py index acff836366c..b97d0611591 100644 --- a/mne/datasets/sleep_physionet/_utils.py +++ b/mne/datasets/sleep_physionet/_utils.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/sleep_physionet/age.py b/mne/datasets/sleep_physionet/age.py index f947874aa0d..c14282ed202 100644 --- a/mne/datasets/sleep_physionet/age.py +++ b/mne/datasets/sleep_physionet/age.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/sleep_physionet/temazepam.py b/mne/datasets/sleep_physionet/temazepam.py index b3b02c6bd85..443b4057f55 100644 --- a/mne/datasets/sleep_physionet/temazepam.py +++ b/mne/datasets/sleep_physionet/temazepam.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/sleep_physionet/tests/test_physionet.py b/mne/datasets/sleep_physionet/tests/test_physionet.py index 5147be94ab9..5cb315f9064 100644 --- a/mne/datasets/sleep_physionet/tests/test_physionet.py +++ b/mne/datasets/sleep_physionet/tests/test_physionet.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/somato/__init__.py b/mne/datasets/somato/__init__.py index ab2b8e18da8..24ad4524de0 100644 --- a/mne/datasets/somato/__init__.py +++ b/mne/datasets/somato/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Somatosensory dataset.""" from .somato import data_path, get_version diff --git a/mne/datasets/somato/somato.py b/mne/datasets/somato/somato.py index 1f679fc317d..177a642fb2e 100644 --- a/mne/datasets/somato/somato.py +++ b/mne/datasets/somato/somato.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/spm_face/__init__.py b/mne/datasets/spm_face/__init__.py index ebee6f81f1d..a49e3432abe 100644 --- a/mne/datasets/spm_face/__init__.py +++ b/mne/datasets/spm_face/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """SPM face dataset.""" from .spm_data import data_path, has_spm_data, get_version, requires_spm_data diff --git a/mne/datasets/spm_face/spm_data.py b/mne/datasets/spm_face/spm_data.py index 72ab6f2b264..6653796e357 100644 --- a/mne/datasets/spm_face/spm_data.py +++ b/mne/datasets/spm_face/spm_data.py @@ -1,5 +1,4 @@ -# Authors: Denis Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/ssvep/__init__.py b/mne/datasets/ssvep/__init__.py index e5ad9259679..18229cf176c 100644 --- a/mne/datasets/ssvep/__init__.py +++ b/mne/datasets/ssvep/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """SSVEP dataset.""" from .ssvep import data_path, get_version diff --git a/mne/datasets/ssvep/ssvep.py b/mne/datasets/ssvep/ssvep.py index 4ba85be3bec..9f13ace8789 100644 --- a/mne/datasets/ssvep/ssvep.py +++ b/mne/datasets/ssvep/ssvep.py @@ -1,4 +1,4 @@ -# Authors: Dominik Welke +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/testing/__init__.py b/mne/datasets/testing/__init__.py index 3aa0704d4f3..07ad8768029 100644 --- a/mne/datasets/testing/__init__.py +++ b/mne/datasets/testing/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """MNE testing dataset.""" from ._testing import ( diff --git a/mne/datasets/testing/_testing.py b/mne/datasets/testing/_testing.py index 2ead4437bb4..61d454898be 100644 --- a/mne/datasets/testing/_testing.py +++ b/mne/datasets/testing/_testing.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/tests/__init__.py b/mne/datasets/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/datasets/tests/__init__.py +++ b/mne/datasets/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/tests/test_datasets.py b/mne/datasets/tests/test_datasets.py index 3f429ea0f51..042087b8098 100644 --- a/mne/datasets/tests/test_datasets.py +++ b/mne/datasets/tests/test_datasets.py @@ -1,6 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. -import os + import re import shutil import zipfile @@ -87,9 +88,6 @@ def noop(*args, **kwargs): monkeypatch.setattr(mne.datasets._fsaverage.base, "_manifest_check_download", noop) sd_2 = datasets.fetch_fsaverage() assert sd / "fsaverage" == sd_2 - with pytest.warns(FutureWarning, match="switch to using forward slash"): - sd_label_str = sd_2 + f"{os.sep}label" - assert sd_label_str == str(sd_2 / "label") @requires_good_network diff --git a/mne/datasets/ucl_opm_auditory/__init__.py b/mne/datasets/ucl_opm_auditory/__init__.py index 88407e6b87d..94f389a51db 100644 --- a/mne/datasets/ucl_opm_auditory/__init__.py +++ b/mne/datasets/ucl_opm_auditory/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """fNIRS motor dataset.""" from .ucl_opm_auditory import data_path, get_version diff --git a/mne/datasets/ucl_opm_auditory/ucl_opm_auditory.py b/mne/datasets/ucl_opm_auditory/ucl_opm_auditory.py index cd872fdd16a..a9f6f410af4 100644 --- a/mne/datasets/ucl_opm_auditory/ucl_opm_auditory.py +++ b/mne/datasets/ucl_opm_auditory/ucl_opm_auditory.py @@ -1,4 +1,4 @@ -# Authors: Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/utils.py b/mne/datasets/utils.py index 75614d0df2f..34dbf0ef803 100644 --- a/mne/datasets/utils.py +++ b/mne/datasets/utils.py @@ -1,11 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# Eric Larson -# Denis Egnemann -# Stefan Appelhoff -# Adam Li -# Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/datasets/visual_92_categories/__init__.py b/mne/datasets/visual_92_categories/__init__.py index ecd85a5fe95..598795bcc9d 100644 --- a/mne/datasets/visual_92_categories/__init__.py +++ b/mne/datasets/visual_92_categories/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """MNE visual_92_categories dataset.""" from .visual_92_categories import data_path, get_version diff --git a/mne/datasets/visual_92_categories/visual_92_categories.py b/mne/datasets/visual_92_categories/visual_92_categories.py index f7d626cf5ac..b0ec1e67820 100644 --- a/mne/datasets/visual_92_categories/visual_92_categories.py +++ b/mne/datasets/visual_92_categories/visual_92_categories.py @@ -1,3 +1,4 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/decoding/__init__.py b/mne/decoding/__init__.py index 925fa73e5e9..b0dc90e1048 100644 --- a/mne/decoding/__init__.py +++ b/mne/decoding/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Decoding and encoding, including machine learning and receptive fields.""" import lazy_loader as lazy diff --git a/mne/decoding/__init__.pyi b/mne/decoding/__init__.pyi index 4c37a6bc496..2b6c89b2140 100644 --- a/mne/decoding/__init__.pyi +++ b/mne/decoding/__init__.pyi @@ -21,10 +21,15 @@ __all__ = [ "cross_val_multiscore", "get_coef", ] -from .base import BaseEstimator, LinearModel, cross_val_multiscore, get_coef +from .base import ( + BaseEstimator, + LinearModel, + TransformerMixin, + cross_val_multiscore, + get_coef, +) from .csp import CSP, SPoC from .ems import EMS, compute_ems -from .mixin import TransformerMixin from .receptive_field import ReceptiveField from .search_light import GeneralizingEstimator, SlidingEstimator from .ssd import SSD diff --git a/mne/decoding/base.py b/mne/decoding/base.py index cf3d9f29333..a8e457137da 100644 --- a/mne/decoding/base.py +++ b/mne/decoding/base.py @@ -1,9 +1,6 @@ """Base class copy from sklearn.base.""" -# Authors: Gael Varoquaux -# Romain Trachel -# Alexandre Gramfort -# Jean-Remi King -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -11,9 +8,18 @@ import numbers import numpy as np -from scipy.sparse import issparse +from sklearn import model_selection as models +from sklearn.base import ( # noqa: F401 + BaseEstimator, + TransformerMixin, + clone, + is_classifier, +) +from sklearn.linear_model import LogisticRegression +from sklearn.metrics import check_scoring +from sklearn.model_selection import KFold, StratifiedKFold, check_cv +from sklearn.utils import check_array, indexable -from ..fixes import BaseEstimator, _check_fit_params, _get_check_scoring from ..parallel import parallel_func from ..utils import _pl, logger, verbose, warn @@ -67,15 +73,10 @@ class LinearModel(BaseEstimator): def __init__(self, model=None): if model is None: - from sklearn.linear_model import LogisticRegression - model = LogisticRegression(solver="liblinear") self.model = model - def _more_tags(self): - return {"no_validation": True} - def __getattr__(self, attr): """Wrap to model for some attributes.""" if attr in LinearModel._model_attr_wrap: @@ -107,22 +108,14 @@ def fit(self, X, y, **fit_params): self : instance of LinearModel Returns the modified instance. """ - # Once we require sklearn 1.1+ we should do: - # from sklearn.utils import check_array - # X = check_array(X, input_name="X") - # y = check_array(y, dtype=None, ensure_2d=False, input_name="y") - if issparse(X): - raise TypeError("X should be a dense array, got sparse instead.") - X, y = np.asarray(X), np.asarray(y) - if X.ndim != 2: - raise ValueError( - f"LinearModel only accepts 2-dimensional X, got {X.shape} instead." - ) - if y.ndim > 2: - raise ValueError( - f"LinearModel only accepts up to 2-dimensional y, got {y.shape} " - "instead." - ) + X = check_array(X, input_name="X") + if y is not None: + y = check_array(y, dtype=None, ensure_2d=False, input_name="y") + if y.ndim > 2: + raise ValueError( + f"LinearModel only accepts up to 2-dimensional y, got {y.shape} " + "instead." + ) # fit the Model self.model.fit(X, y, **fit_params) @@ -156,17 +149,13 @@ def filters_(self): def _set_cv(cv, estimator=None, X=None, y=None): """Set the default CV depending on whether clf is classifier/regressor.""" # Detect whether classification or regression - from sklearn.base import is_classifier if estimator in ["classifier", "regressor"]: est_is_classifier = estimator == "classifier" else: est_is_classifier = is_classifier(estimator) # Setup CV - from sklearn import model_selection as models - from sklearn.model_selection import KFold, StratifiedKFold, check_cv - - if isinstance(cv, (int, np.int64)): + if isinstance(cv, int | np.int64): XFold = StratifiedKFold if est_is_classifier else KFold cv = XFold(n_splits=cv) elif isinstance(cv, str): @@ -394,12 +383,6 @@ def cross_val_multiscore( Array of scores of the estimator for each run of the cross validation. """ # This code is copied from sklearn - from sklearn.base import clone, is_classifier - from sklearn.model_selection._split import check_cv - from sklearn.utils import indexable - - check_scoring = _get_check_scoring() - X, y, groups = indexable(X, y, groups) cv = check_cv(cv, y, classifier=is_classifier(estimator)) @@ -452,12 +435,16 @@ def _fit_and_score( ): """Fit estimator and compute scores for a given dataset split.""" # This code is adapted from sklearn + from sklearn.model_selection import _validation from sklearn.utils.metaestimators import _safe_split from sklearn.utils.validation import _num_samples # Adjust length of sample weights + fit_params = fit_params if fit_params is not None else {} - fit_params = _check_fit_params(X, fit_params, train) + fit_params = { + k: _validation._index_param_value(X, v, train) for k, v in fit_params.items() + } if parameters is not None: estimator.set_params(**parameters) diff --git a/mne/decoding/csp.py b/mne/decoding/csp.py index 82372243d1c..1261ca82055 100644 --- a/mne/decoding/csp.py +++ b/mne/decoding/csp.py @@ -1,9 +1,4 @@ -# Authors: Romain Trachel -# Alexandre Gramfort -# Alexandre Barachant -# Clemens Brunner -# Jean-Remi King -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -11,6 +6,7 @@ import numpy as np from scipy.linalg import eigh +from sklearn.base import BaseEstimator, TransformerMixin from .._fiff.meas_info import create_info from ..cov import _compute_rank_raw_array, _regularized_covariance, _smart_eigh @@ -20,12 +16,10 @@ _check_option, _validate_type, _verbose_safe_false, - copy_doc, fill_doc, pinv, + warn, ) -from .base import BaseEstimator -from .mixin import TransformerMixin @fill_doc @@ -277,8 +271,31 @@ def inverse_transform(self, X): ) return X[:, np.newaxis, :] * self.patterns_[: self.n_components].T - @copy_doc(TransformerMixin.fit_transform) - def fit_transform(self, X, y, **fit_params): # noqa: D102 + def fit_transform(self, X, y=None, **fit_params): + """Fit CSP to data, then transform it. + + Fits transformer to ``X`` and ``y`` with optional parameters ``fit_params``, and + returns a transformed version of ``X``. + + Parameters + ---------- + X : array, shape (n_epochs, n_channels, n_times) + The data on which to estimate the CSP. + y : array, shape (n_epochs,) + The class for each epoch. + **fit_params : dict + Additional fitting parameters passed to the :meth:`mne.decoding.CSP.fit` + method. Not used for this class. + + Returns + ------- + X_csp : array, shape (n_epochs, n_components[, n_times]) + If ``self.transform_into == 'average_power'`` then returns the power of CSP + features averaged over time and shape is ``(n_epochs, n_components)``. If + ``self.transform_into == 'csp_space'`` then returns the data in CSP space + and shape is ``(n_epochs, n_components, n_times)``. + """ + # use parent TransformerMixin method but with custom docstring return super().fit_transform(X, y=y, **fit_params) @fill_doc @@ -374,6 +391,9 @@ def plot_patterns( if components is None: components = np.arange(self.n_components) + if average is not None: + warn("`average` is deprecated and will be removed in 1.10.", FutureWarning) + # set sampling frequency to have 1 component per time point info = cp.deepcopy(info) with info._unlock(): @@ -505,6 +525,9 @@ def plot_filters( if components is None: components = np.arange(self.n_components) + if average is not None: + warn("`average` is deprecated and will be removed in 1.10.", FutureWarning) + # set sampling frequency to have 1 component per time point info = cp.deepcopy(info) with info._unlock(): @@ -951,3 +974,30 @@ def transform(self, X): space and shape is (n_epochs, n_components, n_times). """ return super().transform(X) + + def fit_transform(self, X, y=None, **fit_params): + """Fit SPoC to data, then transform it. + + Fits transformer to ``X`` and ``y`` with optional parameters ``fit_params``, and + returns a transformed version of ``X``. + + Parameters + ---------- + X : array, shape (n_epochs, n_channels, n_times) + The data on which to estimate the SPoC. + y : array, shape (n_epochs,) + The class for each epoch. + **fit_params : dict + Additional fitting parameters passed to the :meth:`mne.decoding.CSP.fit` + method. Not used for this class. + + Returns + ------- + X : array, shape (n_epochs, n_components[, n_times]) + If ``self.transform_into == 'average_power'`` then returns the power of CSP + features averaged over time and shape is ``(n_epochs, n_components)``. If + ``self.transform_into == 'csp_space'`` then returns the data in CSP space + and shape is ``(n_epochs, n_components, n_times)``. + """ + # use parent TransformerMixin method but with custom docstring + return super().fit_transform(X, y=y, **fit_params) diff --git a/mne/decoding/ems.py b/mne/decoding/ems.py index 9bd7d568919..f6811de460d 100644 --- a/mne/decoding/ems.py +++ b/mne/decoding/ems.py @@ -1,22 +1,19 @@ -# Author: Denis Engemann -# Alexandre Gramfort -# Jean-Remi King -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. from collections import Counter import numpy as np +from sklearn.base import BaseEstimator, TransformerMixin from .._fiff.pick import _picks_to_idx, pick_info, pick_types from ..parallel import parallel_func from ..utils import logger, verbose from .base import _set_cv -from .mixin import EstimatorMixin, TransformerMixin -class EMS(TransformerMixin, EstimatorMixin): +class EMS(BaseEstimator, TransformerMixin): """Transformer to compute event-matched spatial filters. This version of EMS :footcite:`SchurgerEtAl2013` operates on the entire diff --git a/mne/decoding/mixin.py b/mne/decoding/mixin.py deleted file mode 100644 index 3916c156873..00000000000 --- a/mne/decoding/mixin.py +++ /dev/null @@ -1,86 +0,0 @@ -# License: BSD-3-Clause -# Copyright the MNE-Python contributors. -class TransformerMixin: - """Mixin class for all transformers in scikit-learn.""" - - def fit_transform(self, X, y=None, **fit_params): - """Fit to data, then transform it. - - Fits transformer to ``X`` and ``y`` with optional parameters - ``fit_params``, and returns a transformed version of ``X``. - - Parameters - ---------- - X : array, shape (n_samples, n_features) - Training set. - y : array, shape (n_samples,) - Target values or class labels. - **fit_params : dict - Additional fitting parameters passed to the ``fit`` method.. - - Returns - ------- - X_new : array, shape (n_samples, n_features_new) - Transformed array. - """ - # non-optimized default implementation; override when a better - # method is possible for a given clustering algorithm - if y is None: - # fit method of arity 1 (unsupervised transformation) - return self.fit(X, **fit_params).transform(X) - else: - # fit method of arity 2 (supervised transformation) - return self.fit(X, y, **fit_params).transform(X) - - -class EstimatorMixin: - """Mixin class for estimators.""" - - def get_params(self, deep=True): - """Get the estimator params. - - Parameters - ---------- - deep : bool - Deep. - """ - return - - def set_params(self, **params): - """Set parameters (mimics sklearn API). - - Parameters - ---------- - **params : dict - Extra parameters. - - Returns - ------- - inst : object - The instance. - """ - if not params: - return self - valid_params = self.get_params(deep=True) - for key, value in params.items(): - split = key.split("__", 1) - if len(split) > 1: - # nested objects case - name, sub_name = split - if name not in valid_params: - raise ValueError( - f"Invalid parameter {name} for estimator {self}. Check the list" - " of available parameters with `estimator.get_params().keys()`." - ) - sub_object = valid_params[name] - sub_object.set_params(**{sub_name: value}) - else: - # simple objects case - if key not in valid_params: - raise ValueError( - f"Invalid parameter {key} for estimator " - f"{self.__class__.__name__}. Check the list of available " - "parameters with `estimator.get_params().keys()`." - ) - setattr(self, key, value) - return self diff --git a/mne/decoding/receptive_field.py b/mne/decoding/receptive_field.py index 8c5bfc62d90..a9cc72d18ce 100644 --- a/mne/decoding/receptive_field.py +++ b/mne/decoding/receptive_field.py @@ -1,6 +1,4 @@ -# Authors: Chris Holdgraf -# Eric Larson - +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -8,8 +6,10 @@ import numpy as np from scipy.stats import pearsonr +from sklearn.base import clone, is_regressor +from sklearn.metrics import r2_score -from ..utils import _validate_type, fill_doc, pinv, verbose +from ..utils import _validate_type, fill_doc, pinv from .base import BaseEstimator, _check_estimator, get_coef from .time_delaying_ridge import TimeDelayingRidge @@ -67,7 +67,6 @@ class ReceptiveField(BaseEstimator): duration. Only used if ``estimator`` is float or None. .. versionadded:: 0.18 - %(verbose)s Attributes ---------- @@ -103,7 +102,6 @@ class ReceptiveField(BaseEstimator): .. footbibliography:: """ # noqa E501 - @verbose def __init__( self, tmin, @@ -116,12 +114,11 @@ def __init__( patterns=False, n_jobs=None, edge_correction=True, - verbose=None, ): - self.feature_names = feature_names - self.sfreq = float(sfreq) self.tmin = tmin self.tmax = tmax + self.sfreq = sfreq + self.feature_names = feature_names self.estimator = 0.0 if estimator is None else estimator self.fit_intercept = fit_intercept self.scoring = scoring @@ -129,9 +126,6 @@ def __init__( self.n_jobs = n_jobs self.edge_correction = edge_correction - def _more_tags(self): - return {"no_validation": True} - def __repr__(self): # noqa: D105 s = f"tmin, tmax : ({self.tmin:.3f}, {self.tmax:.3f}), " estimator = self.estimator @@ -160,7 +154,7 @@ def _delay_and_reshape(self, X, y=None): X, self.tmin, self.tmax, - self.sfreq, + self.sfreq_, fill_mean=self.fit_intercept_, ) X = _reshape_for_est(X) @@ -188,14 +182,13 @@ def fit(self, X, y): raise ValueError( f"scoring must be one of {sorted(_SCORERS.keys())}, got {self.scoring} " ) - from sklearn.base import clone, is_regressor - + self.sfreq_ = float(self.sfreq) X, y, _, self._y_dim = self._check_dimensions(X, y) if self.tmin > self.tmax: raise ValueError(f"tmin ({self.tmin}) must be at most tmax ({self.tmax})") # Initialize delays - self.delays_ = _times_to_delays(self.tmin, self.tmax, self.sfreq) + self.delays_ = _times_to_delays(self.tmin, self.tmax, self.sfreq_) # Define the slice that we should use in the middle self.valid_samples_ = _delays_to_slice(self.delays_) @@ -208,7 +201,7 @@ def fit(self, X, y): estimator = TimeDelayingRidge( self.tmin, self.tmax, - self.sfreq, + self.sfreq_, alpha=self.estimator, fit_intercept=self.fit_intercept_, n_jobs=self.n_jobs, @@ -516,8 +509,6 @@ def _corr_score(y_true, y, multioutput=None): def _r2_score(y_true, y, multioutput=None): - from sklearn.metrics import r2_score - return r2_score(y_true, y, multioutput=multioutput) diff --git a/mne/decoding/search_light.py b/mne/decoding/search_light.py index 0cd6707da7f..64f38a60634 100644 --- a/mne/decoding/search_light.py +++ b/mne/decoding/search_light.py @@ -1,17 +1,18 @@ -# Author: Jean-Remi King -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import logging import numpy as np -from scipy.sparse import issparse +from sklearn.base import BaseEstimator, TransformerMixin, clone +from sklearn.metrics import check_scoring +from sklearn.preprocessing import LabelEncoder +from sklearn.utils import check_array -from ..fixes import _get_check_scoring from ..parallel import parallel_func from ..utils import ProgressBar, _parse_verbose, array_split_idx, fill_doc, verbose -from .base import BaseEstimator, _check_estimator -from .mixin import TransformerMixin +from .base import _check_estimator @fill_doc @@ -56,9 +57,6 @@ def __init__( self.allow_2d = allow_2d self.verbose = verbose - def _more_tags(self): - return {"no_validation": True, "requires_fit": False} - @property def _estimator_type(self): return getattr(self.base_estimator, "_estimator_type", None) @@ -256,14 +254,9 @@ def decision_function(self, X): def _check_Xy(self, X, y=None): """Aux. function to check input data.""" # Once we require sklearn 1.1+ we should do something like: - # from sklearn.utils import check_array - # X = check_array(X, ensure_2d=False, input_name="X") - # y = check_array(y, dtype=None, ensure_2d=False, input_name="y") - if issparse(X): - raise TypeError("X should be a dense array, got sparse instead.") - X = np.asarray(X) + X = check_array(X, ensure_2d=False, allow_nd=True, input_name="X") if y is not None: - y = np.asarray(y) + y = check_array(y, dtype=None, ensure_2d=False, input_name="y") if len(X) != len(y) or len(y) < 1: raise ValueError("X and y must have the same length.") if X.ndim < 3: @@ -300,8 +293,6 @@ def score(self, X, y): score : array, shape (n_samples, n_estimators) Score for each estimator/task. """ # noqa: E501 - check_scoring = _get_check_scoring() - X = self._check_Xy(X, y) if X.shape[-1] != len(self.estimators_): raise ValueError("The number of estimators does not match X.shape[-1]") @@ -357,8 +348,6 @@ def _sl_fit(estimator, X, y, pb, **fit_params): estimators_ : list of estimators The fitted estimators. """ - from sklearn.base import clone - estimators_ = list() for ii in range(X.shape[-1]): est = clone(estimator) @@ -600,7 +589,6 @@ def score(self, X, y): score : array, shape (n_samples, n_estimators, n_slices) Score for each estimator / data slice couple. """ # noqa: E501 - check_scoring = _get_check_scoring() X = self._check_Xy(X, y) # For predictions/transforms the parallelization is across the data and # not across the estimators to avoid memory load. @@ -719,8 +707,6 @@ def _gl_score(estimators, scoring, X, y, pb): def _fix_auc(scoring, y): - from sklearn.preprocessing import LabelEncoder - # This fixes sklearn's inability to compute roc_auc when y not in [0, 1] # scikit-learn/scikit-learn#6874 if scoring is not None: diff --git a/mne/decoding/ssd.py b/mne/decoding/ssd.py index 4b05cb7a4d0..4043aa99835 100644 --- a/mne/decoding/ssd.py +++ b/mne/decoding/ssd.py @@ -1,17 +1,15 @@ -# Author: Denis A. Engemann -# Victoria Peterson -# Thomas S. Binns +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import numpy as np from scipy.linalg import eigh +from sklearn.base import BaseEstimator, TransformerMixin from .._fiff.pick import _picks_to_idx from ..cov import Covariance, _regularized_covariance from ..defaults import _handle_default from ..filter import filter_data -from ..fixes import BaseEstimator from ..rank import compute_rank from ..time_frequency import psd_array_welch from ..utils import ( @@ -22,7 +20,6 @@ fill_doc, logger, ) -from .mixin import TransformerMixin @fill_doc @@ -115,7 +112,7 @@ def __init__( f"{param + '_freq'} must be defined in filter parameters for {key}" ) val = dicts[key][param + "_freq"] - if not isinstance(val, (int, float)): + if not isinstance(val, int | float): _validate_type(val, ("numeric",), f"{key} {param}_freq") # check freq bands if ( @@ -127,14 +124,8 @@ def __init__( "The signal band-pass must be within the noise " "band-pass!" ) - self.picks_ = _picks_to_idx(info, picks, none="data", exclude="bads") + self.picks = picks del picks - ch_types = info.get_channel_types(picks=self.picks_, unique=True) - if len(ch_types) > 1: - raise ValueError( - "At this point SSD only supports fitting " - "single channel types. Your info has %i types" % (len(ch_types)) - ) self.info = info self.freqs_signal = (filt_params_signal["l_freq"], filt_params_signal["h_freq"]) self.freqs_noise = (filt_params_noise["l_freq"], filt_params_noise["h_freq"]) @@ -185,6 +176,13 @@ def fit(self, X, y=None): self : instance of SSD Returns the modified instance. """ + ch_types = self.info.get_channel_types(picks=self.picks, unique=True) + if len(ch_types) > 1: + raise ValueError( + "At this point SSD only supports fitting " + "single channel types. Your info has %i types" % (len(ch_types)) + ) + self.picks_ = _picks_to_idx(self.info, self.picks, none="data", exclude="bads") self._check_X(X) X_aux = X[..., self.picks_, :] @@ -263,6 +261,31 @@ def transform(self, X): X_ssd = X_ssd[:, self.sorter_spec, :][:, : self.n_components, :] return X_ssd + def fit_transform(self, X, y=None, **fit_params): + """Fit SSD to data, then transform it. + + Fits transformer to ``X`` and ``y`` with optional parameters ``fit_params``, and + returns a transformed version of ``X``. + + Parameters + ---------- + X : array, shape ([n_epochs, ]n_channels, n_times) + The input data from which to estimate the SSD. Either 2D array obtained from + continuous data or 3D array obtained from epoched data. + y : None + Ignored; exists for compatibility with scikit-learn pipelines. + **fit_params : dict + Additional fitting parameters passed to the :meth:`mne.decoding.SSD.fit` + method. Not used for this class. + + Returns + ------- + X_ssd : array, shape ([n_epochs, ]n_components, n_times) + The processed data. + """ + # use parent TransformerMixin method but with custom docstring + return super().fit_transform(X, y=y, **fit_params) + def get_spectral_ratio(self, ssd_sources): """Get the spectal signal-to-noise ratio for each spatial filter. diff --git a/mne/decoding/tests/__init__.py b/mne/decoding/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/decoding/tests/__init__.py +++ b/mne/decoding/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/decoding/tests/test_base.py b/mne/decoding/tests/test_base.py index 3ce1657e468..25fbba3fafd 100644 --- a/mne/decoding/tests/test_base.py +++ b/mne/decoding/tests/test_base.py @@ -1,6 +1,4 @@ -# Author: Jean-Remi King, -# Marijn van Vliet, -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -16,6 +14,30 @@ assert_equal, ) +pytest.importorskip("sklearn") + +from sklearn import svm +from sklearn.base import ( + BaseEstimator as sklearn_BaseEstimator, +) +from sklearn.base import ( + TransformerMixin as sklearn_TransformerMixin, +) +from sklearn.base import ( + is_classifier, + is_regressor, +) +from sklearn.linear_model import LinearRegression, LogisticRegression, Ridge +from sklearn.model_selection import ( + GridSearchCV, + KFold, + StratifiedKFold, + cross_val_score, +) +from sklearn.pipeline import make_pipeline +from sklearn.preprocessing import StandardScaler +from sklearn.utils.estimator_checks import parametrize_with_checks + from mne import EpochsArray, create_info from mne.decoding import GeneralizingEstimator, Scaler, TransformerMixin, Vectorizer from mne.decoding.base import ( @@ -27,8 +49,6 @@ ) from mne.decoding.search_light import SlidingEstimator -pytest.importorskip("sklearn") - def _make_data(n_samples=1000, n_features=5, n_targets=3): """Generate some testing data. @@ -69,20 +89,9 @@ def _make_data(n_samples=1000, n_features=5, n_targets=3): return X, Y, A +@pytest.mark.filterwarnings("ignore:invalid value encountered in cast.*:RuntimeWarning") def test_get_coef(): """Test getting linear coefficients (filters/patterns) from estimators.""" - from sklearn import svm - from sklearn.base import ( - BaseEstimator, - TransformerMixin, - is_classifier, - is_regressor, - ) - from sklearn.linear_model import Ridge - from sklearn.model_selection import GridSearchCV - from sklearn.pipeline import make_pipeline - from sklearn.preprocessing import StandardScaler - lm_classification = LinearModel() assert is_classifier(lm_classification) @@ -101,6 +110,8 @@ def test_get_coef(): assert is_regressor(lm_gs_regression) # Define a classifier, an invertible transformer and an non-invertible one. + assert BaseEstimator is sklearn_BaseEstimator + assert TransformerMixin is sklearn_TransformerMixin class Clf(BaseEstimator): def fit(self, X, y): @@ -224,9 +235,6 @@ def transform(self, X): ) def test_get_coef_inverse_transform(inverse, Scale, kwargs): """Test get_coef with and without inverse_transform.""" - from sklearn.linear_model import Ridge - from sklearn.pipeline import make_pipeline - lm_regression = LinearModel(Ridge()) X, y, A = _make_data(n_samples=1000, n_features=3, n_targets=1) # Check with search_light and combination of preprocessing ending with sl: @@ -255,9 +263,6 @@ def test_get_coef_inverse_transform(inverse, Scale, kwargs): def test_get_coef_multiclass(n_features, n_targets): """Test get_coef on multiclass problems.""" # Check patterns with more than 1 regressor - from sklearn.linear_model import LinearRegression, Ridge - from sklearn.pipeline import make_pipeline - X, Y, A = _make_data(n_samples=30000, n_features=n_features, n_targets=n_targets) lm = LinearModel(LinearRegression()).fit(X, Y) assert_array_equal(lm.filters_.shape, lm.patterns_.shape) @@ -309,10 +314,6 @@ def test_get_coef_multiclass(n_features, n_targets): @pytest.mark.filterwarnings("ignore:'multi_class' was deprecated in.*:FutureWarning") def test_get_coef_multiclass_full(n_classes, n_channels, n_times): """Test a full example with pattern extraction.""" - from sklearn.linear_model import LogisticRegression - from sklearn.model_selection import StratifiedKFold - from sklearn.pipeline import make_pipeline - data = np.zeros((10 * n_classes, n_channels, n_times)) # Make only the first channel informative for ii in range(n_classes): @@ -348,8 +349,6 @@ def test_get_coef_multiclass_full(n_classes, n_channels, n_times): def test_linearmodel(): """Test LinearModel class for computing filters and patterns.""" # check categorical target fit in standard linear model - from sklearn.linear_model import LinearRegression - rng = np.random.RandomState(0) clf = LinearModel() n, n_features = 20, 3 @@ -363,9 +362,6 @@ def test_linearmodel(): clf.fit(wrong_X, y) # check categorical target fit in standard linear model with GridSearchCV - from sklearn import svm - from sklearn.model_selection import GridSearchCV - parameters = {"kernel": ["linear"], "C": [1, 10]} clf = LinearModel( GridSearchCV(svm.SVC(), parameters, cv=2, refit=True, n_jobs=None) @@ -404,9 +400,6 @@ def test_linearmodel(): def test_cross_val_multiscore(): """Test cross_val_multiscore for computing scores on decoding over time.""" - from sklearn.linear_model import LinearRegression, LogisticRegression - from sklearn.model_selection import KFold, StratifiedKFold, cross_val_score - logreg = LogisticRegression(solver="liblinear", random_state=0) # compare to cross-val-score @@ -463,19 +456,15 @@ def test_cross_val_multiscore(): assert_array_equal(manual, auto) -def test_sklearn_compliance(): +@parametrize_with_checks([LinearModel(LogisticRegression())]) +def test_sklearn_compliance(estimator, check): """Test LinearModel compliance with sklearn.""" - pytest.importorskip("sklearn") - from sklearn.linear_model import LogisticRegression - from sklearn.utils.estimator_checks import check_estimator - - lm = LinearModel(LogisticRegression()) ignores = ( + "check_n_features_in", # maybe we should add this someday? "check_estimator_sparse_data", # we densify "check_estimators_overwrite_params", # self.model changes! "check_parameters_default_constructible", ) - for est, check in check_estimator(lm, generate_only=True): - if any(ignore in str(check) for ignore in ignores): - continue - check(est) + if any(ignore in str(check) for ignore in ignores): + return + check(estimator) diff --git a/mne/decoding/tests/test_csp.py b/mne/decoding/tests/test_csp.py index 5dd297dc2f8..7a1a83feeaf 100644 --- a/mne/decoding/tests/test_csp.py +++ b/mne/decoding/tests/test_csp.py @@ -1,8 +1,4 @@ -# Author: Alexandre Gramfort -# Romain Trachel -# Alexandre Barachant -# Jean-Remi King -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -17,6 +13,13 @@ assert_equal, ) +pytest.importorskip("sklearn") + +from sklearn.linear_model import LogisticRegression +from sklearn.model_selection import StratifiedKFold, cross_val_score +from sklearn.pipeline import Pipeline, make_pipeline +from sklearn.svm import SVC + from mne import Epochs, compute_proj_raw, io, pick_types, read_events from mne.decoding import CSP, LinearModel, Scaler, SPoC, get_coef from mne.decoding.csp import _ajd_pham @@ -259,11 +262,6 @@ def test_csp(): @pytest.mark.parametrize("reg", [None, 0.001, "oas"]) def test_regularized_csp(ch_type, rank, reg): """Test Common Spatial Patterns algorithm using regularized covariance.""" - pytest.importorskip("sklearn") - from sklearn.linear_model import LogisticRegression - from sklearn.model_selection import StratifiedKFold, cross_val_score - from sklearn.pipeline import make_pipeline - raw = io.read_raw_fif(raw_fname).pick(ch_type, exclude="bads").load_data() n_orig = len(raw.ch_names) ch_decim = 2 @@ -377,10 +375,6 @@ def test_regularized_csp(ch_type, rank, reg): def test_csp_pipeline(): """Test if CSP works in a pipeline.""" - pytest.importorskip("sklearn") - from sklearn.pipeline import Pipeline - from sklearn.svm import SVC - csp = CSP(reg=1, norm_trace=False) svc = SVC() pipe = Pipeline([("CSP", csp), ("SVC", svc)]) diff --git a/mne/decoding/tests/test_ems.py b/mne/decoding/tests/test_ems.py index e32664608ce..10774c0681a 100644 --- a/mne/decoding/tests/test_ems.py +++ b/mne/decoding/tests/test_ems.py @@ -1,5 +1,4 @@ -# Author: Denis A. Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -9,6 +8,10 @@ import pytest from numpy.testing import assert_array_almost_equal, assert_equal +pytest.importorskip("sklearn") + +from sklearn.model_selection import StratifiedKFold + from mne import Epochs, io, pick_types, read_events from mne.decoding import EMS, compute_ems @@ -18,13 +21,9 @@ tmin, tmax = -0.2, 0.5 event_id = dict(aud_l=1, vis_l=3) -pytest.importorskip("sklearn") - def test_ems(): """Test event-matched spatial filters.""" - from sklearn.model_selection import StratifiedKFold - raw = io.read_raw_fif(raw_fname, preload=False) # create unequal number of events diff --git a/mne/decoding/tests/test_receptive_field.py b/mne/decoding/tests/test_receptive_field.py index e0f146af9cc..5d7e1ff0661 100644 --- a/mne/decoding/tests/test_receptive_field.py +++ b/mne/decoding/tests/test_receptive_field.py @@ -1,5 +1,4 @@ -# Authors: Chris Holdgraf -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -11,6 +10,11 @@ from numpy.fft import irfft, rfft from numpy.testing import assert_allclose, assert_array_equal, assert_equal +pytest.importorskip("sklearn") + +from sklearn.linear_model import Ridge +from sklearn.utils.estimator_checks import parametrize_with_checks + from mne.decoding import ReceptiveField, TimeDelayingRidge from mne.decoding.receptive_field import ( _SCORERS, @@ -80,9 +84,6 @@ def test_compute_reg_neighbors(): def test_rank_deficiency(): """Test signals that are rank deficient.""" # See GH#4253 - pytest.importorskip("sklearn") - from sklearn.linear_model import Ridge - N = 256 fs = 1.0 tmin, tmax = -50, 100 @@ -175,9 +176,6 @@ def test_time_delay(): @pytest.mark.parametrize("n_jobs", n_jobs_test) def test_receptive_field_basic(n_jobs): """Test model prep and fitting.""" - pytest.importorskip("sklearn") - from sklearn.linear_model import Ridge - # Make sure estimator pulling works mod = Ridge() rng = np.random.RandomState(1337) @@ -373,9 +371,6 @@ def test_time_delaying_fast_calc(n_jobs): @pytest.mark.parametrize("n_jobs", n_jobs_test) def test_receptive_field_1d(n_jobs): """Test that the fast solving works like Ridge.""" - pytest.importorskip("sklearn") - from sklearn.linear_model import Ridge - rng = np.random.RandomState(0) x = rng.randn(500, 1) for delay in range(-2, 3): @@ -434,9 +429,6 @@ def test_receptive_field_1d(n_jobs): @pytest.mark.parametrize("n_jobs", n_jobs_test) def test_receptive_field_nd(n_jobs): """Test multidimensional support.""" - pytest.importorskip("sklearn") - from sklearn.linear_model import Ridge - # multidimensional rng = np.random.RandomState(3) x = rng.randn(1000, 3) @@ -553,9 +545,6 @@ def _make_data(n_feats, n_targets, n_samples, tmin, tmax): def test_inverse_coef(): """Test inverse coefficients computation.""" - pytest.importorskip("sklearn") - from sklearn.linear_model import Ridge - tmin, tmax = 0.0, 10.0 n_feats, n_targets, n_samples = 3, 2, 1000 n_delays = int((tmax - tmin) + 1) @@ -584,9 +573,6 @@ def test_inverse_coef(): def test_linalg_warning(): """Test that warnings are issued when no regularization is applied.""" - pytest.importorskip("sklearn") - from sklearn.linear_model import Ridge - n_feats, n_targets, n_samples = 5, 60, 50 X, y = _make_data(n_feats, n_targets, n_samples, tmin, tmax) for estimator in (0.0, Ridge(alpha=0.0)): @@ -597,12 +583,9 @@ def test_linalg_warning(): rf.fit(y, X) -def test_tdr_sklearn_compliance(): +@parametrize_with_checks([TimeDelayingRidge(0, 10, 1.0, 0.1, "laplacian", n_jobs=1)]) +def test_tdr_sklearn_compliance(estimator, check): """Test sklearn estimator compliance.""" - pytest.importorskip("sklearn") - from sklearn.utils.estimator_checks import check_estimator - - tdr = TimeDelayingRidge(0, 10, 1.0, 0.1, "laplacian", n_jobs=1) # We don't actually comply with a bunch of the regressor specs :( ignores = ( "check_supervised_y_no_nan", @@ -610,27 +593,36 @@ def test_tdr_sklearn_compliance(): "check_parameters_default_constructible", "check_estimators_unfitted", "_invariance", + "check_complex_data", + "check_estimators_empty_data_messages", + "check_estimators_nan_inf", + "check_supervised_y_2d", + "check_n_features_in", "check_fit2d_1sample", + "check_fit1d", + "check_fit2d_predict1d", + "check_requires_y_none", ) - for est, check in check_estimator(tdr, generate_only=True): - if any(ignore in str(check) for ignore in ignores): - continue - check(est) + if any(ignore in str(check) for ignore in ignores): + return + check(estimator) -def test_rf_sklearn_compliance(): +@pytest.mark.filterwarnings("ignore:.*invalid value encountered in subtract.*:") +@parametrize_with_checks([ReceptiveField(-1, 2, 1.0, estimator=Ridge(), patterns=True)]) +def test_rf_sklearn_compliance(estimator, check): """Test sklearn RF compliance.""" - pytest.importorskip("sklearn") - from sklearn.linear_model import Ridge - from sklearn.utils.estimator_checks import check_estimator - - rf = ReceptiveField(-1, 2, 1.0, estimator=Ridge(), patterns=True) ignores = ( "check_parameters_default_constructible", "_invariance", "check_fit2d_1sample", + # Should probably fix these? + "check_complex_data", + "check_dtype_object", + "check_estimators_empty_data_messages", + "check_n_features_in", + "check_fit2d_predict1d", ) - for est, check in check_estimator(rf, generate_only=True): - if any(ignore in str(check) for ignore in ignores): - continue - check(est) + if any(ignore in str(check) for ignore in ignores): + return + check(estimator) diff --git a/mne/decoding/tests/test_search_light.py b/mne/decoding/tests/test_search_light.py index d78b123f746..9e15a1df59b 100644 --- a/mne/decoding/tests/test_search_light.py +++ b/mne/decoding/tests/test_search_light.py @@ -1,5 +1,4 @@ -# Author: Jean-Remi King, -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -10,11 +9,22 @@ import pytest from numpy.testing import assert_array_equal, assert_equal +sklearn = pytest.importorskip("sklearn") + +from sklearn.base import BaseEstimator, clone, is_classifier +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis +from sklearn.ensemble import BaggingClassifier +from sklearn.linear_model import LinearRegression, LogisticRegression, Ridge +from sklearn.metrics import make_scorer, roc_auc_score +from sklearn.model_selection import cross_val_predict +from sklearn.multiclass import OneVsRestClassifier +from sklearn.pipeline import make_pipeline +from sklearn.svm import SVC +from sklearn.utils.estimator_checks import parametrize_with_checks + from mne.decoding.search_light import GeneralizingEstimator, SlidingEstimator from mne.decoding.transformer import Vectorizer -from mne.utils import _record_warnings, check_version, use_log_level - -sklearn = pytest.importorskip("sklearn") +from mne.utils import check_version, use_log_level NEW_MULTICLASS_SAMPLE_WEIGHT = check_version("sklearn", "1.4") @@ -36,14 +46,6 @@ def test_search_light(): # https://github.com/scikit-learn/scikit-learn/issues/27711 if platform.system() == "Windows" and check_version("numpy", "2.0.0.dev0"): pytest.skip("sklearn int_t / long long mismatch") - from sklearn.linear_model import LogisticRegression, Ridge - from sklearn.metrics import make_scorer, roc_auc_score - from sklearn.multiclass import OneVsRestClassifier - from sklearn.pipeline import make_pipeline - - with _record_warnings(): # NumPy module import - from sklearn.ensemble import BaggingClassifier - from sklearn.base import is_classifier logreg = OneVsRestClassifier(LogisticRegression(solver="liblinear", random_state=0)) @@ -198,11 +200,6 @@ def metadata_routing(): def test_generalization_light(metadata_routing): """Test GeneralizingEstimator.""" - from sklearn.linear_model import LogisticRegression - from sklearn.metrics import roc_auc_score - from sklearn.multiclass import OneVsRestClassifier - from sklearn.pipeline import make_pipeline - if NEW_MULTICLASS_SAMPLE_WEIGHT: clf = LogisticRegression(random_state=0) clf.set_fit_request(sample_weight=True) @@ -297,8 +294,6 @@ def test_generalization_light(metadata_routing): ) def test_verbose_arg(capsys, n_jobs, verbose): """Test controlling output with the ``verbose`` argument.""" - from sklearn.svm import SVC - X, y = make_data() clf = SVC() @@ -319,11 +314,6 @@ def test_verbose_arg(capsys, n_jobs, verbose): def test_cross_val_predict(): """Test cross_val_predict with predict_proba.""" - from sklearn.base import BaseEstimator, clone - from sklearn.discriminant_analysis import LinearDiscriminantAnalysis - from sklearn.linear_model import LinearRegression - from sklearn.model_selection import cross_val_predict - rng = np.random.RandomState(42) X = rng.randn(10, 1, 3) y = rng.randint(0, 2, 10) @@ -353,13 +343,9 @@ def predict_proba(self, X): @pytest.mark.slowtest -def test_sklearn_compliance(): +@parametrize_with_checks([SlidingEstimator(LogisticRegression(), allow_2d=True)]) +def test_sklearn_compliance(estimator, check): """Test LinearModel compliance with sklearn.""" - from sklearn.linear_model import LogisticRegression - from sklearn.utils.estimator_checks import check_estimator - - est = SlidingEstimator(LogisticRegression(), allow_2d=True) - ignores = ( "check_estimator_sparse_data", # we densify "check_classifiers_one_label_sample_weights", # don't handle singleton @@ -367,8 +353,13 @@ def test_sklearn_compliance(): "check_classifiers_train", "check_decision_proba_consistency", "check_parameters_default_constructible", + # Should probably fix these? + "check_estimators_unfitted", + "check_transformer_data_not_an_array", + "check_n_features_in", + "check_fit2d_predict1d", + "check_do_not_raise_errors_in_init_or_set_params", ) - for est, check in check_estimator(est, generate_only=True): - if any(ignore in str(check) for ignore in ignores): - continue - check(est) + if any(ignore in str(check) for ignore in ignores): + return + check(estimator) diff --git a/mne/decoding/tests/test_ssd.py b/mne/decoding/tests/test_ssd.py index e72e0ff81ad..198feeb6532 100644 --- a/mne/decoding/tests/test_ssd.py +++ b/mne/decoding/tests/test_ssd.py @@ -1,13 +1,17 @@ -# Author: Denis A. Engemann -# Victoria Peterson -# Thomas S. Binns +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. +import sys + import numpy as np import pytest from numpy.testing import assert_array_almost_equal, assert_array_equal +pytest.importorskip("sklearn") + +from sklearn.pipeline import Pipeline + from mne import create_info, io from mne.decoding import CSP from mne.decoding.ssd import SSD @@ -150,8 +154,9 @@ def test_ssd(): ch_types = np.reshape([["mag"] * 10, ["eeg"] * 10], n_channels) info_2 = create_info(ch_names=n_channels, sfreq=sf, ch_types=ch_types) + ssd = SSD(info_2, filt_params_signal, filt_params_noise) with pytest.raises(ValueError, match="At this point SSD"): - ssd = SSD(info_2, filt_params_signal, filt_params_noise) + ssd.fit(X) # Number of channels info_3 = create_info(ch_names=n_channels + 1, sfreq=sf, ch_types="eeg") @@ -298,9 +303,6 @@ def test_ssd_epoched_data(): def test_ssd_pipeline(): """Test if SSD works in a pipeline.""" - pytest.importorskip("sklearn") - from sklearn.pipeline import Pipeline - sf = 250 X, A, S = simulate_data(n_trials=100, n_channels=20, n_samples=500) X_e = np.reshape(X, (100, 20, 500)) @@ -471,4 +473,6 @@ def test_non_full_rank_data(): assert np.linalg.matrix_rank(X) == rank ssd = SSD(info, filt_params_signal, filt_params_noise) + if sys.platform == "darwin": + pytest.skip("Unknown linalg bug (Accelerate?)") ssd.fit(X) diff --git a/mne/decoding/tests/test_time_frequency.py b/mne/decoding/tests/test_time_frequency.py index 24708f4e00c..37e7d7d8dc2 100644 --- a/mne/decoding/tests/test_time_frequency.py +++ b/mne/decoding/tests/test_time_frequency.py @@ -1,5 +1,4 @@ -# Author: Jean-Remi King, -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -8,14 +7,15 @@ import pytest from numpy.testing import assert_array_equal +pytest.importorskip("sklearn") + +from sklearn.base import clone + from mne.decoding.time_frequency import TimeFrequency def test_timefrequency(): """Test TimeFrequency.""" - pytest.importorskip("sklearn") - from sklearn.base import clone - # Init n_freqs = 3 freqs = [20, 21, 22] diff --git a/mne/decoding/tests/test_transformer.py b/mne/decoding/tests/test_transformer.py index 1c2a29bdf8e..8dcc3ad74c7 100644 --- a/mne/decoding/tests/test_transformer.py +++ b/mne/decoding/tests/test_transformer.py @@ -1,6 +1,4 @@ -# Author: Mainak Jas -# Romain Trachel -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -15,6 +13,11 @@ assert_equal, ) +pytest.importorskip("sklearn") + +from sklearn.decomposition import PCA +from sklearn.kernel_ridge import KernelRidge + from mne import Epochs, io, pick_types, read_events from mne.decoding import ( FilterEstimator, @@ -25,7 +28,7 @@ Vectorizer, ) from mne.defaults import DEFAULTS -from mne.utils import check_version, use_log_level +from mne.utils import use_log_level tmin, tmax = -0.2, 0.5 event_id = dict(aud_l=1, vis_l=3) @@ -60,11 +63,6 @@ def test_scaler(info, method): y = epochs.events[:, -1] epochs_data_t = epochs_data.transpose([1, 0, 2]) - if method in ("mean", "median"): - if not check_version("sklearn"): - with pytest.raises((ImportError, RuntimeError), match=" module "): - Scaler(info, method) - return if info: info = epochs.info @@ -219,10 +217,6 @@ def test_vectorizer(): def test_unsupervised_spatial_filter(): """Test unsupervised spatial filter.""" - pytest.importorskip("sklearn") - from sklearn.decomposition import PCA - from sklearn.kernel_ridge import KernelRidge - raw = io.read_raw_fif(raw_fname) events = read_events(event_name) picks = pick_types( diff --git a/mne/decoding/time_delaying_ridge.py b/mne/decoding/time_delaying_ridge.py index 5d6171bc301..b80b36d3922 100644 --- a/mne/decoding/time_delaying_ridge.py +++ b/mne/decoding/time_delaying_ridge.py @@ -1,7 +1,6 @@ """TimeDelayingRidge class.""" -# Authors: Eric Larson -# Ross Maddox -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -288,27 +287,22 @@ def __init__( n_jobs=None, edge_correction=True, ): - if tmin > tmax: - raise ValueError(f"tmin must be <= tmax, got {tmin} and {tmax}") - self.tmin = float(tmin) - self.tmax = float(tmax) - self.sfreq = float(sfreq) - self.alpha = float(alpha) + self.tmin = tmin + self.tmax = tmax + self.sfreq = sfreq + self.alpha = alpha self.reg_type = reg_type self.fit_intercept = fit_intercept self.edge_correction = edge_correction self.n_jobs = n_jobs - def _more_tags(self): - return {"no_validation": True} - @property def _smin(self): - return int(round(self.tmin * self.sfreq)) + return int(round(self.tmin_ * self.sfreq_)) @property def _smax(self): - return int(round(self.tmax * self.sfreq)) + 1 + return int(round(self.tmax_ * self.sfreq_)) + 1 def fit(self, X, y): """Estimate the coefficients of the linear model. @@ -327,6 +321,12 @@ def fit(self, X, y): """ _validate_type(X, "array-like", "X") _validate_type(y, "array-like", "y") + self.tmin_ = float(self.tmin) + self.tmax_ = float(self.tmax) + self.sfreq_ = float(self.sfreq) + self.alpha_ = float(self.alpha) + if self.tmin_ > self.tmax_: + raise ValueError(f"tmin must be <= tmax, got {self.tmin_} and {self.tmax_}") X = np.asarray(X, dtype=float) y = np.asarray(y, dtype=float) if X.ndim == 3: @@ -353,7 +353,7 @@ def fit(self, X, y): self.edge_correction, ) self.coef_ = _fit_corrs( - self.cov_, x_y_, n_ch_x, self.reg_type, self.alpha, n_ch_x + self.cov_, x_y_, n_ch_x, self.reg_type, self.alpha_, n_ch_x ) # This is the sklearn formula from LinearModel (will be 0. for no fit) if self.fit_intercept: diff --git a/mne/decoding/time_frequency.py b/mne/decoding/time_frequency.py index 0555d190ddd..de6ec52155b 100644 --- a/mne/decoding/time_frequency.py +++ b/mne/decoding/time_frequency.py @@ -1,14 +1,12 @@ -# Author: Jean-Remi King -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import numpy as np +from sklearn.base import BaseEstimator, TransformerMixin from ..time_frequency.tfr import _compute_tfr from ..utils import _check_option, fill_doc, verbose -from .base import BaseEstimator -from .mixin import TransformerMixin @fill_doc diff --git a/mne/decoding/transformer.py b/mne/decoding/transformer.py index 703580798ad..e293d108ba8 100644 --- a/mne/decoding/transformer.py +++ b/mne/decoding/transformer.py @@ -1,11 +1,9 @@ -# Authors: Mainak Jas -# Alexandre Gramfort -# Romain Trachel -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import numpy as np +from sklearn.base import BaseEstimator, TransformerMixin from .._fiff.pick import ( _pick_data_channels, @@ -18,8 +16,6 @@ from ..filter import filter_data from ..time_frequency import psd_array_multitaper from ..utils import _check_option, _validate_type, fill_doc, verbose -from .base import BaseEstimator -from .mixin import TransformerMixin class _ConstantScaler: @@ -113,7 +109,7 @@ def __init__(self, info=None, scalings=None, with_mean=True, with_std=True): self.with_std = with_std self.scalings = scalings - if not (scalings is None or isinstance(scalings, (dict, str))): + if not (scalings is None or isinstance(scalings, dict | str)): raise ValueError( f"scalings type should be dict, str, or None, got {type(scalings)}" ) diff --git a/mne/defaults.py b/mne/defaults.py index 0418feb6788..d5aab1a8d38 100644 --- a/mne/defaults.py +++ b/mne/defaults.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis A. Engemann -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -67,8 +64,8 @@ whitened="Z", gsr="S", temperature="C", - eyegaze="AU", - pupil="AU", + eyegaze="rad", + pupil="m", ), units=dict( mag="fT", @@ -95,8 +92,8 @@ whitened="Z", gsr="S", temperature="C", - eyegaze="AU", - pupil="AU", + eyegaze="rad", + pupil="µm", ), # scalings for the units scalings=dict( @@ -125,7 +122,7 @@ gsr=1.0, temperature=1.0, eyegaze=1.0, - pupil=1.0, + pupil=1e6, ), # rough guess for a good plot scalings_plot_raw=dict( @@ -159,8 +156,8 @@ gof=1e2, gsr=1.0, temperature=0.1, - eyegaze=3e-1, - pupil=1e3, + eyegaze=2e-1, + pupil=1e-2, ), scalings_cov_rank=dict( mag=1e12, @@ -186,8 +183,8 @@ hbo=(0, 20), hbr=(0, 20), csd=(-50.0, 50.0), - eyegaze=(0.0, 5000.0), - pupil=(0.0, 5000.0), + eyegaze=(-1, 1), + pupil=(-1.0, 1.0), ), titles=dict( mag="Magnetometers", diff --git a/mne/dipole.py b/mne/dipole.py index 9f31b3f2e1e..133b2e9ed3d 100644 --- a/mne/dipole.py +++ b/mne/dipole.py @@ -1,8 +1,6 @@ """Single-dipole functions and classes.""" -# Authors: Alexandre Gramfort -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/epochs.py b/mne/epochs.py index 55b256fffd2..c25d8a6797b 100644 --- a/mne/epochs.py +++ b/mne/epochs.py @@ -1,12 +1,6 @@ """Tools for working with epoched data.""" -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Daniel Strohmeier -# Denis Engemann -# Mainak Jas -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1822,7 +1816,7 @@ def _data_sel_copy_scale( data_is_self_data = bool(self.preload) logger.debug(f"Data is self data: {data_is_self_data}") # only two types of epoch subselection allowed - assert isinstance(select, (slice, np.ndarray)), type(select) + assert isinstance(select, slice | np.ndarray), type(select) if not isinstance(select, slice): logger.debug(" Copying, fancy indexed epochs") data_is_self_data = False # copy (fancy indexing) @@ -2201,6 +2195,12 @@ def save( .. versionadded:: 0.24 %(verbose)s + Returns + ------- + fnames : List of path-like + List of path-like objects containing the path to each file split. + .. versionadded:: 1.9 + Notes ----- Bad epochs will be dropped before saving the epochs to disk. @@ -2312,6 +2312,7 @@ def save( this_epochs.event_id = self.event_id _save_split(this_epochs, split_fnames, part_idx, n_parts, fmt, overwrite) + return split_fnames @verbose def export(self, fname, fmt="auto", *, overwrite=False, verbose=None): @@ -3170,12 +3171,12 @@ def _diff_input_strings_vs_event_id(input_strings, input_name, event_id): # This follows the approach taken in mne.Epochs # For strings and None, we don't know the start and stop samples in advance as the # time window can vary. - if isinstance(tmin, (type(None), list)): + if isinstance(tmin, type(None) | list): start_sample = None else: start_sample = int(round(tmin * sfreq)) - if isinstance(tmax, (type(None), list)): + if isinstance(tmax, type(None) | list): stop_sample = None else: stop_sample = int(round(tmax * sfreq)) + 1 @@ -3386,7 +3387,7 @@ def _events_from_annotations(raw, events, event_id, annotations, on_missing): # if event_id is the names of events, map to events integers if isinstance(event_id, str): event_id = [event_id] - if isinstance(event_id, (list, tuple, set)): + if isinstance(event_id, list | tuple | set): if not set(event_id).issubset(set(event_id_tmp)): msg = ( "No matching annotations found for event_id(s) " @@ -3858,7 +3859,7 @@ def equalize_epoch_counts(epochs_list, method="mintime", *, random_state=None): -------- >>> equalize_epoch_counts([epochs1, epochs2]) # doctest: +SKIP """ - if not all(isinstance(epoch, (BaseEpochs, EpochsTFR)) for epoch in epochs_list): + if not all(isinstance(epoch, BaseEpochs | EpochsTFR) for epoch in epochs_list): raise ValueError("All inputs must be Epochs instances") # make sure bad epochs are dropped for epoch in epochs_list: @@ -4493,7 +4494,7 @@ def _concatenate_epochs( epochs_list, *, with_data=True, add_offset=True, on_mismatch="raise" ): """Auxiliary function for concatenating epochs.""" - if not isinstance(epochs_list, (list, tuple)): + if not isinstance(epochs_list, list | tuple): raise TypeError(f"epochs_list must be a list or tuple, got {type(epochs_list)}") # to make warning messages only occur once during concatenation diff --git a/mne/event.py b/mne/event.py index b2b3a03efce..91b14c53e80 100644 --- a/mne/event.py +++ b/mne/event.py @@ -1,10 +1,6 @@ """IO with fif files containing events.""" -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Teon Brooks -# Clement Moutard -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1633,7 +1629,7 @@ def match_event_names(event_names, keys, *, on_missing="raise"): event_names = list(event_names) # ensure we have a list of `keys` - if isinstance(keys, (Sequence, np.ndarray)) and not isinstance(keys, str): + if isinstance(keys, Sequence | np.ndarray) and not isinstance(keys, str): keys = list(keys) else: keys = [keys] diff --git a/mne/evoked.py b/mne/evoked.py index 32fbe93f7e2..a14436efacf 100644 --- a/mne/evoked.py +++ b/mne/evoked.py @@ -1,10 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Denis Engemann -# Andrew Dykstra -# Mads Jensen -# Jona Sassenhagen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1996,7 +1990,7 @@ def _write_evokeds(fname, evoked, check=True, *, on_mismatch="raise", overwrite= fname, "evoked", ("-ave.fif", "-ave.fif.gz", "_ave.fif", "_ave.fif.gz") ) - if not isinstance(evoked, (list, tuple)): + if not isinstance(evoked, list | tuple): evoked = [evoked] warned = False diff --git a/mne/export/__init__.py b/mne/export/__init__.py index b4f10c1606f..7a07df656d6 100644 --- a/mne/export/__init__.py +++ b/mne/export/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Functions for exporting data to non-FIF formats.""" import lazy_loader as lazy diff --git a/mne/export/_brainvision.py b/mne/export/_brainvision.py index d705d8cef9d..ba64ba010ce 100644 --- a/mne/export/_brainvision.py +++ b/mne/export/_brainvision.py @@ -1,5 +1,4 @@ -# Authors: MNE Developers -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/export/_edf.py b/mne/export/_edf.py index 03b696d1b4c..424d5250356 100644 --- a/mne/export/_edf.py +++ b/mne/export/_edf.py @@ -1,10 +1,9 @@ -# Authors: MNE Developers -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import datetime as dt -from typing import Callable +from collections.abc import Callable import numpy as np diff --git a/mne/export/_eeglab.py b/mne/export/_eeglab.py index f8095cfc4f0..607102901df 100644 --- a/mne/export/_eeglab.py +++ b/mne/export/_eeglab.py @@ -1,5 +1,4 @@ -# Authors: MNE Developers -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/export/_egimff.py b/mne/export/_egimff.py index 427efe6b059..3792ea4a6a5 100644 --- a/mne/export/_egimff.py +++ b/mne/export/_egimff.py @@ -1,5 +1,4 @@ -# Authors: MNE Developers -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/export/_export.py b/mne/export/_export.py index 684de220c7f..490bf986895 100644 --- a/mne/export/_export.py +++ b/mne/export/_export.py @@ -1,5 +1,4 @@ -# Authors: MNE Developers -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/export/tests/test_export.py b/mne/export/tests/test_export.py index 4208c04af1c..400dbc4fe7e 100644 --- a/mne/export/tests/test_export.py +++ b/mne/export/tests/test_export.py @@ -1,6 +1,6 @@ """Test exporting functions.""" -# Authors: MNE Developers -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/filter.py b/mne/filter.py index 88957fae043..a3655394939 100644 --- a/mne/filter.py +++ b/mne/filter.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """IIR and FIR filtering and resampling functions.""" from collections import Counter @@ -1775,7 +1777,7 @@ def _check_filterable(x, kind="filtered", alternative="filter"): from .evoked import Evoked from .io import BaseRaw - if isinstance(x, (BaseRaw, BaseEpochs, Evoked)): + if isinstance(x, BaseRaw | BaseEpochs | Evoked): try: name = x.__class__.__name__ except Exception: @@ -1903,7 +1905,7 @@ def _prep_polyphase(ratio, x_len, final_len, window): up = up // g_ down = down // g_ # Figure out our signal neighborhood and design window (adapted from SciPy) - if not isinstance(window, (list, np.ndarray)): + if not isinstance(window, list | np.ndarray): # Design a linear-phase low-pass FIR filter max_rate = max(up, down) f_c = 1.0 / max_rate # cutoff of FIR filter (rel. to Nyquist) @@ -2634,7 +2636,7 @@ def resample( # Should be guaranteed by our inheritance, and the fact that # mne.io.BaseRaw and _BaseSourceEstimate overrides this method - assert isinstance(self, (BaseEpochs, Evoked)) + assert isinstance(self, BaseEpochs | Evoked) sfreq = float(sfreq) o_sfreq = self.info["sfreq"] diff --git a/mne/fixes.py b/mne/fixes.py index 84d660c87b0..e9d62fb42e6 100644 --- a/mne/fixes.py +++ b/mne/fixes.py @@ -6,10 +6,8 @@ # originally copied from scikit-learn """ -# Authors: Emmanuelle Gouillart -# Gael Varoquaux -# Fabian Pedregosa -# Lars Buitinck + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -21,9 +19,7 @@ import operator as operator_module import os import warnings -from io import StringIO from math import log -from pprint import pprint import numpy as np @@ -136,231 +132,6 @@ def _get_img_fdata(img): return data.astype(dtype) -############################################################################## -# adapted from scikit-learn - - -_DEFAULT_TAGS = { - "array_api_support": False, - "non_deterministic": False, - "requires_positive_X": False, - "requires_positive_y": False, - "X_types": ["2darray"], - "poor_score": False, - "no_validation": False, - "multioutput": False, - "allow_nan": False, - "stateless": False, - "multilabel": False, - "_skip_test": False, - "_xfail_checks": False, - "multioutput_only": False, - "binary_only": False, - "requires_fit": True, - "preserves_dtype": [np.float64], - "requires_y": False, - "pairwise": False, -} - - -class BaseEstimator: - """Base class for all estimators in scikit-learn. - - Notes - ----- - All estimators should specify all the parameters that can be set - at the class level in their ``__init__`` as explicit keyword - arguments (no ``*args`` or ``**kwargs``). - """ - - @classmethod - def _get_param_names(cls): - """Get parameter names for the estimator.""" - # fetch the constructor or the original constructor before - # deprecation wrapping if any - init = getattr(cls.__init__, "deprecated_original", cls.__init__) - if init is object.__init__: - # No explicit constructor to introspect - return [] - - # introspect the constructor arguments to find the model parameters - # to represent - init_signature = inspect.signature(init) - # Consider the constructor parameters excluding 'self' - parameters = [ - p - for p in init_signature.parameters.values() - if p.name != "self" and p.kind != p.VAR_KEYWORD - ] - for p in parameters: - if p.kind == p.VAR_POSITIONAL: - raise RuntimeError( - "scikit-learn estimators should always " - "specify their parameters in the signature" - " of their __init__ (no varargs)." - f" {cls} with constructor {init_signature} doesn't " - " follow this convention." - ) - # Extract and sort argument names excluding 'self' - return sorted([p.name for p in parameters]) - - def get_params(self, deep=True): - """Get parameters for this estimator. - - Parameters - ---------- - deep : bool, optional - If True, will return the parameters for this estimator and - contained subobjects that are estimators. - - Returns - ------- - params : dict - Parameter names mapped to their values. - """ - out = dict() - for key in self._get_param_names(): - # We need deprecation warnings to always be on in order to - # catch deprecated param values. - # This is set in utils/__init__.py but it gets overwritten - # when running under python3 somehow. - warnings.simplefilter("always", DeprecationWarning) - try: - with warnings.catch_warnings(record=True) as w: - value = getattr(self, key, None) - if len(w) and w[0].category is DeprecationWarning: - # if the parameter is deprecated, don't show it - continue - finally: - warnings.filters.pop(0) - - # XXX: should we rather test if instance of estimator? - if deep and hasattr(value, "get_params"): - deep_items = value.get_params().items() - out.update((key + "__" + k, val) for k, val in deep_items) - out[key] = value - return out - - def set_params(self, **params): - """Set the parameters of this estimator. - - The method works on simple estimators as well as on nested objects - (such as pipelines). The latter have parameters of the form - ``__`` so that it's possible to update each - component of a nested object. - - Parameters - ---------- - **params : dict - Parameters. - - Returns - ------- - inst : instance - The object. - """ - if not params: - # Simple optimisation to gain speed (inspect is slow) - return self - valid_params = self.get_params(deep=True) - for key, value in params.items(): - split = key.split("__", 1) - if len(split) > 1: - # nested objects case - name, sub_name = split - if name not in valid_params: - raise ValueError( - f"Invalid parameter {name} for estimator {self}. " - "Check the list of available parameters " - "with `estimator.get_params().keys()`." - ) - sub_object = valid_params[name] - sub_object.set_params(**{sub_name: value}) - else: - # simple objects case - if key not in valid_params: - raise ValueError( - f"Invalid parameter {key} for estimator " - f"{self.__class__.__name__}. " - "Check the list of available parameters " - "with `estimator.get_params().keys()`." - ) - setattr(self, key, value) - return self - - def __repr__(self): # noqa: D105 - params = StringIO() - pprint(self.get_params(deep=False), params) - params.seek(0) - class_name = self.__class__.__name__ - return f"{class_name}({params.read().strip()})" - - # __getstate__ and __setstate__ are omitted because they only contain - # conditionals that are not satisfied by our objects (e.g., - # ``if type(self).__module__.startswith('sklearn.')``. - - def _more_tags(self): - return _DEFAULT_TAGS - - def _get_tags(self): - collected_tags = {} - for base_class in reversed(inspect.getmro(self.__class__)): - if hasattr(base_class, "_more_tags"): - # need the if because mixins might not have _more_tags - # but might do redundant work in estimators - # (i.e. calling more tags on BaseEstimator multiple times) - more_tags = base_class._more_tags(self) - collected_tags.update(more_tags) - return collected_tags - - -# newer sklearn deprecates importing from sklearn.metrics.scoring, -# but older sklearn does not expose check_scoring in sklearn.metrics. -def _get_check_scoring(): - try: - from sklearn.metrics import check_scoring # noqa - except ImportError: - from sklearn.metrics.scorer import check_scoring # noqa - return check_scoring - - -def _check_fit_params(X, fit_params, indices=None): - """Check and validate the parameters passed during `fit`. - - Parameters - ---------- - X : array-like of shape (n_samples, n_features) - Data array. - - fit_params : dict - Dictionary containing the parameters passed at fit. - - indices : array-like of shape (n_samples,), default=None - Indices to be selected if the parameter has the same size as - `X`. - - Returns - ------- - fit_params_validated : dict - Validated parameters. We ensure that the values support - indexing. - """ - try: - from sklearn.utils.validation import ( - _check_fit_params as _sklearn_check_fit_params, - ) - - return _sklearn_check_fit_params(X, fit_params, indices) - except ImportError: - from sklearn.model_selection import _validation - - fit_params_validated = { - k: _validation._index_param_value(X, v, indices) - for k, v in fit_params.items() - } - return fit_params_validated - - ############################################################################### # Copied from sklearn to simplify code paths @@ -403,7 +174,54 @@ def empirical_covariance(X, assume_centered=False): return covariance -class EmpiricalCovariance(BaseEstimator): +class _EstimatorMixin: + def _param_names(self): + return inspect.getfullargspec(self.__init__).args[1:] + + def get_params(self, deep=True): + """Get parameters for this estimator. + + Parameters + ---------- + deep : bool, default=True + If True, will return the parameters for this estimator and + contained subobjects that are estimators. + + Returns + ------- + params : dict + Parameter names mapped to their values. + """ + out = dict() + for key in self._param_names(): + out[key] = getattr(self, key) + return out + + def set_params(self, **params): + """Set the parameters of this estimator. + + The method works on simple estimators as well as on nested objects + (such as pipelines). The latter have parameters of the form + ``__`` so that it's possible to update each + component of a nested object. + + Parameters + ---------- + **params : dict + Estimator parameters. + + Returns + ------- + self : object + Estimator instance. + """ + param_names = self._param_names() + for key in params: + if key in param_names: + setattr(self, key, params[key]) + + +class EmpiricalCovariance(_EstimatorMixin): """Maximum likelihood covariance estimator. Read more in the :ref:`User Guide `. @@ -778,7 +596,7 @@ def _crop_colorbar(cbar, cbar_vmin, cbar_vmax): try: import numba - if _compare_version(numba.__version__, "<", "0.53.1"): + if _compare_version(numba.__version__, "<", "0.56.4"): raise ImportError prange = numba.prange diff --git a/mne/forward/__init__.py b/mne/forward/__init__.py index 57dfb1ca09c..3dcafb625de 100644 --- a/mne/forward/__init__.py +++ b/mne/forward/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Forward modeling code.""" import lazy_loader as lazy # for testing purposes diff --git a/mne/forward/_compute_forward.py b/mne/forward/_compute_forward.py index f5e24fd889b..b048d9657ea 100644 --- a/mne/forward/_compute_forward.py +++ b/mne/forward/_compute_forward.py @@ -1,9 +1,4 @@ -# Authors: Matti Hämäläinen -# Alexandre Gramfort -# Martin Luessi -# Eric Larson -# Mark Wronkiewicz -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/forward/_field_interpolation.py b/mne/forward/_field_interpolation.py index 1b768b9a0cb..c362600c253 100644 --- a/mne/forward/_field_interpolation.py +++ b/mne/forward/_field_interpolation.py @@ -1,6 +1,4 @@ -# Authors: Matti Hämäläinen -# Alexandre Gramfort -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/forward/_lead_dots.py b/mne/forward/_lead_dots.py index 504f352bd7a..5db396224b5 100644 --- a/mne/forward/_lead_dots.py +++ b/mne/forward/_lead_dots.py @@ -1,7 +1,4 @@ -# Authors: Matti Hämäläinen -# Eric Larson -# Mainak Jas -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/forward/_make_forward.py b/mne/forward/_make_forward.py index 73fed0bf259..64ad2487d53 100644 --- a/mne/forward/_make_forward.py +++ b/mne/forward/_make_forward.py @@ -1,8 +1,4 @@ -# Authors: Matti Hämäläinen -# Alexandre Gramfort -# Martin Luessi -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/forward/forward.py b/mne/forward/forward.py index 27bc3ccd236..e1f6e5961e2 100644 --- a/mne/forward/forward.py +++ b/mne/forward/forward.py @@ -1,7 +1,4 @@ -# Authors: Matti Hämäläinen -# Alexandre Gramfort -# Martin Luessi -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -56,6 +53,7 @@ from ..label import Label from ..source_estimate import _BaseSourceEstimate, _BaseVectorSourceEstimate from ..source_space._source_space import ( + SourceSpaces, _get_src_nn, _read_source_spaces_from_tree, _set_source_space_vertices, @@ -916,7 +914,10 @@ def _write_forward_hdf5(fname, fwd): def _read_forward_hdf5(fname): read_hdf5, _ = _import_h5io_funcs() - return Forward(read_hdf5(fname)["fwd"]) + fwd = Forward(read_hdf5(fname)["fwd"]) + fwd["info"] = Info(fwd["info"]) + fwd["src"] = SourceSpaces(fwd["src"]) + return fwd def _write_forward_solution(fid, fwd): @@ -1970,7 +1971,7 @@ def _do_forward_solution( # check for meas to exist as string, or try to make evoked _validate_type(meas, ("path-like", BaseRaw, BaseEpochs, Evoked), "meas") - if isinstance(meas, (BaseRaw, BaseEpochs, Evoked)): + if isinstance(meas, BaseRaw | BaseEpochs | Evoked): meas_file = op.join(temp_dir, "info.fif") write_info(meas_file, meas.info) meas = meas_file @@ -1996,7 +1997,7 @@ def _do_forward_solution( "trans was a dict, but could not be " "written to disk as a transform file" ) - elif isinstance(trans, (str, Path, PathLike)): + elif isinstance(trans, str | Path | PathLike): _check_fname(trans, "read", must_exist=True, name="trans") trans = Path(trans) else: @@ -2012,7 +2013,7 @@ def _do_forward_solution( "mri was a dict, but could not be " "written to disk as a transform file" ) - elif isinstance(mri, (str, Path, PathLike)): + elif isinstance(mri, str | Path | PathLike): _check_fname(mri, "read", must_exist=True, name="mri") mri = Path(mri) else: diff --git a/mne/forward/tests/__init__.py b/mne/forward/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/forward/tests/__init__.py +++ b/mne/forward/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/forward/tests/test_field_interpolation.py b/mne/forward/tests/test_field_interpolation.py index 4f09a90df73..98f84dd0b87 100644 --- a/mne/forward/tests/test_field_interpolation.py +++ b/mne/forward/tests/test_field_interpolation.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from os import path as op from pathlib import Path diff --git a/mne/forward/tests/test_forward.py b/mne/forward/tests/test_forward.py index 7442c68959c..3918ee37f18 100644 --- a/mne/forward/tests/test_forward.py +++ b/mne/forward/tests/test_forward.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import gc from pathlib import Path diff --git a/mne/forward/tests/test_make_forward.py b/mne/forward/tests/test_make_forward.py index 4e52b9a50b0..37ec6e041b5 100644 --- a/mne/forward/tests/test_make_forward.py +++ b/mne/forward/tests/test_make_forward.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from itertools import product from pathlib import Path @@ -294,7 +296,10 @@ def test_make_forward_solution_bti(fname_src_small): "other", [ pytest.param("MNE-C", marks=requires_mne_mark()), - pytest.param("openmeeg", marks=requires_openmeeg_mark()), + pytest.param( + "openmeeg", + marks=[requires_openmeeg_mark(), pytest.mark.slowtest], + ), ], ) def test_make_forward_solution_ctf(tmp_path, fname_src_small, other): @@ -401,6 +406,7 @@ def test_make_forward_solution_ctf(tmp_path, fname_src_small, other): repr(fwd_py) +@pytest.mark.slowtest @testing.requires_testing_data def test_make_forward_solution_basic(): """Test making M-EEG forward solution from python.""" diff --git a/mne/gui/__init__.py b/mne/gui/__init__.py index 0474ce59e82..c06c8dc9939 100644 --- a/mne/gui/__init__.py +++ b/mne/gui/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Convenience functions for opening GUIs.""" import lazy_loader as lazy diff --git a/mne/gui/_coreg.py b/mne/gui/_coreg.py index e16b8bfa4ba..4aaec5cbc94 100644 --- a/mne/gui/_coreg.py +++ b/mne/gui/_coreg.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import inspect import os import os.path as op @@ -35,6 +37,7 @@ from ..io._read_raw import _get_supported, read_raw from ..surface import _CheckInside, _DistanceQuery from ..transforms import ( + Transform, _ensure_trans, _get_trans, _get_transforms_to_coord_frame, @@ -118,8 +121,8 @@ class CoregistrationUI(HasTraits): with a different color. Defaults to True. sensor_opacity : float The opacity of the sensors between 0 and 1. Defaults to 1.0. - trans : path-like - The path to the Head<->MRI transform FIF file ("-trans.fif"). + trans : path-like | Transform + The Head<->MRI transform or the path to its FIF file ("-trans.fif"). size : tuple The dimensions (width, height) of the rendering view. The default is (800, 600). @@ -1165,7 +1168,7 @@ def _forward_widget_command( if isinstance(names, str): names = [names] - if not isinstance(value, (str, float, int, dict, type(None))): + if not isinstance(value, str | float | int | dict | type(None)): value = list(value) assert len(names) == len(value) @@ -1541,10 +1544,10 @@ def _save_trans(self, fname): self._display_message(f"{fname} transform file is saved.") self._trans_modified = False - def _load_trans(self, fname): - mri_head_t = _ensure_trans(read_trans(fname, return_all=True), "mri", "head")[ - "trans" - ] + def _load_trans(self, trans): + if not isinstance(trans, Transform): + trans = read_trans(trans, return_all=True) + mri_head_t = _ensure_trans(trans, "mri", "head")["trans"] rot_x, rot_y, rot_z = rotation_angles(mri_head_t) x, y, z = mri_head_t[:3, 3] self.coreg._update_params( @@ -1554,7 +1557,7 @@ def _load_trans(self, fname): self._update_parameters() self._update_distance_estimation() self._update_plot() - self._display_message(f"{fname} transform file is loaded.") + self._display_message(f"{trans} transform file is loaded.") def _update_fiducials_label(self): if self._fiducials_file is None: diff --git a/mne/gui/_gui.py b/mne/gui/_gui.py index e522986a60c..f4db67cf2f6 100644 --- a/mne/gui/_gui.py +++ b/mne/gui/_gui.py @@ -1,5 +1,4 @@ -# Authors: Christian Brodbeck -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -60,8 +59,8 @@ def coregistration( Use a high resolution head surface. Default is None, which uses ``MNE_COREG_HEAD_HIGH_RES`` config value (which defaults to True). - trans : path-like | None - The transform file to use. + trans : path-like | Transform | None + The Head<->MRI transform or the path to its FIF file ("-trans.fif"). orient_to_surface : bool | None If True (default), orient EEG electrode and head shape points to the head surface. diff --git a/mne/gui/tests/__init__.py b/mne/gui/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/gui/tests/__init__.py +++ b/mne/gui/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/gui/tests/test_coreg.py b/mne/gui/tests/test_coreg.py index 0bafc98d83a..409b5c6665c 100644 --- a/mne/gui/tests/test_coreg.py +++ b/mne/gui/tests/test_coreg.py @@ -1,5 +1,4 @@ -# Author: Christian Brodbeck -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/gui/tests/test_gui_api.py b/mne/gui/tests/test_gui_api.py index ae04124dd14..5be82d27af6 100644 --- a/mne/gui/tests/test_gui_api.py +++ b/mne/gui/tests/test_gui_api.py @@ -1,5 +1,4 @@ -# Authors: Guillaume Favelier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/html_templates/__init__.py b/mne/html_templates/__init__.py index 845e5fe07f9..b8234d27037 100644 --- a/mne/html_templates/__init__.py +++ b/mne/html_templates/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Jinja2 HTML templates.""" import lazy_loader as lazy diff --git a/mne/html_templates/_templates.py b/mne/html_templates/_templates.py index b2c2dc10714..9427f2d6a25 100644 --- a/mne/html_templates/_templates.py +++ b/mne/html_templates/_templates.py @@ -1,3 +1,4 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/inverse_sparse/__init__.py b/mne/inverse_sparse/__init__.py index 1065c9d6bcc..615c3062bdb 100644 --- a/mne/inverse_sparse/__init__.py +++ b/mne/inverse_sparse/__init__.py @@ -1,8 +1,9 @@ """Non-Linear sparse inverse solvers.""" -# Author: Alexandre Gramfort -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import lazy_loader as lazy (__getattr__, __dir__, __all__) = lazy.attach_stub(__name__, __file__) diff --git a/mne/inverse_sparse/_gamma_map.py b/mne/inverse_sparse/_gamma_map.py index 6389917c29e..35fd158f3e0 100644 --- a/mne/inverse_sparse/_gamma_map.py +++ b/mne/inverse_sparse/_gamma_map.py @@ -1,5 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/inverse_sparse/mxne_debiasing.py b/mne/inverse_sparse/mxne_debiasing.py index 31c87ba0690..860c67c5f6c 100644 --- a/mne/inverse_sparse/mxne_debiasing.py +++ b/mne/inverse_sparse/mxne_debiasing.py @@ -1,6 +1,4 @@ -# Authors: Daniel Strohmeier -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/inverse_sparse/mxne_inverse.py b/mne/inverse_sparse/mxne_inverse.py index 32f085d48cd..c3ccddbf7cd 100644 --- a/mne/inverse_sparse/mxne_inverse.py +++ b/mne/inverse_sparse/mxne_inverse.py @@ -1,6 +1,4 @@ -# Author: Alexandre Gramfort -# Daniel Strohmeier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -472,7 +470,7 @@ def mixed_norm( f"dgap_freq must be a positive integer. Got dgap_freq = {dgap_freq}" ) if not ( - isinstance(sure_alpha_grid, (np.ndarray, list)) or sure_alpha_grid == "auto" + isinstance(sure_alpha_grid, np.ndarray | list) or sure_alpha_grid == "auto" ): raise ValueError( 'If not equal to "auto" sure_alpha_grid must be an ' @@ -651,7 +649,7 @@ def mixed_norm( def _window_evoked(evoked, size): """Window evoked (size in seconds).""" - if isinstance(size, (float, int)): + if isinstance(size, float | int): lsize = rsize = float(size) else: lsize, rsize = size diff --git a/mne/inverse_sparse/mxne_optim.py b/mne/inverse_sparse/mxne_optim.py index 2a7388f8686..c9f78c8c3b6 100644 --- a/mne/inverse_sparse/mxne_optim.py +++ b/mne/inverse_sparse/mxne_optim.py @@ -1,6 +1,4 @@ -# Author: Alexandre Gramfort -# Daniel Strohmeier -# Mathurin Massias +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/inverse_sparse/tests/__init__.py b/mne/inverse_sparse/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/inverse_sparse/tests/__init__.py +++ b/mne/inverse_sparse/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/inverse_sparse/tests/test_gamma_map.py b/mne/inverse_sparse/tests/test_gamma_map.py index d8c1c84f974..db4ac5c9260 100644 --- a/mne/inverse_sparse/tests/test_gamma_map.py +++ b/mne/inverse_sparse/tests/test_gamma_map.py @@ -1,5 +1,4 @@ -# Author: Martin Luessi -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/inverse_sparse/tests/test_mxne_debiasing.py b/mne/inverse_sparse/tests/test_mxne_debiasing.py index 1143e3752ac..9c32f136eaf 100644 --- a/mne/inverse_sparse/tests/test_mxne_debiasing.py +++ b/mne/inverse_sparse/tests/test_mxne_debiasing.py @@ -1,6 +1,4 @@ -# Authors: Daniel Strohmeier -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/inverse_sparse/tests/test_mxne_inverse.py b/mne/inverse_sparse/tests/test_mxne_inverse.py index 17a088f5c1e..0939298a3cd 100644 --- a/mne/inverse_sparse/tests/test_mxne_inverse.py +++ b/mne/inverse_sparse/tests/test_mxne_inverse.py @@ -1,6 +1,4 @@ -# Author: Alexandre Gramfort -# Daniel Strohmeier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/inverse_sparse/tests/test_mxne_optim.py b/mne/inverse_sparse/tests/test_mxne_optim.py index 79d578532ea..464fe274def 100644 --- a/mne/inverse_sparse/tests/test_mxne_optim.py +++ b/mne/inverse_sparse/tests/test_mxne_optim.py @@ -1,6 +1,4 @@ -# Author: Alexandre Gramfort -# Daniel Strohmeier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/__init__.py b/mne/io/__init__.py index b2ba75e44a6..40f385391cd 100644 --- a/mne/io/__init__.py +++ b/mne/io/__init__.py @@ -1,9 +1,9 @@ """IO module for reading raw data.""" -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import lazy_loader as lazy (__getattr__, __dir__, __all__) = lazy.attach_stub(__name__, __file__) diff --git a/mne/io/__init__.pyi b/mne/io/__init__.pyi index 3843ca3a384..a9c11415f15 100644 --- a/mne/io/__init__.pyi +++ b/mne/io/__init__.pyi @@ -17,6 +17,7 @@ __all__ = [ "read_fiducials", "read_info", "read_raw", + "read_raw_ant", "read_raw_artemis123", "read_raw_bdf", "read_raw_boxy", @@ -59,6 +60,7 @@ from ._fiff_wrap import ( write_info, ) from ._read_raw import read_raw +from .ant import read_raw_ant from .array import RawArray from .artemis123 import read_raw_artemis123 from .base import BaseRaw, concatenate_raws, match_channel_orders diff --git a/mne/io/_fiff_wrap.py b/mne/io/_fiff_wrap.py index 526868d7f4b..e4566d61a40 100644 --- a/mne/io/_fiff_wrap.py +++ b/mne/io/_fiff_wrap.py @@ -1,4 +1,5 @@ # ruff: noqa: F401 +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/_read_raw.py b/mne/io/_read_raw.py index 6df23ee02f1..28c86c00ee6 100644 --- a/mne/io/_read_raw.py +++ b/mne/io/_read_raw.py @@ -1,7 +1,6 @@ """Generic wrapper function read_raw for specific read_raw_xxx readers.""" -# Authors: Clemens Brunner -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -25,6 +24,7 @@ def _read_unsupported(fname, **kwargs): # supported read file formats def _get_supported(): from . import ( + read_raw_ant, read_raw_artemis123, read_raw_bdf, read_raw_boxy, @@ -36,6 +36,7 @@ def _get_supported(): read_raw_eeglab, read_raw_egi, read_raw_eximia, + read_raw_eyelink, read_raw_fieldtrip, read_raw_fif, read_raw_fil, @@ -45,6 +46,8 @@ def _get_supported(): read_raw_nicolet, read_raw_nihon, read_raw_nirx, + read_raw_nsx, + read_raw_persyst, read_raw_snirf, ) @@ -58,7 +61,7 @@ def _get_supported(): ".fif": dict(FIF=read_raw_fif), ".fif.gz": dict(FIF=read_raw_fif), ".set": dict(EEGLAB=read_raw_eeglab), - ".cnt": dict(CNT=read_raw_cnt), + ".cnt": dict(CNT=read_raw_cnt, ANT=read_raw_ant), ".mff": dict(EGI=read_raw_egi), ".nxe": dict(eximia=read_raw_eximia), ".hdr": dict(NIRx=read_raw_nirx), @@ -83,6 +86,10 @@ def _get_supported(): ".cef": dict(CURRY=read_raw_curry), # NEDF ".nedf": dict(NEDF=read_raw_nedf), + # EyeLink + ".asc": dict(EyeLink=read_raw_eyelink), + ".ns3": dict(NSx=read_raw_nsx), + ".lay": dict(Persyst=read_raw_persyst), } @@ -119,15 +126,31 @@ def read_raw(fname, *, preload=False, verbose=None, **kwargs) -> BaseRaw: The following readers are currently supported: - `~mne.io.read_raw_artemis123`, `~mne.io.read_raw_bdf`, - `~mne.io.read_raw_boxy`, `~mne.io.read_raw_brainvision`, - `~mne.io.read_raw_cnt`, `~mne.io.read_raw_ctf`, `~mne.io.read_raw_edf`, - `~mne.io.read_raw_eeglab`, `~mne.io.read_raw_egi`, - `~mne.io.read_raw_eximia`, `~mne.io.read_raw_fieldtrip`, - `~mne.io.read_raw_fif`, `~mne.io.read_raw_gdf`, `~mne.io.read_raw_kit`, - `~mne.io.read_raw_fil`, - `~mne.io.read_raw_nicolet`, `~mne.io.read_raw_nirx`, - `~mne.io.read_raw_curry`, and `~mne.io.read_raw_nedf`. + * `~mne.io.read_raw_ant` + * `~mne.io.read_raw_artemis123` + * `~mne.io.read_raw_bdf` + * `~mne.io.read_raw_boxy` + * `~mne.io.read_raw_brainvision` + * `~mne.io.read_raw_cnt` + * `~mne.io.read_raw_ctf` + * `~mne.io.read_raw_curry` + * `~mne.io.read_raw_edf` + * `~mne.io.read_raw_eeglab` + * `~mne.io.read_raw_egi` + * `~mne.io.read_raw_eximia` + * `~mne.io.read_raw_eyelink` + * `~mne.io.read_raw_fieldtrip` + * `~mne.io.read_raw_fif` + * `~mne.io.read_raw_fil` + * `~mne.io.read_raw_gdf` + * `~mne.io.read_raw_kit` + * `~mne.io.read_raw_nedf` + * `~mne.io.read_raw_nicolet` + * `~mne.io.read_raw_nihon` + * `~mne.io.read_raw_nirx` + * `~mne.io.read_raw_nsx` + * `~mne.io.read_raw_persyst` + * `~mne.io.read_raw_snirf` Parameters ---------- diff --git a/mne/io/ant/__init__.py b/mne/io/ant/__init__.py new file mode 100644 index 00000000000..86ae7b38e0d --- /dev/null +++ b/mne/io/ant/__init__.py @@ -0,0 +1,5 @@ +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + +from .ant import read_raw_ant diff --git a/mne/io/ant/ant.py b/mne/io/ant/ant.py new file mode 100644 index 00000000000..cc8dbe05dfe --- /dev/null +++ b/mne/io/ant/ant.py @@ -0,0 +1,344 @@ +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + +from __future__ import annotations + +import importlib +import re +from collections import defaultdict +from typing import TYPE_CHECKING + +import numpy as np + +from ..._fiff.constants import FIFF +from ..._fiff.meas_info import create_info +from ...annotations import Annotations +from ...utils import ( + _check_fname, + _validate_type, + check_version, + copy_doc, + fill_doc, + logger, + verbose, + warn, +) +from ..base import BaseRaw + +if TYPE_CHECKING: + from pathlib import Path + + from numpy.typing import NDArray + +units = {"uv": 1e-6} + + +@fill_doc +class RawANT(BaseRaw): + r"""Reader for Raw ANT files in .cnt format. + + Parameters + ---------- + fname : file-like + Path to the ANT raw file to load. The file should have the extension ``.cnt``. + eog : str | None + Regex pattern to find EOG channel labels. If None, no EOG channels are + automatically detected. + misc : str | None + Regex pattern to find miscellaneous channels. If None, no miscellaneous channels + are automatically detected. The default pattern ``"BIP\d+"`` will mark all + bipolar channels as ``misc``. + + .. note:: + + A bipolar channel might actually contain ECG, EOG or other signal types + which might have a dedicated channel type in MNE-Python. In this case, use + :meth:`mne.io.Raw.set_channel_types` to change the channel type of the + channel. + bipolars : list of str | tuple of str | None + The list of channels to treat as bipolar EEG channels. Each element should be + a string of the form ``'anode-cathode'`` or in ANT terminology as ``'label- + reference'``. If None, all channels are interpreted as ``'eeg'`` channels + referenced to the same reference electrode. Bipolar channels are treated + as EEG channels with a special coil type in MNE-Python, see also + :func:`mne.set_bipolar_reference` + + .. warning:: + + Do not provide auxiliary channels in this argument, provide them in the + ``eog`` and ``misc`` arguments. + impedance_annotation : str + The string to use for impedance annotations. Defaults to ``"impedance"``, + however, the impedance measurement might mark the end of a segment and the + beginning of a new segment, in which case a discontinuity similar to what + :func:`mne.concatenate_raws` produces is present. In this case, it's better to + include a ``BAD_xxx`` annotation to mark the discontinuity. + + .. note:: + + Note that the impedance annotation will likely have a duration of ``0``. + If the measurement marks a discontinuity, the duration should be modified to + cover the discontinuity in its entirety. + %(preload)s + %(verbose)s + """ + + _extra_attributes = ("impedances",) + + @verbose + def __init__( + self, + fname: str | Path, + eog: str | None, + misc: str | None, + bipolars: list[str] | tuple[str, ...] | None, + impedance_annotation: str, + *, + preload: bool | NDArray, + verbose=None, + ) -> None: + logger.info("Reading ANT file %s", fname) + if importlib.util.find_spec("antio") is None: + raise ImportError( + "Missing optional dependency 'antio'. Use pip or conda to install " + "'antio'." + ) + check_version("antio", "0.3.0") + + from antio import read_cnt + from antio.parser import ( + read_device_info, + read_info, + read_meas_date, + read_subject_info, + read_triggers, + ) + + fname = _check_fname(fname, overwrite="read", must_exist=True, name="fname") + _validate_type(eog, (str, None), "eog") + _validate_type(misc, (str, None), "misc") + _validate_type(bipolars, (list, tuple, None), "bipolar") + _validate_type(impedance_annotation, (str,), "impedance_annotation") + if len(impedance_annotation) == 0: + raise ValueError("The impedance annotation cannot be an empty string.") + cnt = read_cnt(fname) + # parse channels, sampling frequency, and create info + ch_info = read_info(cnt) # load in 2 lines for compat with antio 0.2 and 0.3 + ch_names, ch_units, ch_refs = ch_info[0], ch_info[1], ch_info[2] + ch_types = _parse_ch_types(ch_names, eog, misc, ch_refs) + if bipolars is not None: # handle bipolar channels + bipolars_idx = _handle_bipolar_channels(ch_names, ch_refs, bipolars) + for idx, ch in zip(bipolars_idx, bipolars): + if ch_types[idx] != "eeg": + warn( + f"Channel {ch} was not parsed as an EEG channel, changing to " + "EEG channel type since bipolar EEG was requested." + ) + ch_names[idx] = ch + ch_types[idx] = "eeg" + info = create_info( + ch_names, sfreq=cnt.get_sample_frequency(), ch_types=ch_types + ) + info.set_meas_date(read_meas_date(cnt)) + make, model, serial, site = read_device_info(cnt) + info["device_info"] = dict(type=make, model=model, serial=serial, site=site) + his_id, name, sex, birthday = read_subject_info(cnt) + info["subject_info"] = dict( + his_id=his_id, first_name=name, sex=sex, birthday=birthday + ) + if bipolars is not None: + with info._unlock(): + for idx in bipolars_idx: + info["chs"][idx]["coil_type"] = FIFF.FIFFV_COIL_EEG_BIPOLAR + first_samps = np.array((0,)) + last_samps = (cnt.get_sample_count() - 1,) + raw_extras = { + "orig_nchan": cnt.get_channel_count(), + "orig_ch_units": ch_units, + "first_samples": np.array(first_samps), + "last_samples": np.array(last_samps), + } + super().__init__( + info, + preload=preload, + first_samps=first_samps, + last_samps=last_samps, + filenames=[fname], + verbose=verbose, + raw_extras=[raw_extras], + ) + # look for annotations (called trigger by ant) + onsets, durations, descriptions, impedances, disconnect = read_triggers(cnt) + onsets, durations, descriptions = _prepare_annotations( + onsets, durations, descriptions, disconnect, impedance_annotation + ) + onsets = np.array(onsets) / self.info["sfreq"] + durations = np.array(durations) / self.info["sfreq"] + annotations = Annotations(onsets, duration=durations, description=descriptions) + self.set_annotations(annotations) + # set impedance similarly as for brainvision files + self._impedances = [ + {ch: imp[k] for k, ch in enumerate(ch_names)} for imp in impedances + ] + + @property + def impedances(self) -> list[dict[str, float]]: + """List of impedance measurements.""" + return self._impedances + + def _read_segment_file(self, data, idx, fi, start, stop, cals, mult): + from antio import read_cnt + from antio.parser import read_data + + ch_units = self._raw_extras[0]["orig_ch_units"] + first_samples = self._raw_extras[0]["first_samples"] + n_times = self._raw_extras[0]["last_samples"] + 1 + for first_samp, this_n_times in zip(first_samples, n_times): + i_start = max(start, first_samp) + i_stop = min(stop, this_n_times + first_samp) + # read and scale data array + cnt = read_cnt(self._filenames[fi]) + one = read_data(cnt, i_start, i_stop) + _scale_data(one, ch_units) + data_view = data[:, i_start - start : i_stop - start] + if isinstance(idx, slice): + data_view[:] = one[idx] + else: + # faster than doing one = one[idx] + np.take(one, idx, axis=0, out=data_view) + + +def _handle_bipolar_channels( + ch_names: list[str], ch_refs: list[str], bipolars: list[str] | tuple[str, ...] +) -> list[int]: + """Handle bipolar channels.""" + bipolars_idx = [] + for ch in bipolars: + _validate_type(ch, (str,), "bipolar_channel") + if "-" not in ch: + raise ValueError( + "Bipolar channels should be provided as 'anode-cathode' or " + f"'label-reference'. '{ch}' is not valid." + ) + anode, cathode = ch.split("-") + if anode not in ch_names: + raise ValueError(f"Anode channel {anode} not found in the channels.") + idx = ch_names.index(anode) + if cathode != ch_refs[idx]: + raise ValueError( + f"Reference electrode for {anode} is {ch_refs[idx]}, not {cathode}." + ) + # store idx for later FIFF coil type change + bipolars_idx.append(idx) + return bipolars_idx + + +def _parse_ch_types( + ch_names: list[str], eog: str | None, misc: str | None, ch_refs: list[str] +) -> list[str]: + """Parse the channel types.""" + eog = re.compile(eog) if eog is not None else None + misc = re.compile(misc) if misc is not None else None + ch_types = [] + for ch in ch_names: + if eog is not None and re.fullmatch(eog, ch): + ch_types.append("eog") + elif misc is not None and re.fullmatch(misc, ch): + ch_types.append("misc") + else: + ch_types.append("eeg") + eeg_refs = [ch_refs[k] for k, elt in enumerate(ch_types) if elt == "eeg"] + if len(set(eeg_refs)) == 1: + logger.info( + "All %i EEG channels are referenced to %s.", len(eeg_refs), eeg_refs[0] + ) + else: + warn("All EEG channels are not referenced to the same electrode.") + return ch_types + + +def _prepare_annotations( + onsets: list[int], + durations: list[int], + descriptions: list[str], + disconnect: dict[str, list[int]], + impedance_annotation: str, +) -> tuple[list[int], list[int], list[str]]: + """Parse the ANT triggers into better Annotations.""" + # first, let's replace the description 'impedance' with impedance_annotation + for k, desc in enumerate(descriptions): + if desc.lower() == "impedance": + descriptions[k] = impedance_annotation + # next, let's look for amplifier connection/disconnection and let's try to create + # BAD_disconnection annotations from them. + if ( + len(disconnect["start"]) == len(disconnect["stop"]) + and len(disconnect["start"]) != 0 + and all( + 0 <= stop - start + for start, stop in zip(disconnect["start"], disconnect["stop"]) + ) + ): + for start, stop in zip(disconnect["start"], disconnect["stop"]): + onsets.append(start) + durations.append(stop - start) + descriptions.append("BAD_disconnection") + else: + for elt in disconnect["start"]: + onsets.append(elt) + durations.append(0) + descriptions.append("Amplifier disconnected") + for elt in disconnect["stop"]: + onsets.append(elt) + durations.append(0) + descriptions.append("Amplifier reconnected") + return onsets, durations, descriptions + + +def _scale_data(data: NDArray[np.float64], ch_units: list[str]) -> None: + """Scale the data array based on the human-readable units reported by ANT. + + Operates in-place. + """ + units_index = defaultdict(list) + for idx, unit in enumerate(ch_units): + units_index[unit].append(idx) + for unit, value in units_index.items(): + if unit in units: + data[np.array(value, dtype=np.int16), :] *= units[unit] + else: + warn( + f"Unit {unit} not recognized, not scaling. Please report the unit on " + "a github issue on https://github.com/mne-tools/mne-python." + ) + + +@copy_doc(RawANT) +def read_raw_ant( + fname, + eog=None, + misc=r"BIP\d+", + bipolars=None, + impedance_annotation="impedance", + *, + preload=False, + verbose=None, +) -> RawANT: + """ + Returns + ------- + raw : instance of RawANT + A Raw object containing ANT data. + See :class:`mne.io.Raw` for documentation of attributes and methods. + The impedance measurements are stored in the extra attribute ``raw.impedances``. + """ + return RawANT( + fname, + eog=eog, + misc=misc, + bipolars=bipolars, + impedance_annotation=impedance_annotation, + preload=preload, + verbose=verbose, + ) diff --git a/mne/io/ant/tests/__init__.py b/mne/io/ant/tests/__init__.py new file mode 100644 index 00000000000..04c673b4e4d --- /dev/null +++ b/mne/io/ant/tests/__init__.py @@ -0,0 +1,3 @@ +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. diff --git a/mne/io/ant/tests/test_ant.py b/mne/io/ant/tests/test_ant.py new file mode 100644 index 00000000000..825ef0bde95 --- /dev/null +++ b/mne/io/ant/tests/test_ant.py @@ -0,0 +1,495 @@ +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + +from __future__ import annotations + +import warnings +from pathlib import Path + +import numpy as np +import pytest +from numpy.testing import assert_allclose + +from mne import Annotations +from mne._fiff.constants import FIFF +from mne.datasets import testing +from mne.io import BaseRaw, read_raw, read_raw_ant, read_raw_brainvision +from mne.io.ant.ant import RawANT + +pytest.importorskip("antio", minversion="0.4.0") +data_path = testing.data_path(download=False) / "antio" + + +TypeDataset = dict[ + str, dict[str, Path] | str | int | tuple[str, str, str] | dict[str, str] | None +] + + +def read_raw_bv(fname: Path) -> BaseRaw: + """Read a brainvision file exported from eego. + + For some reason, the first impedance measurement is annotated at sample 0. But since + BrainVision files are 1-indexed, the reader removes '1' to create 0-indexed + annotations. Thus, the first impedance measurement annotation ends up with an onset + 1 sample before the start of the recording. + This is not really an issue as the annotation duration is sufficient to make sure + that MNE does not drop it entirely as 'outside of the data range'. + """ + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", + message="Limited .* annotation.*outside the data range.", + category=RuntimeWarning, + ) + raw_bv = read_raw_brainvision(fname) + return raw_bv + + +@pytest.fixture(scope="module") +def ca_208() -> TypeDataset: + """Return the paths to the CA_208 dataset containing 64 channel gel recordings.""" + cnt = { + "short": data_path / "CA_208" / "test_CA_208.cnt", + "amp-dc": data_path / "CA_208" / "test_CA_208_amp_disconnection.cnt", + "start-stop": data_path / "CA_208" / "test_CA_208_start_stop.cnt", + } + bv = {key: value.with_suffix(".vhdr") for key, value in cnt.items()} + return { + "cnt": cnt, + "bv": bv, + "n_eeg": 64, + "n_misc": 24, + "meas_date": "2024-08-14-10-44-47+0000", + "patient_info": { + "name": "antio test", + "his_id": "", + "birthday": "2024-08-14", + "sex": 0, + }, + "machine_info": ("eego", "EE_225", ""), + "hospital": "", + } + + +@pytest.fixture(scope="module") +def ca_208_refs() -> TypeDataset: + """Return the paths and info to the CA_208_refs dataset. + + The following montage was applid on export: + - highpass: 0.3 Hz - lowpass: 30 Hz + - Fp1, Fpz, Fp2 referenced to Fz + - CP3, CP4 referenced to Cz + - others to CPz + """ + cnt = { + "short": data_path / "CA_208_refs" / "test-ref.cnt", + "legacy": data_path / "CA_208_refs" / "test-ref-legacy.cnt", + } + bv = { + "short": cnt["short"].with_suffix(".vhdr"), + } + return { + "cnt": cnt, + "bv": bv, + "n_eeg": 64, + "n_misc": 0, + "meas_date": "2024-09-09-10-57-44+0000", + "patient_info": { + "name": "antio test", + "his_id": "", + "birthday": "2024-08-14", + "sex": 0, + }, + "machine_info": ("eego", "EE_225", ""), + "hospital": "", + } + + +@pytest.fixture(scope="module") +def andy_101() -> TypeDataset: + """Return the path and info to the andy_101 dataset.""" + cnt = { + "short": data_path / "andy_101" / "Andy_101-raw.cnt", + } + bv = {key: value.with_suffix(".vhdr") for key, value in cnt.items()} + return { + "cnt": cnt, + "bv": bv, + "n_eeg": 128, + "n_misc": 0, + "meas_date": "2024-08-19-16-17-07+0000", + "patient_info": { + "name": "Andy test_middle_name EEG_Exam", + "his_id": "test_subject_code", + "birthday": "2024-08-19", + "sex": 2, + }, + "machine_info": ("eego", "EE_226", ""), + "hospital": "", + } + + +@pytest.fixture(scope="module") +def na_271() -> TypeDataset: + """Return the path to a dataset containing 128 channel recording. + + The recording was done with an NA_271 net dipped in saline solution. + """ + cnt = { + "short": data_path / "NA_271" / "test-na-271.cnt", + "legacy": data_path / "NA_271" / "test-na-271-legacy.cnt", + } + bv = { + "short": cnt["short"].with_suffix(".vhdr"), + } + return { + "cnt": cnt, + "bv": bv, + "n_eeg": 128, + "n_misc": 0, + "meas_date": "2024-09-06-10-45-07+0000", + "patient_info": { + "name": "antio test", + "his_id": "", + "birthday": "2024-08-14", + "sex": 0, + }, + "machine_info": ("eego", "EE_226", ""), + "hospital": "", + } + + +@pytest.fixture(scope="module") +def na_271_bips() -> TypeDataset: + """Return the path to a dataset containing 128 channel recording. + + The recording was done with an NA_271 net dipped in saline solution and includes + bipolar channels. + """ + cnt = { + "short": data_path / "NA_271_bips" / "test-na-271.cnt", + "legacy": data_path / "NA_271_bips" / "test-na-271-legacy.cnt", + } + bv = { + "short": cnt["short"].with_suffix(".vhdr"), + } + return { + "cnt": cnt, + "bv": bv, + "n_eeg": 128, + "n_misc": 6, + "meas_date": "2024-09-06-10-37-23+0000", + "patient_info": { + "name": "antio test", + "his_id": "", + "birthday": "2024-08-14", + "sex": 0, + }, + "machine_info": ("eego", "EE_226", ""), + "hospital": "", + } + + +@pytest.fixture(scope="module") +def user_annotations() -> TypeDataset: + """Return the path to a dataset containing user annotations with floating pins.""" + cnt = { + "short": data_path / "user_annotations" / "test-user-annotation.cnt", + "legacy": data_path / "user_annotations" / "test-user-annotation-legacy.cnt", + } + bv = { + "short": cnt["short"].with_suffix(".vhdr"), + } + return { + "cnt": cnt, + "bv": bv, + "n_eeg": 64, + "n_misc": 0, + "meas_date": "2024-08-29-16-15-44+0000", + "patient_info": { + "name": "test test", + "his_id": "", + "birthday": "2024-02-06", + "sex": 0, + }, + "machine_info": ("eego", "EE_225", ""), + "hospital": "", + } + + +@testing.requires_testing_data +@pytest.mark.parametrize("dataset", ["ca_208", "andy_101", "na_271"]) +def test_io_data(dataset, request): + """Test loading of .cnt file.""" + dataset = request.getfixturevalue(dataset) + raw_cnt = read_raw_ant(dataset["cnt"]["short"]) # preload=False + raw_bv = read_raw_bv(dataset["bv"]["short"]) + cnt = raw_cnt.get_data() + bv = raw_bv.get_data() + assert cnt.shape == bv.shape + assert_allclose(cnt, bv, atol=1e-8) + + # check preload=False and preload=False with raw.load_data() + raw_cnt.crop(0.05, 1.05) + raw_cnt2 = read_raw_ant(dataset["cnt"]["short"], preload=False) + raw_cnt2.crop(0.05, 1.05).load_data() + assert_allclose(raw_cnt.get_data(), raw_cnt2.get_data()) + + # check preload=False vs Brainvision file + raw_bv.crop(0.05, 1.05) + assert_allclose(raw_cnt.get_data(), raw_bv.get_data(), atol=1e-8) + + # check preload=False vs BrainVision file after dropping channels + raw_cnt.pick(raw_cnt.ch_names[::2]) + raw_bv.pick(raw_bv.ch_names[::2]) + assert_allclose(raw_cnt.get_data(), raw_bv.get_data(), atol=1e-8) + + # check after raw_cnt.load_data() + raw_cnt.load_data() + assert_allclose(raw_cnt.get_data(), raw_bv.get_data(), atol=1e-8) + + # check preload True vs False + raw_cnt = read_raw_ant(dataset["cnt"]["short"], preload=False) + raw_cnt2 = read_raw_ant(dataset["cnt"]["short"], preload=True) + bads = [raw_cnt.ch_names[idx] for idx in (1, 5, 10)] + assert_allclose( + raw_cnt.drop_channels(bads).get_data(), raw_cnt2.drop_channels(bads).get_data() + ) + raw_bv = read_raw_bv(dataset["bv"]["short"]).drop_channels(bads) + assert_allclose(raw_cnt.get_data(), raw_bv.get_data(), atol=1e-8) + assert_allclose(raw_cnt2.get_data(), raw_bv.get_data(), atol=1e-8) + + +@testing.requires_testing_data +@pytest.mark.parametrize("dataset", ["ca_208", "andy_101", "na_271"]) +def test_io_info(dataset, request): + """Test the ifo loaded from a .cnt file.""" + dataset = request.getfixturevalue(dataset) + raw_cnt = read_raw_ant(dataset["cnt"]["short"]) # preload=False + raw_bv = read_raw_bv(dataset["bv"]["short"]) + assert raw_cnt.ch_names == raw_bv.ch_names + assert raw_cnt.info["sfreq"] == raw_bv.info["sfreq"] + assert ( + raw_cnt.get_channel_types() + == ["eeg"] * dataset["n_eeg"] + ["misc"] * dataset["n_misc"] + ) + assert_allclose( + (raw_bv.info["meas_date"] - raw_cnt.info["meas_date"]).total_seconds(), + 0, + atol=1e-3, + ) + + +@testing.requires_testing_data +def test_io_info_parse_misc(ca_208: TypeDataset): + """Test parsing misc channels from a .cnt file.""" + raw_cnt = read_raw_ant(ca_208["cnt"]["short"]) + with pytest.warns( + RuntimeWarning, + match="All EEG channels are not referenced to the same electrode.", + ): + raw_cnt = read_raw_ant(ca_208["cnt"]["short"], misc=None) + assert len(raw_cnt.ch_names) == ca_208["n_eeg"] + ca_208["n_misc"] + assert raw_cnt.get_channel_types() == ["eeg"] * len(raw_cnt.ch_names) + + +def test_io_info_parse_non_standard_misc(na_271_bips: TypeDataset): + """Test parsing misc channels with modified names from a .cnt file.""" + with pytest.warns( + RuntimeWarning, match="EEG channels are not referenced to the same electrode" + ): + raw = read_raw_ant(na_271_bips["cnt"]["short"], misc=None) + assert raw.get_channel_types() == ["eeg"] * ( + na_271_bips["n_eeg"] + na_271_bips["n_misc"] + ) + raw = read_raw_ant( + na_271_bips["cnt"]["short"], preload=False, misc=r".{0,1}E.{1}G|Aux|Audio" + ) + assert ( + raw.get_channel_types() + == ["eeg"] * na_271_bips["n_eeg"] + ["misc"] * na_271_bips["n_misc"] + ) + + +@testing.requires_testing_data +def test_io_info_parse_eog(ca_208: TypeDataset): + """Test parsing EOG channels from a .cnt file.""" + raw_cnt = read_raw_ant(ca_208["cnt"]["short"], eog="EOG") + assert len(raw_cnt.ch_names) == ca_208["n_eeg"] + ca_208["n_misc"] + idx = raw_cnt.ch_names.index("EOG") + ch_types = ["eeg"] * ca_208["n_eeg"] + ["misc"] * ca_208["n_misc"] + ch_types[idx] = "eog" + assert raw_cnt.get_channel_types() == ch_types + + +@testing.requires_testing_data +@pytest.mark.parametrize( + "dataset", ["andy_101", "ca_208", "na_271", "user_annotations"] +) +def test_subject_info(dataset, request): + """Test reading the subject info.""" + dataset = request.getfixturevalue(dataset) + raw_cnt = read_raw_ant(dataset["cnt"]["short"]) + subject_info = raw_cnt.info["subject_info"] + assert subject_info["his_id"] == dataset["patient_info"]["his_id"] + assert subject_info["first_name"] == dataset["patient_info"]["name"] + assert subject_info["sex"] == dataset["patient_info"]["sex"] + assert ( + subject_info["birthday"].strftime("%Y-%m-%d") + == dataset["patient_info"]["birthday"] + ) + + +@testing.requires_testing_data +@pytest.mark.parametrize( + "dataset", ["andy_101", "ca_208", "na_271", "user_annotations"] +) +def test_machine_info(dataset, request): + """Test reading the machine info.""" + dataset = request.getfixturevalue(dataset) + raw_cnt = read_raw_ant(dataset["cnt"]["short"]) + device_info = raw_cnt.info["device_info"] + make, model, serial = dataset["machine_info"] + assert device_info["type"] == make + assert device_info["model"] == model + assert device_info["serial"] == serial + + +@testing.requires_testing_data +def test_io_amp_disconnection(ca_208: TypeDataset): + """Test loading of .cnt file with amplifier disconnection.""" + raw_cnt = read_raw_ant(ca_208["cnt"]["amp-dc"]) + raw_bv = read_raw_bv(ca_208["bv"]["amp-dc"]) + assert_allclose(raw_cnt.get_data(), raw_bv.get_data(), atol=1e-8) + assert ( + raw_cnt.get_data(reject_by_annotation="omit").shape != raw_bv.get_data().shape + ) + # create annotation on the BV file + idx = [ + k + for k, elt in enumerate(raw_bv.annotations.description) + if any(code in elt for code in ("9001", "9002")) + ] + assert len(idx) == 2 + start = raw_bv.annotations.onset[idx[0]] + stop = raw_bv.annotations.onset[idx[1]] + annotations = Annotations( + onset=start, + duration=stop - start + 1 / raw_bv.info["sfreq"], # estimate is 1 sample short + description="BAD_segment", + ) + raw_bv.set_annotations(annotations) + assert_allclose( + raw_cnt.get_data(reject_by_annotation="omit"), + raw_bv.get_data(reject_by_annotation="omit"), + atol=1e-8, + ) + + +@testing.requires_testing_data +@pytest.mark.parametrize("description", ["impedance", "test"]) +def test_io_impedance(ca_208: TypeDataset, description: str): + """Test loading of impedances from a .cnt file.""" + raw_cnt = read_raw_ant(ca_208["cnt"]["amp-dc"], impedance_annotation=description) + assert isinstance(raw_cnt.impedances, list) + for elt in raw_cnt.impedances: + assert isinstance(elt, dict) + assert list(elt) == raw_cnt.ch_names + assert all(isinstance(val, float) for val in elt.values()) + annotations = [ + annot for annot in raw_cnt.annotations if annot["description"] == description + ] + assert len(annotations) == len(raw_cnt.impedances) + + +@testing.requires_testing_data +def test_io_segments(ca_208: TypeDataset): + """Test reading a .cnt file with segents (start/stop).""" + raw_cnt = read_raw_ant(ca_208["cnt"]["start-stop"]) + raw_bv = read_raw_bv(ca_208["bv"]["start-stop"]) + assert_allclose(raw_cnt.get_data(), raw_bv.get_data(), atol=1e-8) + + +@testing.requires_testing_data +def test_annotations_and_preload(ca_208: TypeDataset): + """Test annotation loading with preload True/False.""" + raw_cnt_preloaded = read_raw_ant(ca_208["cnt"]["short"], preload=True) + assert len(raw_cnt_preloaded.annotations) == 2 # impedance measurements, start/end + raw_cnt = read_raw_ant(ca_208["cnt"]["short"], preload=False) + assert len(raw_cnt.annotations) == 2 + raw_cnt.crop(2, 3) + assert len(raw_cnt.annotations) == 0 + raw_cnt.load_data() + assert len(raw_cnt.annotations) == 0 + + raw_cnt_preloaded = read_raw_ant(ca_208["cnt"]["amp-dc"], preload=True) + assert len(raw_cnt_preloaded.annotations) == 5 # 4 impedances, 1 disconnection + raw_cnt = read_raw_ant(ca_208["cnt"]["amp-dc"], preload=False) + assert len(raw_cnt.annotations) == 5 + idx = np.where(raw_cnt.annotations.description == "BAD_disconnection")[0] + onset = raw_cnt.annotations.onset[idx][0] + raw_cnt.crop(0, onset - 1) + assert len(raw_cnt.annotations) == 1 # initial impedance measurement + assert raw_cnt.annotations.description[0] == "impedance" + + +@testing.requires_testing_data +def test_read_raw(ca_208: TypeDataset): + """Test loading through read_raw.""" + raw = read_raw(ca_208["cnt"]["short"]) + assert isinstance(raw, RawANT) + + +@testing.requires_testing_data +@pytest.mark.parametrize("preload", [True, False]) +def test_read_raw_with_user_annotations(user_annotations: TypeDataset, preload: bool): + """Test reading raw objects which have user annotations.""" + raw = read_raw_ant(user_annotations["cnt"]["short"], preload=preload) + assert raw.annotations + assert "1000/user-annot" in raw.annotations.description + assert "1000/user-annot-2" in raw.annotations.description + + +@testing.requires_testing_data +@pytest.mark.parametrize("dataset", ["na_271", "user_annotations"]) +def test_read_raw_legacy_format(dataset, request): + """Test reading the legacy CNT format.""" + dataset = request.getfixturevalue(dataset) + raw_cnt = read_raw_ant(dataset["cnt"]["short"]) # preload=False + raw_bv = read_raw_bv(dataset["bv"]["short"]) + assert raw_cnt.ch_names == raw_bv.ch_names + assert raw_cnt.info["sfreq"] == raw_bv.info["sfreq"] + assert ( + raw_cnt.get_channel_types() + == ["eeg"] * dataset["n_eeg"] + ["misc"] * dataset["n_misc"] + ) + assert_allclose( + (raw_bv.info["meas_date"] - raw_cnt.info["meas_date"]).total_seconds(), + 0, + atol=1e-3, + ) + + +@testing.requires_testing_data +def test_read_raw_custom_reference(ca_208_refs: TypeDataset): + """Test reading a CNT file with custom EEG references.""" + with pytest.warns( + RuntimeWarning, match="EEG channels are not referenced to the same electrode" + ): + raw = read_raw_ant(ca_208_refs["cnt"]["short"], preload=False) + for ch in raw.info["chs"]: + assert ch["coil_type"] == FIFF.FIFFV_COIL_EEG + bipolars = ("Fp1-Fz", "Fpz-Fz", "Fp2-Fz", "CP3-Cz", "CP4-Cz") + with pytest.warns( + RuntimeWarning, match="EEG channels are not referenced to the same electrode" + ): + raw = read_raw_ant( + ca_208_refs["cnt"]["short"], preload=False, bipolars=bipolars + ) + assert all(elt in raw.ch_names for elt in bipolars) + for ch in raw.info["chs"]: + if ch["ch_name"] in bipolars: + assert ch["coil_type"] == FIFF.FIFFV_COIL_EEG_BIPOLAR + else: + assert ch["coil_type"] == FIFF.FIFFV_COIL_EEG diff --git a/mne/io/array/__init__.py b/mne/io/array/__init__.py index c730a538b2f..aea21ef42ce 100644 --- a/mne/io/array/__init__.py +++ b/mne/io/array/__init__.py @@ -1,6 +1,6 @@ """Module to convert user data to FIF.""" -# Author: Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/array/array.py b/mne/io/array/array.py index dda73b80a23..0349cdf87dc 100644 --- a/mne/io/array/array.py +++ b/mne/io/array/array.py @@ -1,7 +1,6 @@ """Tools for creating Raw objects from numpy arrays.""" -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/array/tests/__init__.py b/mne/io/array/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/array/tests/__init__.py +++ b/mne/io/array/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/array/tests/test_array.py b/mne/io/array/tests/test_array.py index ef0a8a9573c..edac2923c2d 100644 --- a/mne/io/array/tests/test_array.py +++ b/mne/io/array/tests/test_array.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/artemis123/__init__.py b/mne/io/artemis123/__init__.py index 9f57c9587a1..7a51a739098 100644 --- a/mne/io/artemis123/__init__.py +++ b/mne/io/artemis123/__init__.py @@ -1,7 +1,6 @@ """artemis123 module for conversion to FIF.""" -# Author: Luke Bloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/artemis123/artemis123.py b/mne/io/artemis123/artemis123.py index 6c2801e998f..349a62822b6 100644 --- a/mne/io/artemis123/artemis123.py +++ b/mne/io/artemis123/artemis123.py @@ -1,5 +1,4 @@ -# Author: Luke Bloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/artemis123/tests/__init__.py b/mne/io/artemis123/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/artemis123/tests/__init__.py +++ b/mne/io/artemis123/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/artemis123/tests/test_artemis123.py b/mne/io/artemis123/tests/test_artemis123.py index c43409664dc..039108eb915 100644 --- a/mne/io/artemis123/tests/test_artemis123.py +++ b/mne/io/artemis123/tests/test_artemis123.py @@ -1,5 +1,4 @@ -# Author: Luke Bloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/artemis123/utils.py b/mne/io/artemis123/utils.py index 92673c9b04f..90df53ea1aa 100644 --- a/mne/io/artemis123/utils.py +++ b/mne/io/artemis123/utils.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os.path as op import numpy as np diff --git a/mne/io/base.py b/mne/io/base.py index a1485e6caf6..ee5603224b5 100644 --- a/mne/io/base.py +++ b/mne/io/base.py @@ -1,12 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Martin Luessi -# Denis Engemann -# Teon Brooks -# Marijn van Vliet -# Stefan Appelhoff -# Clemens Brunner -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -595,7 +587,7 @@ def load_data(self, verbose=None): def _preload_data(self, preload): """Actually preload the data.""" data_buffer = preload - if isinstance(preload, (bool, np.bool_)) and not preload: + if isinstance(preload, bool | np.bool_) and not preload: data_buffer = None logger.info( "Reading %d ... %d = %9.3f ... %9.3f secs..." @@ -794,7 +786,7 @@ def _parse_get_set_params(self, item): # Let's do automated type conversion to integer here if np.array(item[1]).dtype.kind == "i": item1 = int(item1) - if isinstance(item1, (int, np.integer)): + if isinstance(item1, int | np.integer): start, stop, step = item1, item1 + 1, 1 # Need to special case -1, because -1:0 will be empty if start == -1: @@ -807,7 +799,7 @@ def _parse_get_set_params(self, item): if step is not None and step != 1: raise ValueError("step needs to be 1 : %d given" % step) - if isinstance(sel, (int, np.integer)): + if isinstance(sel, int | np.integer): sel = np.array([sel]) if sel is not None and len(sel) == 0: @@ -1671,6 +1663,12 @@ def save( .. versionadded:: 0.17 %(verbose)s + Returns + ------- + fnames : List of path-like + List of path-like objects containing the path to each file split. + .. versionadded:: 1.9 + Notes ----- If Raw is a concatenation of several raw files, **be warned** that @@ -1749,7 +1747,8 @@ def save( cfg = _RawFidWriterCfg(buffer_size, split_size, drop_small_buffer, fmt) raw_fid_writer = _RawFidWriter(self, info, picks, projector, start, stop, cfg) - _write_raw(raw_fid_writer, fname, split_naming, overwrite) + filenames = _write_raw(raw_fid_writer, fname, split_naming, overwrite) + return filenames @verbose def export( @@ -2656,6 +2655,7 @@ def _write_raw(raw_fid_writer, fpath, split_naming, overwrite): fpath.name, n_splits=MAX_N_SPLITS + 1, split_naming=split_naming ) is_next_split, prev_fname = True, None + output_fnames = [] for part_idx in range(0, MAX_N_SPLITS): if not is_next_split: break @@ -2680,11 +2680,15 @@ def _write_raw(raw_fid_writer, fpath, split_naming, overwrite): logger.info(f"Renaming BIDS split file {fpath.name}") prev_fname = dir_path / split_fnames[0] shutil.move(use_fpath, prev_fname) + output_fnames.append(prev_fname) + else: + output_fnames.append(use_fpath) prev_fname = use_fpath else: raise RuntimeError(f"Exceeded maximum number of splits ({MAX_N_SPLITS}).") logger.info("[done]") + return output_fnames class _ReservedFilename: diff --git a/mne/io/besa/__init__.py b/mne/io/besa/__init__.py index 0d4d86983df..a91614c31a4 100644 --- a/mne/io/besa/__init__.py +++ b/mne/io/besa/__init__.py @@ -1,7 +1,6 @@ """Support for various BESA file formats.""" -# Author: Marijn van Vliet -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/besa/besa.py b/mne/io/besa/besa.py index 907129665c4..d6d4ee9657c 100644 --- a/mne/io/besa/besa.py +++ b/mne/io/besa/besa.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from collections import OrderedDict from pathlib import Path diff --git a/mne/io/besa/tests/test_besa.py b/mne/io/besa/tests/test_besa.py index 2ee2843840b..60deb1b4820 100644 --- a/mne/io/besa/tests/test_besa.py +++ b/mne/io/besa/tests/test_besa.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Test reading BESA fileformats.""" import inspect diff --git a/mne/io/boxy/__init__.py b/mne/io/boxy/__init__.py index 618a89dc5d0..ac47cccffbc 100644 --- a/mne/io/boxy/__init__.py +++ b/mne/io/boxy/__init__.py @@ -1,7 +1,6 @@ """fNIRS module for conversion to FIF.""" -# Authors: Kyle Mathewson, Jonathan Kuziek -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/boxy/boxy.py b/mne/io/boxy/boxy.py index 85791349294..87cedf1d608 100644 --- a/mne/io/boxy/boxy.py +++ b/mne/io/boxy/boxy.py @@ -1,5 +1,4 @@ -# Authors: Kyle Mathewson, Jonathan Kuziek -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/boxy/tests/__init__.py b/mne/io/boxy/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/boxy/tests/__init__.py +++ b/mne/io/boxy/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/boxy/tests/test_boxy.py b/mne/io/boxy/tests/test_boxy.py index 2e9e1900aaf..58f4671edd0 100644 --- a/mne/io/boxy/tests/test_boxy.py +++ b/mne/io/boxy/tests/test_boxy.py @@ -1,5 +1,4 @@ -# Authors: Kyle Mathewson, Jonathan Kuziek -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/brainvision/__init__.py b/mne/io/brainvision/__init__.py index 5c66c1a82e2..860e157c014 100644 --- a/mne/io/brainvision/__init__.py +++ b/mne/io/brainvision/__init__.py @@ -1,8 +1,6 @@ """BrainVision module for conversion to FIF.""" -# Author: Teon Brooks -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/brainvision/brainvision.py b/mne/io/brainvision/brainvision.py index a4b32d9540a..e58e04e07e6 100644 --- a/mne/io/brainvision/brainvision.py +++ b/mne/io/brainvision/brainvision.py @@ -1,12 +1,6 @@ """Conversion tool from BrainVision EEG to FIF.""" -# Authors: Teon Brooks -# Christian Brodbeck -# Eric Larson -# Jona Sassenhagen -# Phillip Alday -# Okba Bekhelifi -# Stefan Appelhoff -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -69,6 +63,12 @@ class RawBrainVision(BaseRaw): Notes ----- + If the BrainVision header file contains impedance measurements, these may be + accessed using ``raw.impedances`` after reading using this function. However, + this attribute will NOT be available after a save and re-load of the data. + That is, it is only available when reading data directly from the BrainVision + header file. + BrainVision markers consist of a type and a description (in addition to other fields like onset and duration). In contrast, annotations in MNE only have a description. Therefore, a BrainVision marker of type "Stimulus" and description "S 1" will be @@ -983,6 +983,12 @@ def read_raw_brainvision( Notes ----- + If the BrainVision header file contains impedance measurements, these may be + accessed using ``raw.impedances`` after reading using this function. However, + this attribute will NOT be available after a save and re-load of the data. + That is, it is only available when reading data directly from the BrainVision + header file. + BrainVision markers consist of a type and a description (in addition to other fields like onset and duration). In contrast, annotations in MNE only have a description. Therefore, a BrainVision marker of type "Stimulus" and description "S 1" will be diff --git a/mne/io/brainvision/tests/__init__.py b/mne/io/brainvision/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/brainvision/tests/__init__.py +++ b/mne/io/brainvision/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/brainvision/tests/test_brainvision.py b/mne/io/brainvision/tests/test_brainvision.py index f580f05b526..704af064b48 100644 --- a/mne/io/brainvision/tests/test_brainvision.py +++ b/mne/io/brainvision/tests/test_brainvision.py @@ -1,7 +1,6 @@ """Test reading of BrainVision format.""" -# Author: Teon Brooks -# Stefan Appelhoff -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/bti/__init__.py b/mne/io/bti/__init__.py index bf43742efbf..3a9d58fe44c 100644 --- a/mne/io/bti/__init__.py +++ b/mne/io/bti/__init__.py @@ -1,6 +1,6 @@ """BTi module for conversion to FIF.""" -# Author: Denis A. Engemann +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/bti/bti.py b/mne/io/bti/bti.py index cdcf75ae294..6b581b19ef4 100644 --- a/mne/io/bti/bti.py +++ b/mne/io/bti/bti.py @@ -1,12 +1,4 @@ -# Authors: Denis A. Engemann -# Martin Luessi -# Alexandre Gramfort -# Matti Hämäläinen -# Yuval Harpaz -# Joan Massich -# Teon Brooks -# -# simplified BSD-3 license +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/bti/constants.py b/mne/io/bti/constants.py index 3abec30d29a..d135dae6e60 100644 --- a/mne/io/bti/constants.py +++ b/mne/io/bti/constants.py @@ -1,5 +1,4 @@ -# Authors: Denis Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/bti/read.py b/mne/io/bti/read.py index 0ca086f3141..abf4b72cd9e 100644 --- a/mne/io/bti/read.py +++ b/mne/io/bti/read.py @@ -1,5 +1,4 @@ -# Authors: Denis A. Engemann -# simplified BSD-3 license +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/bti/tests/__init__.py b/mne/io/bti/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/bti/tests/__init__.py +++ b/mne/io/bti/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/bti/tests/test_bti.py b/mne/io/bti/tests/test_bti.py index afe387b8769..cc595833275 100644 --- a/mne/io/bti/tests/test_bti.py +++ b/mne/io/bti/tests/test_bti.py @@ -1,5 +1,4 @@ -# Authors: Denis Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/cnt/__init__.py b/mne/io/cnt/__init__.py index d85b6bce1db..10aac79f2f1 100644 --- a/mne/io/cnt/__init__.py +++ b/mne/io/cnt/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """CNT data reader.""" from .cnt import read_raw_cnt diff --git a/mne/io/cnt/_utils.py b/mne/io/cnt/_utils.py index 6a05427ff20..cf2d45cb1ef 100644 --- a/mne/io/cnt/_utils.py +++ b/mne/io/cnt/_utils.py @@ -1,5 +1,4 @@ -# Author: Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/cnt/cnt.py b/mne/io/cnt/cnt.py index 5e5c60ee1a1..09fc145d93f 100644 --- a/mne/io/cnt/cnt.py +++ b/mne/io/cnt/cnt.py @@ -1,10 +1,9 @@ """Conversion tool from Neuroscan CNT to FIF.""" -# Author: Jaakko Leppakangas -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from os import path import numpy as np @@ -449,7 +448,8 @@ def _get_cnt_info(input_fname, eog, ecg, emg, misc, data_format, date_format, he class RawCNT(BaseRaw): """Raw object from Neuroscan CNT file. - .. Note:: + .. note:: + The channel positions are read from the file header. Channels that are not assigned with keywords ``eog``, ``ecg``, ``emg`` and ``misc`` are assigned as eeg channels. All the eeg channel locations are fit to a @@ -460,10 +460,15 @@ class RawCNT(BaseRaw): the header are correct, it is probably safer to use a (standard) montage. See :func:`mne.channels.make_standard_montage` + .. note:: + + A CNT file can also come from the EEG manufacturer ANT Neuro, in which case the + function :func:`mne.io.read_raw_ant` should be used. + Parameters ---------- input_fname : path-like - Path to the CNT file. + Path to the Neuroscan CNT file. eog : list | tuple Names of channels or list of indices that should be designated EOG channels. If ``'auto'``, the channel names beginning with @@ -491,16 +496,6 @@ class RawCNT(BaseRaw): if either contain a bad channel make channel bad. Defaults to ``'auto'``. %(preload)s - stim_channel : bool | None - Add a stim channel from the events. Defaults to None to trigger a - future warning. - - .. warning:: This defaults to True in 0.18 but will change to False in - 0.19 (when no stim channel synthesis will be allowed) - and be removed in 0.20; migrate code to use - :func:`mne.events_from_annotations` instead. - - .. versionadded:: 0.18 %(verbose)s See Also @@ -529,9 +524,16 @@ def __init__( _date_format = "%m/%d/%y %H:%M:%S" input_fname = path.abspath(input_fname) - info, cnt_info = _get_cnt_info( - input_fname, eog, ecg, emg, misc, data_format, _date_format, header - ) + try: + info, cnt_info = _get_cnt_info( + input_fname, eog, ecg, emg, misc, data_format, _date_format, header + ) + except Exception: + raise RuntimeError( + "Could not read header from *.cnt file. mne.io.read_raw_cnt " + "supports Neuroscan CNT files only. If this file is an ANT Neuro CNT, " + "please use mne.io.read_raw_ant instead." + ) last_samps = [cnt_info["n_samples"] - 1] super().__init__( info, diff --git a/mne/io/cnt/tests/__init__.py b/mne/io/cnt/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/cnt/tests/__init__.py +++ b/mne/io/cnt/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/cnt/tests/test_cnt.py b/mne/io/cnt/tests/test_cnt.py index e056ef85880..c098b58e6f3 100644 --- a/mne/io/cnt/tests/test_cnt.py +++ b/mne/io/cnt/tests/test_cnt.py @@ -1,6 +1,4 @@ -# Author: Jaakko Leppakangas -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/constants.py b/mne/io/constants.py index fdac1a856c2..50cf5677731 100644 --- a/mne/io/constants.py +++ b/mne/io/constants.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/__init__.py b/mne/io/ctf/__init__.py index 0a9427f6825..538d63f0ac3 100644 --- a/mne/io/ctf/__init__.py +++ b/mne/io/ctf/__init__.py @@ -1,7 +1,6 @@ """CTF module for conversion to FIF.""" -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/constants.py b/mne/io/ctf/constants.py index 880109d3166..a99b627eeee 100644 --- a/mne/io/ctf/constants.py +++ b/mne/io/ctf/constants.py @@ -1,8 +1,6 @@ """CTF constants.""" -# Authors: Matti Hämäläinen -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/ctf.py b/mne/io/ctf/ctf.py index f503f287a7c..760430e7484 100644 --- a/mne/io/ctf/ctf.py +++ b/mne/io/ctf/ctf.py @@ -1,8 +1,6 @@ """Conversion tool from CTF to FIF.""" -# Authors: Matti Hämäläinen -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/eeg.py b/mne/io/ctf/eeg.py index 940d35dce6e..cd39bc980e0 100644 --- a/mne/io/ctf/eeg.py +++ b/mne/io/ctf/eeg.py @@ -1,7 +1,6 @@ """Read .eeg files.""" -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/hc.py b/mne/io/ctf/hc.py index 5de790d0dac..22acceda0ca 100644 --- a/mne/io/ctf/hc.py +++ b/mne/io/ctf/hc.py @@ -1,7 +1,6 @@ """Read .hc files.""" -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/info.py b/mne/io/ctf/info.py index e12ee4a3d68..6ed0d26d692 100644 --- a/mne/io/ctf/info.py +++ b/mne/io/ctf/info.py @@ -1,7 +1,6 @@ """Populate measurement info.""" -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/markers.py b/mne/io/ctf/markers.py index 5138a4e385d..64360fbc9c3 100644 --- a/mne/io/ctf/markers.py +++ b/mne/io/ctf/markers.py @@ -1,5 +1,4 @@ -# Author: Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/res4.py b/mne/io/ctf/res4.py index 0c964f03af1..b2ecb9dc304 100644 --- a/mne/io/ctf/res4.py +++ b/mne/io/ctf/res4.py @@ -1,8 +1,6 @@ """Read .res4 files.""" -# Authors: Matti Hämäläinen -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/tests/__init__.py b/mne/io/ctf/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/ctf/tests/__init__.py +++ b/mne/io/ctf/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/tests/test_ctf.py b/mne/io/ctf/tests/test_ctf.py index 8c1061ac950..4a5dd846655 100644 --- a/mne/io/ctf/tests/test_ctf.py +++ b/mne/io/ctf/tests/test_ctf.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/ctf/trans.py b/mne/io/ctf/trans.py index b50f659aa5a..3e74063fa40 100644 --- a/mne/io/ctf/trans.py +++ b/mne/io/ctf/trans.py @@ -1,7 +1,6 @@ """Create coordinate transforms.""" -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/curry/__init__.py b/mne/io/curry/__init__.py index 1b46ae8afe2..fce6b7d9a32 100644 --- a/mne/io/curry/__init__.py +++ b/mne/io/curry/__init__.py @@ -1,7 +1,6 @@ """Reader for CURRY data.""" -# Author: Dirk Gütlin -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/curry/curry.py b/mne/io/curry/curry.py index 3754a7ab92d..4d32866209f 100644 --- a/mne/io/curry/curry.py +++ b/mne/io/curry/curry.py @@ -1,8 +1,5 @@ -# -*- coding: UTF-8 -*- -# -# Authors: Dirk Gütlin -# # +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/curry/tests/__init__.py b/mne/io/curry/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/curry/tests/__init__.py +++ b/mne/io/curry/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/curry/tests/test_curry.py b/mne/io/curry/tests/test_curry.py index de5247fb3de..0c63c419525 100644 --- a/mne/io/curry/tests/test_curry.py +++ b/mne/io/curry/tests/test_curry.py @@ -1,7 +1,5 @@ # -# Authors: Dirk Gütlin -# -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/edf/__init__.py b/mne/io/edf/__init__.py index 67f309a6d80..49e41a7ea5b 100644 --- a/mne/io/edf/__init__.py +++ b/mne/io/edf/__init__.py @@ -1,7 +1,6 @@ """EDF+,BDF module for conversion to FIF.""" -# Author: Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/edf/edf.py b/mne/io/edf/edf.py index c388f009e29..778102c28b4 100644 --- a/mne/io/edf/edf.py +++ b/mne/io/edf/edf.py @@ -1,13 +1,6 @@ """Reading tools from EDF, EDF+, BDF, and GDF.""" -# Authors: Teon Brooks -# Martin Billinger -# Nicolas Barascud -# Stefan Appelhoff -# Joan Massich -# Clemens Brunner -# Jeroen Van Der Donckt (IDlab - imec) -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -766,7 +759,7 @@ def _parse_prefilter_string(prefiltering): def _prefilter_float(filt): - if isinstance(filt, (int, float, np.number)): + if isinstance(filt, int | float | np.number): return filt if filt == "DC": return 0.0 diff --git a/mne/io/edf/tests/__init__.py b/mne/io/edf/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/edf/tests/__init__.py +++ b/mne/io/edf/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/edf/tests/test_edf.py b/mne/io/edf/tests/test_edf.py index 45543b90d9d..b4f0ab33fa5 100644 --- a/mne/io/edf/tests/test_edf.py +++ b/mne/io/edf/tests/test_edf.py @@ -1,10 +1,4 @@ -# Authors: Teon Brooks -# Martin Billinger -# Alan Leggitt -# Alexandre Barachant -# Stefan Appelhoff -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/edf/tests/test_gdf.py b/mne/io/edf/tests/test_gdf.py index c743024131e..1dc5dc00a47 100644 --- a/mne/io/edf/tests/test_gdf.py +++ b/mne/io/edf/tests/test_gdf.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Barachant -# Nicolas Barascud -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eeglab/__init__.py b/mne/io/eeglab/__init__.py index 7976ad992ce..6ffc4e416cc 100644 --- a/mne/io/eeglab/__init__.py +++ b/mne/io/eeglab/__init__.py @@ -1,6 +1,6 @@ """EEGLAB module for conversion to FIF.""" -# Author: Mainak Jas +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eeglab/_eeglab.py b/mne/io/eeglab/_eeglab.py index 9d138beab38..173a1fd71bf 100644 --- a/mne/io/eeglab/_eeglab.py +++ b/mne/io/eeglab/_eeglab.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np try: diff --git a/mne/io/eeglab/eeglab.py b/mne/io/eeglab/eeglab.py index e1108b7605d..102765ee7bc 100644 --- a/mne/io/eeglab/eeglab.py +++ b/mne/io/eeglab/eeglab.py @@ -1,7 +1,4 @@ -# Authors: Mainak Jas -# Jona Sassenhagen -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -91,7 +88,7 @@ def _check_load_mat(fname, uint16_codec): def _to_loc(ll): """Check if location exists.""" - if isinstance(ll, (int, float)) or len(ll) > 0: + if isinstance(ll, int | float) or len(ll) > 0: return ll else: return np.nan @@ -627,7 +624,7 @@ def __init__( epochs = _bunchify(eeg.epoch) events = _bunchify(eeg.event) for ep in epochs: - if isinstance(ep.eventtype, (int, float)): + if isinstance(ep.eventtype, int | float): ep.eventtype = str(ep.eventtype) if not isinstance(ep.eventtype, str): event_type = "/".join([str(et) for et in ep.eventtype]) @@ -665,7 +662,7 @@ def __init__( events[idx, 0] = event_latencies[idx] events[idx, 1] = prev_stim events[idx, 2] = event_id[event_name[idx]] - elif isinstance(events, (str, Path, PathLike)): + elif isinstance(events, str | Path | PathLike): events = read_events(events) logger.info(f"Extracting parameters from {input_fname}...") @@ -779,7 +776,7 @@ def _read_annotations_eeglab(eeg, uint16_codec=None): events = [] elif isinstance(eeg.event, dict) and np.array(eeg.event["latency"]).ndim > 0: events = _dol_to_lod(eeg.event) - elif not isinstance(eeg.event, (np.ndarray, list)): + elif not isinstance(eeg.event, np.ndarray | list): events = [eeg.event] else: events = eeg.event diff --git a/mne/io/eeglab/tests/__init__.py b/mne/io/eeglab/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/eeglab/tests/__init__.py +++ b/mne/io/eeglab/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eeglab/tests/test_eeglab.py b/mne/io/eeglab/tests/test_eeglab.py index 84c9be5e0be..cd3fbfd893e 100644 --- a/mne/io/eeglab/tests/test_eeglab.py +++ b/mne/io/eeglab/tests/test_eeglab.py @@ -1,7 +1,4 @@ -# Author: Mainak Jas -# Mikolaj Magnuski -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/egi/__init__.py b/mne/io/egi/__init__.py index de803d94eff..72f638d49e9 100644 --- a/mne/io/egi/__init__.py +++ b/mne/io/egi/__init__.py @@ -1,6 +1,6 @@ """EGI module for conversion to FIF.""" -# Author: Denis A. Engemann +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/egi/egi.py b/mne/io/egi/egi.py index 980b6a7b5bc..433758e19bf 100644 --- a/mne/io/egi/egi.py +++ b/mne/io/egi/egi.py @@ -1,7 +1,4 @@ -# Authors: Denis A. Engemann -# Teon Brooks -# -# simplified BSD-3 license +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -14,7 +11,7 @@ from ..._fiff.meas_info import _empty_info from ..._fiff.utils import _create_chs, _read_segments_file from ...annotations import Annotations -from ...utils import _check_fname, _validate_type, logger, verbose, warn +from ...utils import _check_fname, _validate_type, logger, verbose from ..base import BaseRaw from .egimff import _read_raw_egi_mff from .events import _combine_triggers, _triage_include_exclude @@ -103,7 +100,7 @@ def read_raw_egi( preload=False, channel_naming="E%d", *, - events_as_annotations=None, + events_as_annotations=True, verbose=None, ) -> "RawEGI": """Read EGI simple binary as raw object. @@ -172,13 +169,7 @@ def read_raw_egi( """ _validate_type(input_fname, "path-like", "input_fname") input_fname = str(input_fname) - if events_as_annotations is None: - warn( - "events_as_annotations defaults to False in 1.8 but will change to " - "True in 1.9, set it explicitly to avoid this warning", - FutureWarning, - ) - events_as_annotations = False + _validate_type(events_as_annotations, bool, "events_as_annotations") if input_fname.rstrip("/\\").endswith(".mff"): # allows .mff or .mff/ return _read_raw_egi_mff( diff --git a/mne/io/egi/egimff.py b/mne/io/egi/egimff.py index 1b76ff60cd7..d38d99322ac 100644 --- a/mne/io/egi/egimff.py +++ b/mne/io/egi/egimff.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """EGI NetStation Load Function.""" import datetime @@ -352,7 +354,7 @@ def _read_raw_egi_mff( preload=False, channel_naming="E%d", *, - events_as_annotations=False, + events_as_annotations=True, verbose=None, ): """Read EGI mff binary as raw object.""" diff --git a/mne/io/egi/events.py b/mne/io/egi/events.py index 35f305e0ae5..3096a3c1aa3 100644 --- a/mne/io/egi/events.py +++ b/mne/io/egi/events.py @@ -1,4 +1,5 @@ # +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/egi/general.py b/mne/io/egi/general.py index 1dec9b9ae5f..882de38c3bf 100644 --- a/mne/io/egi/general.py +++ b/mne/io/egi/general.py @@ -1,4 +1,5 @@ # +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/egi/tests/__init__.py b/mne/io/egi/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/egi/tests/__init__.py +++ b/mne/io/egi/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/egi/tests/test_egi.py b/mne/io/egi/tests/test_egi.py index 2f680fd7bd9..d91b4fbd264 100644 --- a/mne/io/egi/tests/test_egi.py +++ b/mne/io/egi/tests/test_egi.py @@ -1,5 +1,4 @@ -# Authors: Denis A. Engemann -# simplified BSD-3 license +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -76,7 +75,7 @@ def test_egi_mff_pause(fname, skip_times, event_times): pytest.importorskip("defusedxml") if fname == egi_pause_w1337_fname: # too slow to _test_raw_reader - raw = read_raw_egi(fname).load_data() + raw = read_raw_egi(fname, events_as_annotations=False).load_data() else: with pytest.warns(RuntimeWarning, match="Acquisition skips detected"): raw = _test_raw_reader( @@ -84,6 +83,7 @@ def test_egi_mff_pause(fname, skip_times, event_times): input_fname=fname, test_scaling=False, # XXX probably some bug test_rank="less", + events_as_annotations=False, ) assert raw.info["sfreq"] == 250.0 # true for all of these files assert len(raw.annotations) == len(skip_times) @@ -253,6 +253,7 @@ def test_io_egi(): include=include, test_rank="less", test_scaling=False, # XXX probably some bug + events_as_annotations=False, ) assert "eeg" in raw diff --git a/mne/io/eximia/__init__.py b/mne/io/eximia/__init__.py index 72922eeb9de..2530990e13e 100644 --- a/mne/io/eximia/__init__.py +++ b/mne/io/eximia/__init__.py @@ -1,7 +1,6 @@ """Eximia module for conversion to FIF.""" -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eximia/eximia.py b/mne/io/eximia/eximia.py index b627f85997c..5d21879de32 100644 --- a/mne/io/eximia/eximia.py +++ b/mne/io/eximia/eximia.py @@ -1,6 +1,4 @@ -# Authors: Eric Larson -# Federico Raimondo -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eximia/tests/__init__.py b/mne/io/eximia/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/eximia/tests/__init__.py +++ b/mne/io/eximia/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eximia/tests/test_eximia.py b/mne/io/eximia/tests/test_eximia.py index 0883e86d2f5..5eef3382970 100644 --- a/mne/io/eximia/tests/test_eximia.py +++ b/mne/io/eximia/tests/test_eximia.py @@ -1,5 +1,4 @@ -# Authors: Federico Raimondo -# simplified BSD-3 license +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eyelink/__init__.py b/mne/io/eyelink/__init__.py index c32b8b4c5d7..2d5e5290b22 100644 --- a/mne/io/eyelink/__init__.py +++ b/mne/io/eyelink/__init__.py @@ -1,8 +1,6 @@ """Module for loading Eye-Tracker data.""" -# Authors: Dominik Welke -# Scott Huberty -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eyelink/_utils.py b/mne/io/eyelink/_utils.py index a6df2a7e82d..bf87920094b 100644 --- a/mne/io/eyelink/_utils.py +++ b/mne/io/eyelink/_utils.py @@ -1,5 +1,6 @@ """Helper functions for reading eyelink ASCII files.""" -# Authors: Scott Huberty + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eyelink/eyelink.py b/mne/io/eyelink/eyelink.py index 2ab00d22b58..192a5555465 100644 --- a/mne/io/eyelink/eyelink.py +++ b/mne/io/eyelink/eyelink.py @@ -1,9 +1,6 @@ """SR Research Eyelink Load Function.""" -# Authors: Dominik Welke -# Scott Huberty -# Christian O'Reilly -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eyelink/tests/__init__.py b/mne/io/eyelink/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/eyelink/tests/__init__.py +++ b/mne/io/eyelink/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/eyelink/tests/test_eyelink.py b/mne/io/eyelink/tests/test_eyelink.py index 1b510670a95..e270b8cbbe5 100644 --- a/mne/io/eyelink/tests/test_eyelink.py +++ b/mne/io/eyelink/tests/test_eyelink.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from pathlib import Path import numpy as np diff --git a/mne/io/fieldtrip/__init__.py b/mne/io/fieldtrip/__init__.py index 43e1cfbe50f..efdd3d2eda6 100644 --- a/mne/io/fieldtrip/__init__.py +++ b/mne/io/fieldtrip/__init__.py @@ -1,7 +1,4 @@ -# -*- coding: UTF-8 -*- -# Authors: Thomas Hartmann -# Dirk Gütlin -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/fieldtrip/fieldtrip.py b/mne/io/fieldtrip/fieldtrip.py index 192782851db..5d94d3e0a80 100644 --- a/mne/io/fieldtrip/fieldtrip.py +++ b/mne/io/fieldtrip/fieldtrip.py @@ -1,7 +1,4 @@ -# -*- coding: UTF-8 -*- -# Authors: Thomas Hartmann -# Dirk Gütlin -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/fieldtrip/tests/__init__.py b/mne/io/fieldtrip/tests/__init__.py index 3c50da09974..04c673b4e4d 100644 --- a/mne/io/fieldtrip/tests/__init__.py +++ b/mne/io/fieldtrip/tests/__init__.py @@ -1,6 +1,3 @@ -# -*- coding: UTF-8 -*- -# Authors: Thomas Hartmann -# Dirk Gütlin -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/fieldtrip/tests/helpers.py b/mne/io/fieldtrip/tests/helpers.py index 4a4202253ca..0a0f6671d6b 100644 --- a/mne/io/fieldtrip/tests/helpers.py +++ b/mne/io/fieldtrip/tests/helpers.py @@ -1,9 +1,7 @@ -# -*- coding: UTF-8 -*- -# Authors: Thomas Hartmann -# Dirk Gütlin -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os from functools import partial diff --git a/mne/io/fieldtrip/tests/test_fieldtrip.py b/mne/io/fieldtrip/tests/test_fieldtrip.py index 15c374bb9ad..341a67df7c4 100644 --- a/mne/io/fieldtrip/tests/test_fieldtrip.py +++ b/mne/io/fieldtrip/tests/test_fieldtrip.py @@ -1,7 +1,4 @@ -# -*- coding: UTF-8 -*- -# Authors: Thomas Hartmann -# Dirk Gütlin -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/fieldtrip/utils.py b/mne/io/fieldtrip/utils.py index cf8a9fc311d..f855b7cf0cf 100644 --- a/mne/io/fieldtrip/utils.py +++ b/mne/io/fieldtrip/utils.py @@ -1,9 +1,7 @@ -# -*- coding: UTF-8 -*- -# Authors: Thomas Hartmann -# Dirk Gütlin -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np from ..._fiff._digitization import DigPoint, _ensure_fiducials_head diff --git a/mne/io/fiff/__init__.py b/mne/io/fiff/__init__.py index ed9f47290ca..3d83b2c7a7b 100644 --- a/mne/io/fiff/__init__.py +++ b/mne/io/fiff/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """FIF raw data reader.""" from .raw import Raw diff --git a/mne/io/fiff/raw.py b/mne/io/fiff/raw.py index 1e15faa6a2d..7974be57665 100644 --- a/mne/io/fiff/raw.py +++ b/mne/io/fiff/raw.py @@ -1,9 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Martin Luessi -# Denis Engemann -# Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/fiff/tests/__init__.py b/mne/io/fiff/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/fiff/tests/__init__.py +++ b/mne/io/fiff/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/fiff/tests/test_raw_fiff.py b/mne/io/fiff/tests/test_raw_fiff.py index bcbf87f9dfc..9f0db8e4e9f 100644 --- a/mne/io/fiff/tests/test_raw_fiff.py +++ b/mne/io/fiff/tests/test_raw_fiff.py @@ -1,6 +1,4 @@ -# Author: Alexandre Gramfort -# Denis Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -525,9 +523,11 @@ def test_split_files(tmp_path, mod, monkeypatch): # Check that if BIDS is used and no split is needed it defaults to # simple writing without _split- entity. - raw_1.save(split_fname, split_naming="bids", verbose=True) + split_fnames = raw_1.save(split_fname, split_naming="bids", verbose=True) assert split_fname.is_file() assert not split_fname_bids_part1.is_file() + assert split_fnames == [split_fname] + for split_naming in ("neuromag", "bids"): with pytest.raises(FileExistsError, match="Destination file"): raw_1.save(split_fname, split_naming=split_naming, verbose=True) @@ -537,17 +537,21 @@ def test_split_files(tmp_path, mod, monkeypatch): with pytest.raises(FileExistsError, match="Destination file"): raw_1.save(split_fname, split_naming="bids", verbose=True) assert not split_fname.is_file() - raw_1.save(split_fname, split_naming="neuromag", verbose=True) # okay + split_fnames = raw_1.save( + split_fname, split_naming="neuromag", verbose=True + ) # okay os.remove(split_fname) os.remove(split_fname_bids_part1) - - raw_1.save(split_fname, buffer_size_sec=1.0, split_size="10MB", verbose=True) - + # Multiple splits + split_filenames = raw_1.save( + split_fname, buffer_size_sec=1.0, split_size="10MB", verbose=True + ) # check that the filenames match the intended pattern assert split_fname.is_file() assert split_fname_elekta_part2.is_file() + assert split_filenames == [split_fname, split_fname_elekta_part2] # check that filenames are being formatted correctly for BIDS - raw_1.save( + split_filenames = raw_1.save( split_fname, buffer_size_sec=1.0, split_size="10MB", @@ -557,6 +561,7 @@ def test_split_files(tmp_path, mod, monkeypatch): ) assert split_fname_bids_part1.is_file() assert split_fname_bids_part2.is_file() + assert split_filenames == [split_fname_bids_part1, split_fname_bids_part2] annot = Annotations(np.arange(20), np.ones((20,)), "test") raw_1.set_annotations(annot) diff --git a/mne/io/fil/__init__.py b/mne/io/fil/__init__.py index 9bf34124866..ad780452c77 100644 --- a/mne/io/fil/__init__.py +++ b/mne/io/fil/__init__.py @@ -1,5 +1,4 @@ -# Authors: George O'Neill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/fil/fil.py b/mne/io/fil/fil.py index 286340fa0d0..a7dd157049a 100644 --- a/mne/io/fil/fil.py +++ b/mne/io/fil/fil.py @@ -1,5 +1,4 @@ -# Authors: George O'Neill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -307,7 +306,7 @@ def _from_tsv(fname, dtypes=None): data_dict = dict() if dtypes is None: dtypes = [str] * info.shape[1] - if not isinstance(dtypes, (list, tuple)): + if not isinstance(dtypes, list | tuple): dtypes = [dtypes] * info.shape[1] if not len(dtypes) == info.shape[1]: raise ValueError( diff --git a/mne/io/fil/sensors.py b/mne/io/fil/sensors.py index 044f8442b46..6431a16bb4d 100644 --- a/mne/io/fil/sensors.py +++ b/mne/io/fil/sensors.py @@ -1,5 +1,4 @@ -# Authors: George O'Neill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/fil/tests/test_fil.py b/mne/io/fil/tests/test_fil.py index f3badae750f..06d3d924319 100644 --- a/mne/io/fil/tests/test_fil.py +++ b/mne/io/fil/tests/test_fil.py @@ -1,5 +1,4 @@ -# Authors: George O'Neill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/hitachi/__init__.py b/mne/io/hitachi/__init__.py index 6fa7f0753ce..fc2cdec78ee 100644 --- a/mne/io/hitachi/__init__.py +++ b/mne/io/hitachi/__init__.py @@ -1,7 +1,6 @@ """fNIRS module for conversion to FIF.""" -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/hitachi/hitachi.py b/mne/io/hitachi/hitachi.py index 05c571c7a8c..fe4e057c495 100644 --- a/mne/io/hitachi/hitachi.py +++ b/mne/io/hitachi/hitachi.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -69,7 +68,7 @@ class RawHitachi(BaseRaw): @verbose def __init__(self, fname, preload=False, *, verbose=None): - if not isinstance(fname, (list, tuple)): + if not isinstance(fname, list | tuple): fname = [fname] fname = list(fname) # our own list that we can modify for fi, this_fname in enumerate(fname): diff --git a/mne/io/hitachi/tests/test_hitachi.py b/mne/io/hitachi/tests/test_hitachi.py index 300af7cf5e8..09b01b535e3 100644 --- a/mne/io/hitachi/tests/test_hitachi.py +++ b/mne/io/hitachi/tests/test_hitachi.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/kit/__init__.py b/mne/io/kit/__init__.py index 5c84d63705b..c522113f64e 100644 --- a/mne/io/kit/__init__.py +++ b/mne/io/kit/__init__.py @@ -1,7 +1,6 @@ """KIT module for reading raw data.""" -# Author: Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/kit/constants.py b/mne/io/kit/constants.py index 5532b523c9f..7831e81c6fa 100644 --- a/mne/io/kit/constants.py +++ b/mne/io/kit/constants.py @@ -1,8 +1,6 @@ """KIT constants.""" -# Authors: Teon Brooks -# Christian Brodbeck -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/kit/coreg.py b/mne/io/kit/coreg.py index 739a82a3137..8e6698d6f78 100644 --- a/mne/io/kit/coreg.py +++ b/mne/io/kit/coreg.py @@ -1,7 +1,6 @@ """Coordinate Point Extractor for KIT system.""" -# Author: Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -136,7 +135,7 @@ def _set_dig_kit(mrk, elp, hsp, eeg, *, bad_coils=()): """ from ...coreg import _decimate_points, fit_matched_points - if isinstance(hsp, (str, Path, PathLike)): + if isinstance(hsp, str | Path | PathLike): hsp = _read_dig_kit(hsp) n_pts = len(hsp) if n_pts > KIT.DIG_POINTS: @@ -148,7 +147,7 @@ def _set_dig_kit(mrk, elp, hsp, eeg, *, bad_coils=()): f"{n_new} points. The preferred way to downsample is using FastScan." ) - if isinstance(elp, (str, Path, PathLike)): + if isinstance(elp, str | Path | PathLike): elp_points = _read_dig_kit(elp) if len(elp_points) != 8: raise ValueError( @@ -162,7 +161,7 @@ def _set_dig_kit(mrk, elp, hsp, eeg, *, bad_coils=()): # passed in directly) if len(elp) not in (6, 7, 8): raise ValueError(f"ELP should contain 6 ~ 8 points; got shape {elp.shape}.") - if isinstance(mrk, (str, Path, PathLike)): + if isinstance(mrk, str | Path | PathLike): mrk = read_mrk(mrk) if len(bad_coils) > 0: mrk = np.delete(mrk, bad_coils, 0) diff --git a/mne/io/kit/kit.py b/mne/io/kit/kit.py index 4bad4e19e21..b873bb269b4 100644 --- a/mne/io/kit/kit.py +++ b/mne/io/kit/kit.py @@ -3,10 +3,7 @@ RawKIT class is adapted from Denis Engemann et al.'s mne_bti2fiff.py. """ -# Authors: Teon Brooks -# Joan Massich -# Christian Brodbeck -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -53,7 +50,7 @@ def _call_digitization(info, mrk, elp, hsp, kit_info, *, bad_coils=()): # prepare mrk if isinstance(mrk, list): mrk = [ - read_mrk(marker) if isinstance(marker, (str, Path, PathLike)) else marker + read_mrk(marker) if isinstance(marker, str | Path | PathLike) else marker for marker in mrk ] mrk = np.mean(mrk, axis=0) @@ -395,7 +392,7 @@ def __init__( standardize_names=None, verbose=None, ): - if isinstance(events, (str, PathLike, Path)): + if isinstance(events, str | PathLike | Path): events = read_events(events) input_fname = str( diff --git a/mne/io/kit/tests/__init__.py b/mne/io/kit/tests/__init__.py index 7ed6f786293..25a040855f1 100644 --- a/mne/io/kit/tests/__init__.py +++ b/mne/io/kit/tests/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from pathlib import Path data_dir = Path(__file__).parent / "data" diff --git a/mne/io/kit/tests/test_coreg.py b/mne/io/kit/tests/test_coreg.py index a1d508afbdd..2ffa7a1178a 100644 --- a/mne/io/kit/tests/test_coreg.py +++ b/mne/io/kit/tests/test_coreg.py @@ -1,5 +1,4 @@ -# Authors: Christian Brodbeck -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/kit/tests/test_kit.py b/mne/io/kit/tests/test_kit.py index 6e325398414..6bd8cb83e84 100644 --- a/mne/io/kit/tests/test_kit.py +++ b/mne/io/kit/tests/test_kit.py @@ -1,5 +1,4 @@ -# Author: Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nedf/__init__.py b/mne/io/nedf/__init__.py index abf86990d77..fe67ee79fb5 100644 --- a/mne/io/nedf/__init__.py +++ b/mne/io/nedf/__init__.py @@ -1,7 +1,6 @@ """NEDF file import module.""" -# Author: Tristan Stenner -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nedf/nedf.py b/mne/io/nedf/nedf.py index df6030f31c1..b44d18b81f0 100644 --- a/mne/io/nedf/nedf.py +++ b/mne/io/nedf/nedf.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Import NeuroElectrics DataFormat (NEDF) files.""" from copy import deepcopy diff --git a/mne/io/nedf/tests/__init__.py b/mne/io/nedf/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/nedf/tests/__init__.py +++ b/mne/io/nedf/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nedf/tests/test_nedf.py b/mne/io/nedf/tests/test_nedf.py index f06e1376e59..1382417cd10 100644 --- a/mne/io/nedf/tests/test_nedf.py +++ b/mne/io/nedf/tests/test_nedf.py @@ -1,6 +1,6 @@ """Test reading of NEDF format.""" -# Author: Tristan Stenner -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/neuralynx/__init__.py b/mne/io/neuralynx/__init__.py index 70a2b0f38d7..f302a22a893 100644 --- a/mne/io/neuralynx/__init__.py +++ b/mne/io/neuralynx/__init__.py @@ -1,3 +1,5 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from .neuralynx import read_raw_neuralynx diff --git a/mne/io/neuralynx/neuralynx.py b/mne/io/neuralynx/neuralynx.py index bebe0a352ca..8c9a2faf5c4 100644 --- a/mne/io/neuralynx/neuralynx.py +++ b/mne/io/neuralynx/neuralynx.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import datetime import glob import inspect diff --git a/mne/io/neuralynx/tests/__init__.py b/mne/io/neuralynx/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/neuralynx/tests/__init__.py +++ b/mne/io/neuralynx/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/neuralynx/tests/test_neuralynx.py b/mne/io/neuralynx/tests/test_neuralynx.py index c1bf9e04d91..ea5cdbccdfb 100644 --- a/mne/io/neuralynx/tests/test_neuralynx.py +++ b/mne/io/neuralynx/tests/test_neuralynx.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os from ast import literal_eval from datetime import datetime, timezone diff --git a/mne/io/nicolet/__init__.py b/mne/io/nicolet/__init__.py index 2ada6089209..6e7ad05b63d 100644 --- a/mne/io/nicolet/__init__.py +++ b/mne/io/nicolet/__init__.py @@ -1,7 +1,6 @@ """Nicolet module for conversion to FIF.""" -# Author: Jaakko Leppakangas -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nicolet/nicolet.py b/mne/io/nicolet/nicolet.py index 3ebefd53f48..f55cd77061d 100644 --- a/mne/io/nicolet/nicolet.py +++ b/mne/io/nicolet/nicolet.py @@ -1,5 +1,4 @@ -# Author: Jaakko Leppakangas -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nicolet/tests/__init__.py b/mne/io/nicolet/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/nicolet/tests/__init__.py +++ b/mne/io/nicolet/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nicolet/tests/test_nicolet.py b/mne/io/nicolet/tests/test_nicolet.py index 6fe732a6dde..e517124417a 100644 --- a/mne/io/nicolet/tests/test_nicolet.py +++ b/mne/io/nicolet/tests/test_nicolet.py @@ -1,5 +1,4 @@ -# Author: Jaakko Leppakangas -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nihon/__init__.py b/mne/io/nihon/__init__.py index 6cdfb64a17e..ae63480559e 100644 --- a/mne/io/nihon/__init__.py +++ b/mne/io/nihon/__init__.py @@ -1,7 +1,6 @@ """Nihon Kohden module for conversion to FIF.""" -# Author: Fede Raimondo -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nihon/nihon.py b/mne/io/nihon/nihon.py index 4e54cb04363..da80e2af390 100644 --- a/mne/io/nihon/nihon.py +++ b/mne/io/nihon/nihon.py @@ -1,5 +1,4 @@ -# Authors: Federico Raimondo -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nihon/tests/test_nihon.py b/mne/io/nihon/tests/test_nihon.py index 4c84dd063a9..071adab3693 100644 --- a/mne/io/nihon/tests/test_nihon.py +++ b/mne/io/nihon/tests/test_nihon.py @@ -1,5 +1,4 @@ -# Authors: Federico Raimondo -# simplified BSD-3 license +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nirx/__init__.py b/mne/io/nirx/__init__.py index af604f32789..5946836cda1 100644 --- a/mne/io/nirx/__init__.py +++ b/mne/io/nirx/__init__.py @@ -1,7 +1,6 @@ """fNIRS module for conversion to FIF.""" -# Author: Robert Luke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nirx/_localized_abbr.py b/mne/io/nirx/_localized_abbr.py index 77622c496e7..37e05016717 100644 --- a/mne/io/nirx/_localized_abbr.py +++ b/mne/io/nirx/_localized_abbr.py @@ -1,6 +1,6 @@ """Localizations for meas_date extraction.""" -# Authors: Eric Larson -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nirx/nirx.py b/mne/io/nirx/nirx.py index 95fa061ea4e..53a812e7a21 100644 --- a/mne/io/nirx/nirx.py +++ b/mne/io/nirx/nirx.py @@ -1,5 +1,4 @@ -# Authors: Robert Luke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nirx/tests/__init__.py b/mne/io/nirx/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/nirx/tests/__init__.py +++ b/mne/io/nirx/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nirx/tests/test_nirx.py b/mne/io/nirx/tests/test_nirx.py index 4bae9c5afa1..16d81c55e78 100644 --- a/mne/io/nirx/tests/test_nirx.py +++ b/mne/io/nirx/tests/test_nirx.py @@ -1,6 +1,4 @@ -# Authors: Robert Luke -# Eric Larson -# simplified BSD-3 license +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nsx/__init__.py b/mne/io/nsx/__init__.py index 90e626130d2..cb2500e2235 100644 --- a/mne/io/nsx/__init__.py +++ b/mne/io/nsx/__init__.py @@ -1,7 +1,6 @@ """NSx module for reading Blackrock Microsystem files.""" -# Author: Proloy Das -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/nsx/nsx.py b/mne/io/nsx/nsx.py index c20e19b29ed..1fc8a6968ea 100644 --- a/mne/io/nsx/nsx.py +++ b/mne/io/nsx/nsx.py @@ -1,7 +1,7 @@ -# Author: Proloy Das -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os from datetime import datetime, timezone @@ -11,7 +11,7 @@ from ..._fiff.meas_info import _empty_info from ..._fiff.utils import _file_size, _read_segments_file from ...annotations import Annotations -from ...utils import fill_doc, logger, warn +from ...utils import _check_fname, fill_doc, logger, warn from ..base import BaseRaw, _get_scaling CH_TYPE_MAPPING = { @@ -126,10 +126,13 @@ def read_raw_nsx( STIM channels by default. Use func:`mne.find_events` to parse events encoded in such analog stim channels. """ - input_fname = os.path.abspath(input_fname) - ext = os.path.splitext(input_fname)[1][1:].lower() - if ext[:2] != "ns": - raise NotImplementedError(f"Only NSx files are supported, got {ext}.") + input_fname = _check_fname( + input_fname, overwrite="read", must_exist=True, name="input_fname" + ) + if not input_fname.suffix.lower().startswith(".ns"): + raise NotImplementedError( + f"Only NSx files are supported, got {input_fname.suffix}." + ) return RawNSX( input_fname, stim_channel, eog, misc, preload=preload, verbose=verbose ) diff --git a/mne/io/nsx/tests/test_nsx.py b/mne/io/nsx/tests/test_nsx.py index 399cfca5bd9..fa1f708adc5 100644 --- a/mne/io/nsx/tests/test_nsx.py +++ b/mne/io/nsx/tests/test_nsx.py @@ -1,7 +1,7 @@ -# Author: Proloy Das -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os import numpy as np diff --git a/mne/io/persyst/__init__.py b/mne/io/persyst/__init__.py index c3f1e35682b..aac04211ff8 100644 --- a/mne/io/persyst/__init__.py +++ b/mne/io/persyst/__init__.py @@ -1,7 +1,6 @@ """Persyst module for conversion to FIF.""" -# Author: Adam Li -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/persyst/persyst.py b/mne/io/persyst/persyst.py index 535123d896d..a6cf80cd0b2 100644 --- a/mne/io/persyst/persyst.py +++ b/mne/io/persyst/persyst.py @@ -1,7 +1,7 @@ -# Authors: Adam Li -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os import os.path as op from collections import OrderedDict diff --git a/mne/io/persyst/tests/__init__.py b/mne/io/persyst/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/persyst/tests/__init__.py +++ b/mne/io/persyst/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/persyst/tests/test_persyst.py b/mne/io/persyst/tests/test_persyst.py index 11cf042a6d7..986a37b9dbb 100644 --- a/mne/io/persyst/tests/test_persyst.py +++ b/mne/io/persyst/tests/test_persyst.py @@ -1,5 +1,4 @@ -# Authors: Adam Li -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/pick.py b/mne/io/pick.py index 4ae1d25b3c5..e78cfc85442 100644 --- a/mne/io/pick.py +++ b/mne/io/pick.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/snirf/__init__.py b/mne/io/snirf/__init__.py index 0ffe39de808..a50ff500a41 100644 --- a/mne/io/snirf/__init__.py +++ b/mne/io/snirf/__init__.py @@ -1,7 +1,6 @@ """SNIRF module for conversion to FIF.""" -# Author: Robert Luke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/snirf/_snirf.py b/mne/io/snirf/_snirf.py index 0a159232c53..3a3edca142b 100644 --- a/mne/io/snirf/_snirf.py +++ b/mne/io/snirf/_snirf.py @@ -1,5 +1,4 @@ -# Authors: Robert Luke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/snirf/tests/__init__.py b/mne/io/snirf/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/snirf/tests/__init__.py +++ b/mne/io/snirf/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/snirf/tests/test_snirf.py b/mne/io/snirf/tests/test_snirf.py index d1e90c2318e..1f69d9b9df7 100644 --- a/mne/io/snirf/tests/test_snirf.py +++ b/mne/io/snirf/tests/test_snirf.py @@ -1,5 +1,4 @@ -# Authors: Robert Luke -# simplified BSD-3 license +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/tests/__init__.py b/mne/io/tests/__init__.py index f5523f5d662..c45203dcc03 100644 --- a/mne/io/tests/__init__.py +++ b/mne/io/tests/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os.path as op data_dir = op.join(op.dirname(__file__), "data") diff --git a/mne/io/tests/data/__init__.py b/mne/io/tests/data/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/io/tests/data/__init__.py +++ b/mne/io/tests/data/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/tests/test_apply_function.py b/mne/io/tests/test_apply_function.py index f250e9489b9..a6745d5e31d 100644 --- a/mne/io/tests/test_apply_function.py +++ b/mne/io/tests/test_apply_function.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/io/tests/test_raw.py b/mne/io/tests/test_raw.py index f68a86317dc..f94107c6048 100644 --- a/mne/io/tests/test_raw.py +++ b/mne/io/tests/test_raw.py @@ -1,7 +1,6 @@ """Generic tests that all raw classes should run.""" -# Authors: MNE Developers -# Stefan Appelhoff -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -318,7 +317,7 @@ def _test_raw_reader( full_data = raw._data assert raw.__class__.__name__ in repr(raw) # to test repr assert raw.info.__class__.__name__ in repr(raw.info) - assert isinstance(raw.info["dig"], (type(None), list)) + assert isinstance(raw.info["dig"], type(None) | list) data_max = np.nanmax(full_data) data_min = np.nanmin(full_data) # these limits could be relaxed if we actually find data with @@ -345,8 +344,11 @@ def _test_raw_reader( # Test saving and reading out_fname = op.join(tempdir, "test_raw.fif") raw = concatenate_raws([raw]) - raw.save(out_fname, tmax=raw.times[-1], overwrite=True, buffer_size_sec=1) - + filenames = raw.save( + out_fname, tmax=raw.times[-1], overwrite=True, buffer_size_sec=1 + ) + for filename in filenames: + assert filename.is_file() # Test saving with not correct extension out_fname_h5 = op.join(tempdir, "test_raw.h5") with pytest.raises(OSError, match="raw must end with .fif or .fif.gz"): diff --git a/mne/io/tests/test_read_raw.py b/mne/io/tests/test_read_raw.py index eccd074d9a0..f74a715d9e7 100644 --- a/mne/io/tests/test_read_raw.py +++ b/mne/io/tests/test_read_raw.py @@ -1,7 +1,6 @@ """Test generic read_raw function.""" -# Authors: Clemens Brunner -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -12,7 +11,7 @@ from mne.datasets import testing from mne.io import read_raw -from mne.io._read_raw import _get_readers, split_name_ext +from mne.io._read_raw import _get_readers, _get_supported, split_name_ext base = Path(__file__).parents[1] test_base = Path(testing.data_path(download=False)) @@ -100,3 +99,60 @@ def test_read_raw_multiple_dots(tmp_path): dst = tmp_path / "test.this.file.edf" copyfile(src, dst) read_raw(dst) + + +reader_excluded_from_read_raw = { + "read_raw_bti", + "read_raw_hitachi", + "read_raw_neuralynx", +} + + +def test_all_reader_documented(): + """Test that all the readers in the documentation are accepted by read_raw.""" + readers = _get_supported() + # flatten the dictionaries and retrieve the function names + functions = [foo.__name__ for value in readers.values() for foo in value.values()] + # read documentation .rst source file + doc_folder = Path(__file__).parents[3] / "doc" + if not doc_folder.exists(): + pytest.skip("Documentation folder not found.") + doc_file = doc_folder / "api" / "reading_raw_data.rst" + doc = doc_file.read_text("utf-8") + reader_lines = [ + line.strip() for line in doc.split("\n") if line.strip().startswith("read_raw_") + ] + reader_lines = [ + elt for elt in reader_lines if elt not in reader_excluded_from_read_raw + ] + missing_from_read_raw = set(reader_lines) - set(functions) + missing_from_doc = set(functions) - set(reader_lines) + if len(missing_from_doc) != 0 or len(missing_from_read_raw) != 0: + raise AssertionError( + "Functions missing from documentation:\n\t" + + "\n\t".join(missing_from_doc) + + "\n\nFunctions missing from read_raw:\n\t" + + "\n\t".join(missing_from_read_raw) + ) + if sorted(reader_lines) != list(reader_lines): + raise AssertionError( + "Functions in documentation are not sorted. Expected order:\n\t" + + "\n\t".join(sorted(reader_lines)) + ) + + +def test_all_reader_documented_in_docstring(): + """Test that all the readers are documented in read_raw docstring.""" + readers = _get_supported() + # flatten the dictionaries and retrieve the function names + functions = [foo.__name__ for value in readers.values() for foo in value.values()] + doc = read_raw.__doc__.split("Parameters")[0] + documented = [elt.strip().split("`")[0] for elt in doc.split("mne.io.")[1:]] + missing_from_docstring = set(functions) - set(documented) + if len(missing_from_docstring) != 0: + raise AssertionError( + "Functions missing from docstring:\n\t" + + "\n\t".join(missing_from_docstring) + ) + if sorted(documented) != documented: + raise AssertionError("Functions in docstring are not sorted.") diff --git a/mne/label.py b/mne/label.py index 9ac1882ae19..7c15bd026e9 100644 --- a/mne/label.py +++ b/mne/label.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# Denis Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -760,7 +757,7 @@ def split(self, parts=2, subject=None, subjects_dir=None, freesurfer=False): """ if isinstance(parts, str) and parts == "contiguous": return _split_label_contig(self, subject, subjects_dir) - elif isinstance(parts, (tuple, int)): + elif isinstance(parts, tuple | int): return split_label(self, parts, subject, subjects_dir, freesurfer) else: raise ValueError( diff --git a/mne/minimum_norm/__init__.py b/mne/minimum_norm/__init__.py index 792c154170f..975eb5ed3e5 100644 --- a/mne/minimum_norm/__init__.py +++ b/mne/minimum_norm/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Linear inverse solvers based on L2 Minimum Norm Estimates (MNE).""" import lazy_loader as lazy diff --git a/mne/minimum_norm/_eloreta.py b/mne/minimum_norm/_eloreta.py index 059480e4062..905bf64ff7e 100644 --- a/mne/minimum_norm/_eloreta.py +++ b/mne/minimum_norm/_eloreta.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/minimum_norm/inverse.py b/mne/minimum_norm/inverse.py index 0e6c3deacb0..cc0464ba80f 100644 --- a/mne/minimum_norm/inverse.py +++ b/mne/minimum_norm/inverse.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1484,7 +1481,7 @@ def _apply_inverse_tfr_epochs_gen( ) this_inverse_operator = ( inverse_operator[freq_idx] - if isinstance(inverse_operator, (list, tuple)) + if isinstance(inverse_operator, list | tuple) else inverse_operator ) stcs = _apply_inverse_epochs_gen( @@ -1562,7 +1559,7 @@ def apply_inverse_tfr_epochs( """ # noqa E501 _check_tfr_complex(epochs_tfr) if ( - isinstance(inverse_operator, (list, tuple)) + isinstance(inverse_operator, list | tuple) and len(inverse_operator) != epochs_tfr.freqs.size ): raise ValueError( diff --git a/mne/minimum_norm/resolution_matrix.py b/mne/minimum_norm/resolution_matrix.py index 4ba90b9c881..10a7b160371 100644 --- a/mne/minimum_norm/resolution_matrix.py +++ b/mne/minimum_norm/resolution_matrix.py @@ -1,9 +1,9 @@ """Compute resolution matrix for linear estimators.""" -# Authors: olaf.hauk@mrc-cbu.cam.ac.uk -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from copy import deepcopy import numpy as np diff --git a/mne/minimum_norm/spatial_resolution.py b/mne/minimum_norm/spatial_resolution.py index 86de5a5bcf2..26efc62be2a 100644 --- a/mne/minimum_norm/spatial_resolution.py +++ b/mne/minimum_norm/spatial_resolution.py @@ -1,7 +1,7 @@ -# Authors: Olaf Hauk -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Compute resolution metrics from resolution matrix. Resolution metrics: localisation error, spatial extent, relative amplitude. diff --git a/mne/minimum_norm/tests/__init__.py b/mne/minimum_norm/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/minimum_norm/tests/__init__.py +++ b/mne/minimum_norm/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/minimum_norm/tests/test_inverse.py b/mne/minimum_norm/tests/test_inverse.py index 4f09413ec0a..3d80e35c12f 100644 --- a/mne/minimum_norm/tests/test_inverse.py +++ b/mne/minimum_norm/tests/test_inverse.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import copy import re from pathlib import Path diff --git a/mne/minimum_norm/tests/test_resolution_matrix.py b/mne/minimum_norm/tests/test_resolution_matrix.py index 2fa6a39e4cf..73c6977f61d 100644 --- a/mne/minimum_norm/tests/test_resolution_matrix.py +++ b/mne/minimum_norm/tests/test_resolution_matrix.py @@ -1,7 +1,4 @@ -# Author: Olaf Hauk -# Alexandre Gramfort -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/minimum_norm/tests/test_resolution_metrics.py b/mne/minimum_norm/tests/test_resolution_metrics.py index 938dc4759dc..81d4de5631e 100644 --- a/mne/minimum_norm/tests/test_resolution_metrics.py +++ b/mne/minimum_norm/tests/test_resolution_metrics.py @@ -1,8 +1,7 @@ -# Authors: Olaf Hauk -# Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """ Test the following properties for resolution metrics. diff --git a/mne/minimum_norm/tests/test_snr.py b/mne/minimum_norm/tests/test_snr.py index befeb0c6e89..0e7a5af4d63 100644 --- a/mne/minimum_norm/tests/test_snr.py +++ b/mne/minimum_norm/tests/test_snr.py @@ -1,6 +1,4 @@ -# Authors: Eric Larson -# Matti Hämäläinen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/minimum_norm/tests/test_time_frequency.py b/mne/minimum_norm/tests/test_time_frequency.py index 5920b8ab4a3..dabb18433ff 100644 --- a/mne/minimum_norm/tests/test_time_frequency.py +++ b/mne/minimum_norm/tests/test_time_frequency.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np import pytest from numpy.testing import assert_allclose diff --git a/mne/minimum_norm/time_frequency.py b/mne/minimum_norm/time_frequency.py index 16b76875941..efd6ccd990a 100644 --- a/mne/minimum_norm/time_frequency.py +++ b/mne/minimum_norm/time_frequency.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -137,7 +135,7 @@ def _prepare_source_params( # vertno: [lh_verts, rh_verts] k_idxs = None - if not isinstance(label, (Label, BiHemiLabel)): + if not isinstance(label, Label | BiHemiLabel): whole_K, whole_noise_norm, whole_vertno, _ = _assemble_kernel( inv, None, method, pick_ori, use_cps=use_cps ) @@ -148,7 +146,7 @@ def _prepare_source_params( else: assert not label K, noise_norm, vertno = whole_K, whole_noise_norm, whole_vertno - elif isinstance(label, (Label, BiHemiLabel)): + elif isinstance(label, Label | BiHemiLabel): K, noise_norm, vertno, _ = _assemble_kernel( inv, label, method, pick_ori, use_cps=use_cps ) @@ -502,7 +500,7 @@ def _source_induced_power( types=(Label, BiHemiLabel, list, tuple, None), type_name=("Label or BiHemiLabel", "list of labels", "None"), ) - if isinstance(label, (list, tuple)): + if isinstance(label, list | tuple): for item in label: _validate_type( item, @@ -562,7 +560,7 @@ def _source_induced_power( power = sum(o[0] for o in out) # power shape: (n_verts, n_freqs, n_samps) power /= len(epochs_data) # average power over epochs - if isinstance(label, (Label, BiHemiLabel)): + if isinstance(label, Label | BiHemiLabel): logger.info( f"Outputting power for {len(power)} vertices in label {label.name}." ) diff --git a/mne/misc.py b/mne/misc.py index 3b362643214..bea711f927d 100644 --- a/mne/misc.py +++ b/mne/misc.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Scott Burns -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/morph.py b/mne/morph.py index 37af757b5fe..9c475bff1e9 100644 --- a/mne/morph.py +++ b/mne/morph.py @@ -1,7 +1,4 @@ -# Author(s): Tommy Clausner -# Alexandre Gramfort -# Eric Larson - +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -912,7 +909,7 @@ def _morphed_stc_as_volume(morph, stc, mri_resolution, mri_space, output): NiftiImage, NiftiHeader = _triage_output(output) # if MRI resolution is set manually as a single value, convert to tuple - if isinstance(mri_resolution, (int, float)): + if isinstance(mri_resolution, int | float): # use iso voxel size new_zooms = (float(mri_resolution),) * 3 elif isinstance(mri_resolution, tuple): @@ -1046,9 +1043,7 @@ def _interpolate_data(stc, morph, mri_resolution, mri_space, output): voxel_size_defined = False - if isinstance(mri_resolution, (int, float)) and not isinstance( - mri_resolution, bool - ): + if isinstance(mri_resolution, int | float) and not isinstance(mri_resolution, bool): # use iso voxel size mri_resolution = (float(mri_resolution),) * 3 @@ -1165,7 +1160,13 @@ def _compute_morph_sdr(mri_from, mri_to, niter_affine, niter_sdr, zooms): ) = _compute_volume_registration( mri_from, mri_to, zooms=zooms, niter=niter, pipeline=pipeline ) - pre_affine = AffineMap(pre_affine, to_shape, to_affine, from_shape, from_affine) + pre_affine = AffineMap( + pre_affine, + domain_grid_shape=to_shape, + domain_grid2world=to_affine, + codomain_grid_shape=from_shape, + codomain_grid2world=from_affine, + ) return to_shape, zooms, to_affine, pre_affine, sdr_morph diff --git a/mne/morph_map.py b/mne/morph_map.py index 54bca2bca02..d2fccd3c075 100644 --- a/mne/morph_map.py +++ b/mne/morph_map.py @@ -1,8 +1,4 @@ -# Authors: Matti Hämäläinen -# Alexandre Gramfort -# Matti Hämäläinen -# Denis A. Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/parallel.py b/mne/parallel.py index b20dd317b27..4feb3458227 100644 --- a/mne/parallel.py +++ b/mne/parallel.py @@ -1,7 +1,6 @@ """Parallel util function.""" -# Author: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/__init__.py b/mne/preprocessing/__init__.py index b409cb8e5d6..dac4012b6ef 100644 --- a/mne/preprocessing/__init__.py +++ b/mne/preprocessing/__init__.py @@ -1,11 +1,9 @@ """Preprocessing with artifact detection, SSP, and ICA.""" -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Martin Luessi -# Denis Engemann -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import lazy_loader as lazy (__getattr__, __dir__, __all__) = lazy.attach_stub(__name__, __file__) diff --git a/mne/preprocessing/_annotate_amplitude.py b/mne/preprocessing/_annotate_amplitude.py index 2f61b19c3db..943c20c0ba2 100644 --- a/mne/preprocessing/_annotate_amplitude.py +++ b/mne/preprocessing/_annotate_amplitude.py @@ -1,5 +1,4 @@ -# Author: Mathieu Scheltienne -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/_annotate_nan.py b/mne/preprocessing/_annotate_nan.py index 0d57ae7f807..59c2680edb7 100644 --- a/mne/preprocessing/_annotate_nan.py +++ b/mne/preprocessing/_annotate_nan.py @@ -1,5 +1,4 @@ -# Author: David Julien -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/_csd.py b/mne/preprocessing/_csd.py index 632a3421cf2..35a32e90245 100644 --- a/mne/preprocessing/_csd.py +++ b/mne/preprocessing/_csd.py @@ -1,6 +1,4 @@ -# Authors: Denis A. Engeman -# Alex Rockhill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/_css.py b/mne/preprocessing/_css.py index ebd9a77eef7..70ba61341c5 100644 --- a/mne/preprocessing/_css.py +++ b/mne/preprocessing/_css.py @@ -1,4 +1,4 @@ -# Author: John Samuelsson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/_fine_cal.py b/mne/preprocessing/_fine_cal.py index c4355ee4ead..a1b9f32c098 100644 --- a/mne/preprocessing/_fine_cal.py +++ b/mne/preprocessing/_fine_cal.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson - +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/_lof.py b/mne/preprocessing/_lof.py index 6d777599a8a..e55d7f50192 100644 --- a/mne/preprocessing/_lof.py +++ b/mne/preprocessing/_lof.py @@ -1,7 +1,6 @@ """Bad channel detection using Local Outlier Factor (LOF).""" -# Authors: Velu Prabhakar Kumaravel -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/_peak_finder.py b/mne/preprocessing/_peak_finder.py index dd83c7a4eab..3c1af44ac57 100644 --- a/mne/preprocessing/_peak_finder.py +++ b/mne/preprocessing/_peak_finder.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np from ..utils import _pl, logger, verbose diff --git a/mne/preprocessing/_regress.py b/mne/preprocessing/_regress.py index 260796a221d..6a87649f138 100644 --- a/mne/preprocessing/_regress.py +++ b/mne/preprocessing/_regress.py @@ -1,6 +1,4 @@ -# Authors: Eric Larson -# Marijn van Vliet -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/artifact_detection.py b/mne/preprocessing/artifact_detection.py index a519f339ab9..6e269e5dac5 100644 --- a/mne/preprocessing/artifact_detection.py +++ b/mne/preprocessing/artifact_detection.py @@ -1,5 +1,4 @@ -# Authors: Adonay Nunes -# Luke Bloy +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -322,9 +321,9 @@ def compute_average_dev_head_t(raw, pos, *, verbose=None): Support for multiple raw instances and position arrays was added. """ # Get weighted head pos trans and rot - if not isinstance(raw, (list, tuple)): + if not isinstance(raw, list | tuple): raw = [raw] - if not isinstance(pos, (list, tuple)): + if not isinstance(pos, list | tuple): pos = [pos] if len(pos) != len(raw): raise ValueError( diff --git a/mne/preprocessing/bads.py b/mne/preprocessing/bads.py index 39af59d8800..8fdf4219cf5 100644 --- a/mne/preprocessing/bads.py +++ b/mne/preprocessing/bads.py @@ -1,4 +1,4 @@ -# Authors: Denis Engemann +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/ctps_.py b/mne/preprocessing/ctps_.py index 4b19f69b70e..7a53243999a 100644 --- a/mne/preprocessing/ctps_.py +++ b/mne/preprocessing/ctps_.py @@ -1,8 +1,7 @@ -# Authors: Juergen Dammers -# Denis Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import math import numpy as np diff --git a/mne/preprocessing/ecg.py b/mne/preprocessing/ecg.py index 8a55a4efda8..1c808867312 100644 --- a/mne/preprocessing/ecg.py +++ b/mne/preprocessing/ecg.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/eog.py b/mne/preprocessing/eog.py index aa7c15ad33a..20e5481f89c 100644 --- a/mne/preprocessing/eog.py +++ b/mne/preprocessing/eog.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/eyetracking/__init__.py b/mne/preprocessing/eyetracking/__init__.py index efab0fb079d..fb0792a696b 100644 --- a/mne/preprocessing/eyetracking/__init__.py +++ b/mne/preprocessing/eyetracking/__init__.py @@ -1,7 +1,6 @@ """Eye tracking specific preprocessing functions.""" -# Authors: Dominik Welke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/eyetracking/_pupillometry.py b/mne/preprocessing/eyetracking/_pupillometry.py index cb494be99c3..cfc630b6441 100644 --- a/mne/preprocessing/eyetracking/_pupillometry.py +++ b/mne/preprocessing/eyetracking/_pupillometry.py @@ -1,5 +1,4 @@ -# Authors: Scott Huberty -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/eyetracking/calibration.py b/mne/preprocessing/eyetracking/calibration.py index 84b53ee3006..867119557a8 100644 --- a/mne/preprocessing/eyetracking/calibration.py +++ b/mne/preprocessing/eyetracking/calibration.py @@ -1,8 +1,6 @@ """Eyetracking Calibration(s) class constructor.""" -# Authors: Scott Huberty -# Eric Larson -# Adapted from: https://github.com/pyeparse/pyeparse +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/eyetracking/eyetracking.py b/mne/preprocessing/eyetracking/eyetracking.py index 0e66fdc0eb5..5bf82068b52 100644 --- a/mne/preprocessing/eyetracking/eyetracking.py +++ b/mne/preprocessing/eyetracking/eyetracking.py @@ -1,6 +1,4 @@ -# Authors: Dominik Welke -# Scott Huberty -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/eyetracking/tests/__init__.py b/mne/preprocessing/eyetracking/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/preprocessing/eyetracking/tests/__init__.py +++ b/mne/preprocessing/eyetracking/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/eyetracking/tests/test_calibration.py b/mne/preprocessing/eyetracking/tests/test_calibration.py index ac50024310f..68ce513cc1f 100644 --- a/mne/preprocessing/eyetracking/tests/test_calibration.py +++ b/mne/preprocessing/eyetracking/tests/test_calibration.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np import pytest diff --git a/mne/preprocessing/eyetracking/tests/test_eyetracking.py b/mne/preprocessing/eyetracking/tests/test_eyetracking.py index 8bea006d9fd..a4a0404fcb1 100644 --- a/mne/preprocessing/eyetracking/tests/test_eyetracking.py +++ b/mne/preprocessing/eyetracking/tests/test_eyetracking.py @@ -1,3 +1,7 @@ +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + import numpy as np import pytest from numpy.testing import assert_allclose diff --git a/mne/preprocessing/eyetracking/tests/test_pupillometry.py b/mne/preprocessing/eyetracking/tests/test_pupillometry.py index f82d0a6a360..19077e44d81 100644 --- a/mne/preprocessing/eyetracking/tests/test_pupillometry.py +++ b/mne/preprocessing/eyetracking/tests/test_pupillometry.py @@ -1,4 +1,4 @@ -# Authors: Scott Huberty +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/eyetracking/utils.py b/mne/preprocessing/eyetracking/utils.py index 89c379c9760..73cf0b4a27b 100644 --- a/mne/preprocessing/eyetracking/utils.py +++ b/mne/preprocessing/eyetracking/utils.py @@ -1,3 +1,7 @@ +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + import numpy as np from ...utils import _validate_type diff --git a/mne/preprocessing/hfc.py b/mne/preprocessing/hfc.py index ab396ca0c44..f8a65510a9a 100644 --- a/mne/preprocessing/hfc.py +++ b/mne/preprocessing/hfc.py @@ -1,5 +1,4 @@ -# Authors: George O'Neill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -17,7 +16,7 @@ def compute_proj_hfc( ): """Generate projectors to perform homogeneous/harmonic correction to data. - Remove evironmental fields from magentometer data by assuming it is + Remove environmental fields from magnetometer data by assuming it is explained as a homogeneous :footcite:`TierneyEtAl2021` or harmonic field :footcite:`TierneyEtAl2022`. Useful for arrays of OPMs. @@ -27,7 +26,7 @@ def compute_proj_hfc( order : int The order of the spherical harmonic basis set to use. Set to 1 to use only the homogeneous field component (default), 2 to add gradients, 3 - to add quadrature terms etc. + to add quadrature terms, etc. picks : str | array_like | slice | None Channels to include. Default of ``'meg'`` (same as None) will select all non-reference MEG channels. Use ``('meg', 'ref_meg')`` to include diff --git a/mne/preprocessing/ica.py b/mne/preprocessing/ica.py index bae94b0f29a..eb4c0a663c4 100644 --- a/mne/preprocessing/ica.py +++ b/mne/preprocessing/ica.py @@ -1,8 +1,5 @@ # -# Authors: Denis A. Engemann -# Alexandre Gramfort -# Juergen Dammers -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -905,7 +902,7 @@ def _fit(self, data, fit_type): n_pca = int(_exp_var_ncomp(use_ev, n_pca)[0]) elif n_pca is None: n_pca = len(use_ev) - assert isinstance(n_pca, (int, np.int_)) + assert isinstance(n_pca, int | np.int_) # If user passed a float, select the PCA components explaining the # given cumulative variance. This information will later be used to @@ -1137,7 +1134,7 @@ def get_explained_variance_ratio(self, inst, *, components=None, ch_type=None): item_name="components", type_name="int, array-like of int, or None", ) - if isinstance(components, (Sequence, np.ndarray)): + if isinstance(components, Sequence | np.ndarray): for item in components: _validate_type( item=item, types="int-like", item_name='Elements of "components"' @@ -1154,7 +1151,7 @@ def get_explained_variance_ratio(self, inst, *, components=None, ch_type=None): elif ch_type is None: ch_types = inst.get_channel_types(unique=True, only_data_chs=True) else: - assert isinstance(ch_type, (Sequence, np.ndarray)) + assert isinstance(ch_type, Sequence | np.ndarray) ch_types = ch_type assert len(ch_types) >= 1 @@ -1196,7 +1193,7 @@ def _get_explained_variance_ratio_one_ch_type(self, *, inst, components, ch_type n_pca_components=0, verbose=False, ) - if isinstance(inst, (BaseEpochs, Evoked)) and inst.baseline is not None: + if isinstance(inst, BaseEpochs | Evoked) and inst.baseline is not None: # Don't warn if data was baseline-corrected. with warnings.catch_warnings(): warnings.filterwarnings( @@ -2223,7 +2220,7 @@ def apply( _check_on_missing(on_baseline, "on_baseline", extras=("reapply",)) reapply_baseline = False - if isinstance(inst, (BaseEpochs, Evoked)): + if isinstance(inst, BaseEpochs | Evoked): if getattr(inst, "baseline", None) is not None: if on_baseline == "reapply": reapply_baseline = True @@ -2828,7 +2825,7 @@ def _ica_explained_variance(ica, inst, normalize=False): # check if ica is ICA and whether inst is Raw or Epochs if not isinstance(ica, ICA): raise TypeError("first argument must be an instance of ICA.") - if not isinstance(inst, (BaseRaw, BaseEpochs, Evoked)): + if not isinstance(inst, BaseRaw | BaseEpochs | Evoked): raise TypeError( "second argument must an instance of either Raw, Epochs or Evoked." ) @@ -2887,7 +2884,7 @@ def _serialize(dict_, outer_sep=";", inner_sep=":"): for subkey, subvalue in value.items(): if isinstance(subvalue, list): if len(subvalue) > 0: - if isinstance(subvalue[0], (int, np.integer)): + if isinstance(subvalue[0], int | np.integer): value[subkey] = [int(i) for i in subvalue] for cls in (np.random.RandomState, Covariance): diff --git a/mne/preprocessing/ieeg/__init__.py b/mne/preprocessing/ieeg/__init__.py index f12ea5ee1ab..36f9ad4b8d8 100644 --- a/mne/preprocessing/ieeg/__init__.py +++ b/mne/preprocessing/ieeg/__init__.py @@ -1,7 +1,6 @@ """Intracranial EEG specific preprocessing functions.""" -# Authors: Alex Rockhill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/ieeg/_projection.py b/mne/preprocessing/ieeg/_projection.py index 779fd279ca9..d71f9e67e4f 100644 --- a/mne/preprocessing/ieeg/_projection.py +++ b/mne/preprocessing/ieeg/_projection.py @@ -1,5 +1,4 @@ -# Authors: Alex Rockhill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/ieeg/_volume.py b/mne/preprocessing/ieeg/_volume.py index 26ed8632400..b4997b2e3f8 100644 --- a/mne/preprocessing/ieeg/_volume.py +++ b/mne/preprocessing/ieeg/_volume.py @@ -1,5 +1,4 @@ -# Authors: Alex Rockhill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -84,7 +83,9 @@ def warp_montage(montage, moving, static, reg_affine, sdr_morph, verbose=None): # now, apply SDR morph if sdr_morph is not None: ch_coords = sdr_morph.transform_points( - ch_coords, sdr_morph.domain_grid2world, sdr_morph.domain_world2grid + ch_coords, + coord2world=sdr_morph.domain_grid2world, + world2coord=sdr_morph.domain_world2grid, ) # back to voxels but now for the static image diff --git a/mne/preprocessing/ieeg/tests/test_projection.py b/mne/preprocessing/ieeg/tests/test_projection.py index feffe863f65..18b851bb78f 100644 --- a/mne/preprocessing/ieeg/tests/test_projection.py +++ b/mne/preprocessing/ieeg/tests/test_projection.py @@ -1,6 +1,6 @@ """Test the ieeg projection functions.""" -# Authors: Alex Rockhill -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/ieeg/tests/test_volume.py b/mne/preprocessing/ieeg/tests/test_volume.py index 066337cee76..efcf2a6554c 100644 --- a/mne/preprocessing/ieeg/tests/test_volume.py +++ b/mne/preprocessing/ieeg/tests/test_volume.py @@ -1,6 +1,6 @@ """Test ieeg volume functions.""" -# Authors: Alex Rockhill -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/infomax_.py b/mne/preprocessing/infomax_.py index 354df38ba8f..8bf86903369 100644 --- a/mne/preprocessing/infomax_.py +++ b/mne/preprocessing/infomax_.py @@ -1,7 +1,4 @@ -# Authors: Lukas Breuer -# Juergen Dammers -# Denis A. Engeman -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/interpolate.py b/mne/preprocessing/interpolate.py index fc9b3c0fdec..e0152bbf2dc 100644 --- a/mne/preprocessing/interpolate.py +++ b/mne/preprocessing/interpolate.py @@ -1,6 +1,6 @@ """Tools for data interpolation.""" -# Authors: Alexandre Gramfort +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/maxwell.py b/mne/preprocessing/maxwell.py index 36a58535b16..afd3c72b5fb 100644 --- a/mne/preprocessing/maxwell.py +++ b/mne/preprocessing/maxwell.py @@ -1,8 +1,4 @@ -# Authors: Mark Wronkiewicz -# Eric Larson -# Jussi Nurminen - - +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -947,7 +943,7 @@ def _check_destination(destination, info, head_frame): raise RuntimeError( "destination can only be set if using the head coordinate frame" ) - if isinstance(destination, (str, Path)): + if isinstance(destination, str | Path): recon_trans = _get_trans(destination, "meg", "head")[0] elif isinstance(destination, Transform): recon_trans = destination diff --git a/mne/preprocessing/nirs/__init__.py b/mne/preprocessing/nirs/__init__.py index 7e003c6dded..6e35b59dd15 100644 --- a/mne/preprocessing/nirs/__init__.py +++ b/mne/preprocessing/nirs/__init__.py @@ -1,9 +1,6 @@ """NIRS specific preprocessing functions.""" -# Authors: Robert Luke -# Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/nirs/_beer_lambert_law.py b/mne/preprocessing/nirs/_beer_lambert_law.py index cb15409a59d..92a2e55b9fb 100644 --- a/mne/preprocessing/nirs/_beer_lambert_law.py +++ b/mne/preprocessing/nirs/_beer_lambert_law.py @@ -1,7 +1,4 @@ -# Authors: Robert Luke -# Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/nirs/_optical_density.py b/mne/preprocessing/nirs/_optical_density.py index c9b9c513960..b28e0090e1a 100644 --- a/mne/preprocessing/nirs/_optical_density.py +++ b/mne/preprocessing/nirs/_optical_density.py @@ -1,7 +1,4 @@ -# Authors: Robert Luke -# Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/nirs/_scalp_coupling_index.py b/mne/preprocessing/nirs/_scalp_coupling_index.py index 89751c6ebdb..5a82664dfd1 100644 --- a/mne/preprocessing/nirs/_scalp_coupling_index.py +++ b/mne/preprocessing/nirs/_scalp_coupling_index.py @@ -1,7 +1,4 @@ -# Authors: Robert Luke -# Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/nirs/_tddr.py b/mne/preprocessing/nirs/_tddr.py index 20c18ea01e8..9f323ae3db9 100644 --- a/mne/preprocessing/nirs/_tddr.py +++ b/mne/preprocessing/nirs/_tddr.py @@ -1,6 +1,4 @@ -# Authors: Robert Luke -# Frank Fishburn -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/nirs/nirs.py b/mne/preprocessing/nirs/nirs.py index 5a0e4b72199..94c7c78468c 100644 --- a/mne/preprocessing/nirs/nirs.py +++ b/mne/preprocessing/nirs/nirs.py @@ -1,7 +1,4 @@ -# Authors: Robert Luke -# Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/nirs/tests/test_beer_lambert_law.py b/mne/preprocessing/nirs/tests/test_beer_lambert_law.py index da5341b17d5..5768ff038ab 100644 --- a/mne/preprocessing/nirs/tests/test_beer_lambert_law.py +++ b/mne/preprocessing/nirs/tests/test_beer_lambert_law.py @@ -1,7 +1,4 @@ -# Authors: Robert Luke -# Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/nirs/tests/test_nirs.py b/mne/preprocessing/nirs/tests/test_nirs.py index 16df22183b8..89fa17c0c8d 100644 --- a/mne/preprocessing/nirs/tests/test_nirs.py +++ b/mne/preprocessing/nirs/tests/test_nirs.py @@ -1,7 +1,4 @@ -# Authors: Robert Luke -# Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/nirs/tests/test_optical_density.py b/mne/preprocessing/nirs/tests/test_optical_density.py index 4ac662e0c9a..89b9edce713 100644 --- a/mne/preprocessing/nirs/tests/test_optical_density.py +++ b/mne/preprocessing/nirs/tests/test_optical_density.py @@ -1,7 +1,4 @@ -# Authors: Robert Luke -# Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/nirs/tests/test_scalp_coupling_index.py b/mne/preprocessing/nirs/tests/test_scalp_coupling_index.py index a9cfa4b1549..4a8fd3e71d0 100644 --- a/mne/preprocessing/nirs/tests/test_scalp_coupling_index.py +++ b/mne/preprocessing/nirs/tests/test_scalp_coupling_index.py @@ -1,7 +1,4 @@ -# Authors: Robert Luke -# Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/nirs/tests/test_temporal_derivative_distribution_repair.py b/mne/preprocessing/nirs/tests/test_temporal_derivative_distribution_repair.py index c3bf3492d03..591ddcc866d 100644 --- a/mne/preprocessing/nirs/tests/test_temporal_derivative_distribution_repair.py +++ b/mne/preprocessing/nirs/tests/test_temporal_derivative_distribution_repair.py @@ -1,5 +1,4 @@ -# Authors: Robert Luke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/otp.py b/mne/preprocessing/otp.py index 1d1f15c350b..f5e6277a7b3 100644 --- a/mne/preprocessing/otp.py +++ b/mne/preprocessing/otp.py @@ -1,6 +1,4 @@ -# Authors: Samu Taulu -# Eric Larson - +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/realign.py b/mne/preprocessing/realign.py index 0462c4dcef5..e9101b4b952 100644 --- a/mne/preprocessing/realign.py +++ b/mne/preprocessing/realign.py @@ -1,6 +1,4 @@ -# Authors: Eric Larson -# Qian Chu -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/ssp.py b/mne/preprocessing/ssp.py index c85e6ac8de1..edf68c438dd 100644 --- a/mne/preprocessing/ssp.py +++ b/mne/preprocessing/ssp.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Martin Luessi -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/stim.py b/mne/preprocessing/stim.py index e19b781473f..7db1bab4c85 100644 --- a/mne/preprocessing/stim.py +++ b/mne/preprocessing/stim.py @@ -1,5 +1,4 @@ -# Authors: Daniel Strohmeier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/__init__.py b/mne/preprocessing/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/preprocessing/tests/__init__.py +++ b/mne/preprocessing/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_annotate_amplitude.py b/mne/preprocessing/tests/test_annotate_amplitude.py index ced337f5610..54ab326ec13 100644 --- a/mne/preprocessing/tests/test_annotate_amplitude.py +++ b/mne/preprocessing/tests/test_annotate_amplitude.py @@ -1,5 +1,4 @@ -# Author: Mathieu Scheltienne -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_annotate_nan.py b/mne/preprocessing/tests/test_annotate_nan.py index 5e56a83f979..4818c458911 100644 --- a/mne/preprocessing/tests/test_annotate_nan.py +++ b/mne/preprocessing/tests/test_annotate_nan.py @@ -1,5 +1,4 @@ -# Author: Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_artifact_detection.py b/mne/preprocessing/tests/test_artifact_detection.py index 6aa386d0b05..91ef4743f95 100644 --- a/mne/preprocessing/tests/test_artifact_detection.py +++ b/mne/preprocessing/tests/test_artifact_detection.py @@ -1,5 +1,4 @@ -# Author: Adonay Nunes -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_csd.py b/mne/preprocessing/tests/test_csd.py index cff4b834c76..4db29eb0a68 100644 --- a/mne/preprocessing/tests/test_csd.py +++ b/mne/preprocessing/tests/test_csd.py @@ -2,8 +2,8 @@ For each supported file format, implement a test. """ -# Authors: Alex Rockhill -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_css.py b/mne/preprocessing/tests/test_css.py index f9293b2490e..6e0f794af4a 100644 --- a/mne/preprocessing/tests/test_css.py +++ b/mne/preprocessing/tests/test_css.py @@ -1,4 +1,4 @@ -# Author: John G Samuelsson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_ctps.py b/mne/preprocessing/tests/test_ctps.py index d6fe23d7112..fba61bb8562 100644 --- a/mne/preprocessing/tests/test_ctps.py +++ b/mne/preprocessing/tests/test_ctps.py @@ -1,5 +1,4 @@ -# Authors: Denis A. Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_ecg.py b/mne/preprocessing/tests/test_ecg.py index a6a5ec733a8..4275d9ebf48 100644 --- a/mne/preprocessing/tests/test_ecg.py +++ b/mne/preprocessing/tests/test_ecg.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from pathlib import Path import numpy as np diff --git a/mne/preprocessing/tests/test_eeglab_infomax.py b/mne/preprocessing/tests/test_eeglab_infomax.py index 584406820a7..dfa8c9a748b 100644 --- a/mne/preprocessing/tests/test_eeglab_infomax.py +++ b/mne/preprocessing/tests/test_eeglab_infomax.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from pathlib import Path import numpy as np diff --git a/mne/preprocessing/tests/test_eog.py b/mne/preprocessing/tests/test_eog.py index eb4163fcc13..c191c3e3557 100644 --- a/mne/preprocessing/tests/test_eog.py +++ b/mne/preprocessing/tests/test_eog.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from pathlib import Path from mne import Annotations diff --git a/mne/preprocessing/tests/test_fine_cal.py b/mne/preprocessing/tests/test_fine_cal.py index 2b3d4df0e3f..247998ba31c 100644 --- a/mne/preprocessing/tests/test_fine_cal.py +++ b/mne/preprocessing/tests/test_fine_cal.py @@ -1,8 +1,7 @@ -# Authors: Mark Wronkiewicz -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np import pytest from numpy.testing import assert_allclose diff --git a/mne/preprocessing/tests/test_hfc.py b/mne/preprocessing/tests/test_hfc.py index 66af5304cf9..d188a40356f 100644 --- a/mne/preprocessing/tests/test_hfc.py +++ b/mne/preprocessing/tests/test_hfc.py @@ -1,5 +1,4 @@ -# Authors: George O'Neill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_ica.py b/mne/preprocessing/tests/test_ica.py index 8b0fbf25515..72cfa601e56 100644 --- a/mne/preprocessing/tests/test_ica.py +++ b/mne/preprocessing/tests/test_ica.py @@ -1,6 +1,4 @@ -# Author: Denis Engemann -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_infomax.py b/mne/preprocessing/tests/test_infomax.py index 4c1c81cd552..ec15017e79d 100644 --- a/mne/preprocessing/tests/test_infomax.py +++ b/mne/preprocessing/tests/test_infomax.py @@ -1,5 +1,4 @@ -# Authors: Denis A. Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_interpolate.py b/mne/preprocessing/tests/test_interpolate.py index 8bf4cf0e345..507697e631f 100644 --- a/mne/preprocessing/tests/test_interpolate.py +++ b/mne/preprocessing/tests/test_interpolate.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import itertools from pathlib import Path diff --git a/mne/preprocessing/tests/test_lof.py b/mne/preprocessing/tests/test_lof.py index 858fa0e4432..a9aed80de3f 100644 --- a/mne/preprocessing/tests/test_lof.py +++ b/mne/preprocessing/tests/test_lof.py @@ -1,5 +1,4 @@ -# Authors: Velu Prabhakar Kumaravel -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_maxwell.py b/mne/preprocessing/tests/test_maxwell.py index 97bc3ea0f96..a2a465b20fb 100644 --- a/mne/preprocessing/tests/test_maxwell.py +++ b/mne/preprocessing/tests/test_maxwell.py @@ -1,5 +1,4 @@ -# Author: Mark Wronkiewicz -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_otp.py b/mne/preprocessing/tests/test_otp.py index 9b050ca2dba..01cc0600a70 100644 --- a/mne/preprocessing/tests/test_otp.py +++ b/mne/preprocessing/tests/test_otp.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_peak_finder.py b/mne/preprocessing/tests/test_peak_finder.py index 19aaa0fc385..78cc9e4f412 100644 --- a/mne/preprocessing/tests/test_peak_finder.py +++ b/mne/preprocessing/tests/test_peak_finder.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np import pytest from numpy.testing import assert_array_equal, assert_equal diff --git a/mne/preprocessing/tests/test_realign.py b/mne/preprocessing/tests/test_realign.py index 952c6ac30bb..db198979d17 100644 --- a/mne/preprocessing/tests/test_realign.py +++ b/mne/preprocessing/tests/test_realign.py @@ -1,6 +1,4 @@ -# Authors: Mark Wronkiewicz -# Qian Chu -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_regress.py b/mne/preprocessing/tests/test_regress.py index 48d960e0464..b51a46a12ee 100644 --- a/mne/preprocessing/tests/test_regress.py +++ b/mne/preprocessing/tests/test_regress.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_ssp.py b/mne/preprocessing/tests/test_ssp.py index a6ece5ea2e1..8262fd468c1 100644 --- a/mne/preprocessing/tests/test_ssp.py +++ b/mne/preprocessing/tests/test_ssp.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from pathlib import Path import numpy as np diff --git a/mne/preprocessing/tests/test_stim.py b/mne/preprocessing/tests/test_stim.py index 270b8d93354..7ae1c4418b4 100644 --- a/mne/preprocessing/tests/test_stim.py +++ b/mne/preprocessing/tests/test_stim.py @@ -1,5 +1,4 @@ -# Authors: Daniel Strohmeier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/preprocessing/tests/test_xdawn.py b/mne/preprocessing/tests/test_xdawn.py index 03bc445f2a7..c30fd5dcfd9 100644 --- a/mne/preprocessing/tests/test_xdawn.py +++ b/mne/preprocessing/tests/test_xdawn.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Barachant -# Jean-Remi King -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -19,10 +17,12 @@ pick_types, read_events, ) -from mne.decoding import Vectorizer from mne.fixes import _safe_svd from mne.io import read_raw_fif -from mne.preprocessing.xdawn import Xdawn, _XdawnTransformer + +pytest.importorskip("sklearn") + +from mne.preprocessing.xdawn import Xdawn, _XdawnTransformer # noqa: E402 base_dir = Path(__file__).parents[2] / "io" / "tests" / "data" raw_fname = base_dir / "test_raw.fif" @@ -355,6 +355,8 @@ def test_xdawn_decoding_performance(): from sklearn.pipeline import make_pipeline from sklearn.preprocessing import MinMaxScaler + from mne.decoding import Vectorizer + n_xdawn_comps = 3 expected_accuracy = 0.98 diff --git a/mne/preprocessing/xdawn.py b/mne/preprocessing/xdawn.py index 10c0d358292..933bd973bc6 100644 --- a/mne/preprocessing/xdawn.py +++ b/mne/preprocessing/xdawn.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Barachant -# Asish Panda -# Jean-Remi King -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -572,7 +569,7 @@ def apply(self, inst, event_id=None, include=None, exclude=None): if event_id is None: event_id = self.event_id_ - if not isinstance(inst, (BaseRaw, BaseEpochs, Evoked)): + if not isinstance(inst, BaseRaw | BaseEpochs | Evoked): raise ValueError("Data input must be Raw, Epochs or Evoked type") picks = _pick_data_channels(inst.info) diff --git a/mne/proj.py b/mne/proj.py index 92414cf2dd8..29ae6a591a8 100644 --- a/mne/proj.py +++ b/mne/proj.py @@ -1,5 +1,4 @@ -# Authors: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/rank.py b/mne/rank.py index 30600ad1cff..5971c4657f5 100644 --- a/mne/rank.py +++ b/mne/rank.py @@ -1,6 +1,6 @@ """Some utility functions for rank estimation.""" -# Authors: Alexandre Gramfort -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -484,7 +484,7 @@ def _compute_rank( else: # Use empirical estimation assert rank_type == "estimated" - if isinstance(inst, (BaseRaw, BaseEpochs)): + if isinstance(inst, BaseRaw | BaseEpochs): if isinstance(inst, BaseRaw): data = inst.get_data(picks, reject_by_annotation="omit") else: # isinstance(inst, BaseEpochs): diff --git a/mne/report/__init__.py b/mne/report/__init__.py index 71cde5609f2..e3a0a07d6c8 100644 --- a/mne/report/__init__.py +++ b/mne/report/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Report-generation functions and classes.""" import lazy_loader as lazy diff --git a/mne/report/report.py b/mne/report/report.py index 1d0921c20de..0f72a85b905 100644 --- a/mne/report/report.py +++ b/mne/report/report.py @@ -1,9 +1,6 @@ """Generate self-contained HTML reports from MNE objects.""" -# Authors: Alex Gramfort -# Mainak Jas -# Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -310,7 +307,7 @@ def _check_tags(tags) -> tuple[str]: # Must be iterable, but not a string if isinstance(tags, str): tags = (tags,) - elif isinstance(tags, (Sequence, np.ndarray)): + elif isinstance(tags, Sequence | np.ndarray): tags = tuple(tags) else: raise TypeError( @@ -895,11 +892,11 @@ def _validate_topomap_kwargs(self, topomap_kwargs): def _validate_input(self, items, captions, tag, comments=None): """Validate input.""" - if not isinstance(items, (list, tuple)): + if not isinstance(items, list | tuple): items = [items] - if not isinstance(captions, (list, tuple)): + if not isinstance(captions, list | tuple): captions = [captions] - if not isinstance(comments, (list, tuple)) and comments is not None: + if not isinstance(comments, list | tuple) and comments is not None: comments = [comments] if comments is not None and len(comments) != len(items): raise ValueError( @@ -2770,7 +2767,7 @@ def parse_folder( if pattern is None: pattern = [f"*{ext}" for ext in SUPPORTED_READ_RAW_EXTENSIONS] - elif not isinstance(pattern, (list, tuple)): + elif not isinstance(pattern, list | tuple): pattern = [pattern] # iterate through the possible patterns diff --git a/mne/report/tests/test_report.py b/mne/report/tests/test_report.py index 2ed736aad8b..6e76c54e6c2 100644 --- a/mne/report/tests/test_report.py +++ b/mne/report/tests/test_report.py @@ -1,6 +1,4 @@ -# Authors: Mainak Jas -# Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/simulation/__init__.py b/mne/simulation/__init__.py index 3abcf5a34d0..67360191ac9 100644 --- a/mne/simulation/__init__.py +++ b/mne/simulation/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Data simulation code.""" import lazy_loader as lazy diff --git a/mne/simulation/_metrics.py b/mne/simulation/_metrics.py index 89e0283cc2f..60771e5daa7 100644 --- a/mne/simulation/_metrics.py +++ b/mne/simulation/_metrics.py @@ -1,6 +1,4 @@ -# Authors: Yousra Bekhti -# Mark Wronkiewicz -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/simulation/evoked.py b/mne/simulation/evoked.py index a96c9c134fe..2af6ea3e6f3 100644 --- a/mne/simulation/evoked.py +++ b/mne/simulation/evoked.py @@ -1,9 +1,7 @@ -# Authors: Alexandre Gramfort -# Daniel Strohmeier -# Martin Luessi -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import math import numpy as np diff --git a/mne/simulation/metrics/__init__.py b/mne/simulation/metrics/__init__.py index 436551abdfc..d8c0dda9d11 100644 --- a/mne/simulation/metrics/__init__.py +++ b/mne/simulation/metrics/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Metrics module for compute stc-based metrics.""" from .metrics import ( diff --git a/mne/simulation/metrics/metrics.py b/mne/simulation/metrics/metrics.py index 027a6b52bf1..c9ac7c0d893 100644 --- a/mne/simulation/metrics/metrics.py +++ b/mne/simulation/metrics/metrics.py @@ -1,8 +1,4 @@ -# Authors: Yousra Bekhti -# Mark Wronkiewicz -# Kostiantyn Maksymenko -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/simulation/metrics/tests/__init__.py b/mne/simulation/metrics/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/simulation/metrics/tests/__init__.py +++ b/mne/simulation/metrics/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/simulation/metrics/tests/test_metrics.py b/mne/simulation/metrics/tests/test_metrics.py index 328a30c88fb..c1d160c21aa 100644 --- a/mne/simulation/metrics/tests/test_metrics.py +++ b/mne/simulation/metrics/tests/test_metrics.py @@ -1,6 +1,4 @@ -# Authors: Kostiantyn Maksymenko -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/simulation/raw.py b/mne/simulation/raw.py index aaeeed4867f..298cd9bf185 100644 --- a/mne/simulation/raw.py +++ b/mne/simulation/raw.py @@ -1,7 +1,4 @@ -# Authors: Mark Wronkiewicz -# Yousra Bekhti -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -101,7 +98,7 @@ def _log_ch(start, info, ch): def _check_head_pos(head_pos, info, first_samp, times=None): if head_pos is None: # use pos from info['dev_head_t'] head_pos = dict() - if isinstance(head_pos, (str, Path, os.PathLike)): + if isinstance(head_pos, str | Path | os.PathLike): head_pos = read_head_pos(head_pos) if isinstance(head_pos, np.ndarray): # can be head_pos quats head_pos = head_pos_to_trans_rot_t(head_pos) @@ -350,7 +347,7 @@ def simulate_raw( this_start = 0 for n in range(max_iter): - if isinstance(stc_counted[1], (list, tuple)): + if isinstance(stc_counted[1], list | tuple): this_n = stc_counted[1][0].data.shape[1] else: this_n = stc_counted[1].data.shape[1] @@ -684,7 +681,7 @@ def __call__(self, offset): def _stc_data_event(stc_counted, head_idx, sfreq, src=None, verts=None): stc_idx, stc = stc_counted - if isinstance(stc, (list, tuple)): + if isinstance(stc, list | tuple): if len(stc) != 2: raise ValueError(f"stc, if tuple, must be length 2, got {len(stc)}") stc, stim_data = stc diff --git a/mne/simulation/source.py b/mne/simulation/source.py index e50575e62d5..96d826dfa83 100644 --- a/mne/simulation/source.py +++ b/mne/simulation/source.py @@ -1,11 +1,4 @@ -# Authors: Alexandre Gramfort -# Martin Luessi -# Daniel Strohmeier -# Nathalie Gayraud -# Kostiantyn Maksymenko -# Samuel Deslauriers-Gauthier -# Ivana Kojcic -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/simulation/tests/__init__.py b/mne/simulation/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/simulation/tests/__init__.py +++ b/mne/simulation/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/simulation/tests/test_evoked.py b/mne/simulation/tests/test_evoked.py index b8fc7f12ff8..003b16ef47d 100644 --- a/mne/simulation/tests/test_evoked.py +++ b/mne/simulation/tests/test_evoked.py @@ -1,5 +1,4 @@ -# Author: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/simulation/tests/test_metrics.py b/mne/simulation/tests/test_metrics.py index 378c7908743..1e581fb72c2 100644 --- a/mne/simulation/tests/test_metrics.py +++ b/mne/simulation/tests/test_metrics.py @@ -1,6 +1,4 @@ -# Author: Yousra Bekhti -# Mark Wronkiewicz -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/simulation/tests/test_raw.py b/mne/simulation/tests/test_raw.py index 2b047f758dd..8d5cd4e5dec 100644 --- a/mne/simulation/tests/test_raw.py +++ b/mne/simulation/tests/test_raw.py @@ -1,7 +1,4 @@ -# Authors: Mark Wronkiewicz -# Yousra Bekhti -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/simulation/tests/test_source.py b/mne/simulation/tests/test_source.py index 43bf5654a8b..eb5eb1bd983 100644 --- a/mne/simulation/tests/test_source.py +++ b/mne/simulation/tests/test_source.py @@ -1,6 +1,4 @@ -# Author: Kostiantyn Maksymenko -# Samuel Deslauriers-Gauthier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/source_estimate.py b/mne/source_estimate.py index 772851483f5..64c2d588f57 100644 --- a/mne/source_estimate.py +++ b/mne/source_estimate.py @@ -1,8 +1,4 @@ -# Authors: Alexandre Gramfort -# Matti Hämäläinen -# Martin Luessi -# Mads Jensen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1455,7 +1451,7 @@ def to_data_frame( # triage surface vs volume source estimates col_names = list() kinds = ["VOL"] * len(self.vertices) - if isinstance(self, (_BaseSurfaceSourceEstimate, _BaseMixedSourceEstimate)): + if isinstance(self, _BaseSurfaceSourceEstimate | _BaseMixedSourceEstimate): kinds[:2] = ["LH", "RH"] for kind, vertno in zip(kinds, self.vertices): col_names.extend([f"{kind}_{vert}" for vert in vertno]) @@ -3643,7 +3639,7 @@ def _get_default_label_modes(): def _get_allowed_label_modes(stc): - if isinstance(stc, (_BaseVolSourceEstimate, _BaseVectorSourceEstimate)): + if isinstance(stc, _BaseVolSourceEstimate | _BaseVectorSourceEstimate): return ("mean", "max", "auto") else: return _get_default_label_modes() @@ -3686,7 +3682,7 @@ def _gen_extract_label_time_course( _get_allowed_label_modes(stc), "when using a vector and/or volume source estimate", ) - if isinstance(stc, (_BaseVolSourceEstimate, _BaseVectorSourceEstimate)): + if isinstance(stc, _BaseVolSourceEstimate | _BaseVectorSourceEstimate): mode = "mean" if mode == "auto" else mode else: mode = "mean_flip" if mode == "auto" else mode @@ -3791,7 +3787,7 @@ def extract_label_time_course( time courses. """ # convert inputs to lists - if not isinstance(stcs, (list, tuple, GeneratorType)): + if not isinstance(stcs, list | tuple | GeneratorType): stcs = [stcs] return_several = False return_generator = False diff --git a/mne/source_space/__init__.py b/mne/source_space/__init__.py index d1370283776..46fb9e1fbff 100644 --- a/mne/source_space/__init__.py +++ b/mne/source_space/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Forward modeling code.""" import lazy_loader as lazy diff --git a/mne/source_space/_source_space.py b/mne/source_space/_source_space.py index ea598d31693..4265de0cd11 100644 --- a/mne/source_space/_source_space.py +++ b/mne/source_space/_source_space.py @@ -1,6 +1,4 @@ -# Authors: Matti Hämäläinen -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1667,7 +1665,7 @@ def setup_volume_source_space( .. note:: For a discrete source space (``pos`` is a dict), ``mri`` must be None. - mri : str | None + mri : path-like | None The filename of an MRI volume (mgh or mgz) to create the interpolation matrix over. Source estimates obtained in the volume source space can then be morphed onto the MRI volume @@ -1793,9 +1791,8 @@ def setup_volume_source_space( mri = _check_mri(mri, subject, subjects_dir) if isinstance(pos, dict): raise ValueError( - "Cannot create interpolation matrix for " - "discrete source space, mri must be None if " - "pos is a dict" + "Cannot create interpolation matrix for discrete source space, mri " + "must be None if pos is a dict" ) if volume_label is not None: diff --git a/mne/source_space/tests/__init__.py b/mne/source_space/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/source_space/tests/__init__.py +++ b/mne/source_space/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/source_space/tests/test_source_space.py b/mne/source_space/tests/test_source_space.py index a4771a02333..94f7aa923d2 100644 --- a/mne/source_space/tests/test_source_space.py +++ b/mne/source_space/tests/test_source_space.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/__init__.py b/mne/stats/__init__.py index ebf535d1339..18946a20aca 100644 --- a/mne/stats/__init__.py +++ b/mne/stats/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Functions for statistical analysis.""" import lazy_loader as lazy diff --git a/mne/stats/_adjacency.py b/mne/stats/_adjacency.py index 1270a956294..919c07b0ba5 100644 --- a/mne/stats/_adjacency.py +++ b/mne/stats/_adjacency.py @@ -1,6 +1,4 @@ -# Authors: Eric Larson -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/cluster_level.py b/mne/stats/cluster_level.py index 02727f2c046..50743c104ef 100644 --- a/mne/stats/cluster_level.py +++ b/mne/stats/cluster_level.py @@ -1,12 +1,6 @@ #!/usr/bin/env python -# Authors: Thorsten Kranz -# Alexandre Gramfort -# Martin Luessi -# Eric Larson -# Denis Engemann -# Fernando Perez (bin_perm_rep function) -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/erp.py b/mne/stats/erp.py index 42766cbc440..9fc7c3bb4cd 100644 --- a/mne/stats/erp.py +++ b/mne/stats/erp.py @@ -1,5 +1,6 @@ """ERP-related statistics.""" +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/multi_comp.py b/mne/stats/multi_comp.py index 228b2f90a2a..4bfc87e3388 100644 --- a/mne/stats/multi_comp.py +++ b/mne/stats/multi_comp.py @@ -1,8 +1,4 @@ -# Authors: Josef Pktd and example from H Raja and rewrite from Vincent Davis -# Alexandre Gramfort -# -# Code borrowed from statsmodels -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/parametric.py b/mne/stats/parametric.py index 0da2d2d0732..2cc0bff2ea1 100644 --- a/mne/stats/parametric.py +++ b/mne/stats/parametric.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/permutations.py b/mne/stats/permutations.py index c5722241ea4..a49d3daca74 100644 --- a/mne/stats/permutations.py +++ b/mne/stats/permutations.py @@ -1,7 +1,6 @@ """T-test with permutations.""" -# Authors: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/regression.py b/mne/stats/regression.py index 281aff12359..bb696f6ef05 100644 --- a/mne/stats/regression.py +++ b/mne/stats/regression.py @@ -1,9 +1,4 @@ -# Authors: Tal Linzen -# Teon Brooks -# Denis A. Engemann -# Jona Sassenhagen -# Marijn van Vliet -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -97,7 +92,7 @@ def linear_regression(inst, design_matrix, names=None): parameters = [p[name] for p in lm_params] for ii, value in enumerate(parameters): out_ = out.copy() - if not isinstance(out_, (SourceEstimate, Evoked)): + if not isinstance(out_, SourceEstimate | Evoked): raise RuntimeError("Invalid container.") out_._data[:] = value parameters[ii] = out_ @@ -354,11 +349,11 @@ def _prepare_rerp_preds( # time windows (per event type) are converted to sample points from times # int(round()) to be safe and match Epochs constructor behavior - if isinstance(tmin, (float, int)): + if isinstance(tmin, float | int): tmin_s = {cond: int(round(tmin * sfreq)) for cond in conds} else: tmin_s = {cond: int(round(tmin.get(cond, -0.1) * sfreq)) for cond in conds} - if isinstance(tmax, (float, int)): + if isinstance(tmax, float | int): tmax_s = {cond: int(round(tmax * sfreq) + 1) for cond in conds} else: tmax_s = {cond: int(round(tmax.get(cond, 1.0) * sfreq)) + 1 for cond in conds} diff --git a/mne/stats/tests/__init__.py b/mne/stats/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/stats/tests/__init__.py +++ b/mne/stats/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/tests/test_adjacency.py b/mne/stats/tests/test_adjacency.py index 8a1e8b15aca..216852a18c4 100644 --- a/mne/stats/tests/test_adjacency.py +++ b/mne/stats/tests/test_adjacency.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/tests/test_cluster_level.py b/mne/stats/tests/test_cluster_level.py index 439045b8d08..e319d018328 100644 --- a/mne/stats/tests/test_cluster_level.py +++ b/mne/stats/tests/test_cluster_level.py @@ -1,6 +1,4 @@ -# Authors: Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/tests/test_erp.py b/mne/stats/tests/test_erp.py index aa4394d611b..d0dea27f43c 100644 --- a/mne/stats/tests/test_erp.py +++ b/mne/stats/tests/test_erp.py @@ -1,3 +1,7 @@ +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + from pathlib import Path import pytest diff --git a/mne/stats/tests/test_multi_comp.py b/mne/stats/tests/test_multi_comp.py index e411d37c0a0..67d183486dd 100644 --- a/mne/stats/tests/test_multi_comp.py +++ b/mne/stats/tests/test_multi_comp.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np import pytest from numpy.testing import assert_allclose, assert_almost_equal, assert_array_equal diff --git a/mne/stats/tests/test_parametric.py b/mne/stats/tests/test_parametric.py index de7aa237c40..61ecbc43af3 100644 --- a/mne/stats/tests/test_parametric.py +++ b/mne/stats/tests/test_parametric.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from functools import partial from itertools import product diff --git a/mne/stats/tests/test_permutations.py b/mne/stats/tests/test_permutations.py index 2bc8ca7e34f..d244e9140a8 100644 --- a/mne/stats/tests/test_permutations.py +++ b/mne/stats/tests/test_permutations.py @@ -1,5 +1,4 @@ -# Authors: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/stats/tests/test_regression.py b/mne/stats/tests/test_regression.py index dab09d4693f..388d9f462e1 100644 --- a/mne/stats/tests/test_regression.py +++ b/mne/stats/tests/test_regression.py @@ -1,7 +1,4 @@ -# Authors: Teon Brooks -# Denis A. Engemann -# Jona Sassenhagen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/surface.py b/mne/surface.py index 9a2ee9d30c9..7018dcce7dd 100644 --- a/mne/surface.py +++ b/mne/surface.py @@ -1,8 +1,4 @@ -# Authors: Matti Hämäläinen -# Alexandre Gramfort -# Matti Hämäläinen -# Denis A. Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/__init__.py b/mne/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/tests/__init__.py +++ b/mne/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_annotations.py b/mne/tests/test_annotations.py index 2c8c6faa6c3..4d37cce033e 100644 --- a/mne/tests/test_annotations.py +++ b/mne/tests/test_annotations.py @@ -1,6 +1,4 @@ -# Authors: Jaakko Leppakangas -# Robert Luke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_bem.py b/mne/tests/test_bem.py index e8302157b3c..9aa8a85fd4d 100644 --- a/mne/tests/test_bem.py +++ b/mne/tests/test_bem.py @@ -1,5 +1,4 @@ -# Authors: Marijn van Vliet -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_chpi.py b/mne/tests/test_chpi.py index d979b62446b..51312fd4c0a 100644 --- a/mne/tests/test_chpi.py +++ b/mne/tests/test_chpi.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_coreg.py b/mne/tests/test_coreg.py index f1988a329a8..762e79e3857 100644 --- a/mne/tests/test_coreg.py +++ b/mne/tests/test_coreg.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os from functools import reduce from glob import glob diff --git a/mne/tests/test_cov.py b/mne/tests/test_cov.py index d65363869f6..ad05f5d8b1f 100644 --- a/mne/tests/test_cov.py +++ b/mne/tests/test_cov.py @@ -1,6 +1,4 @@ -# Author: Alexandre Gramfort -# Denis Engemann -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_defaults.py b/mne/tests/test_defaults.py index 2a490ad19ee..ba3a8395fa8 100644 --- a/mne/tests/test_defaults.py +++ b/mne/tests/test_defaults.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from copy import deepcopy import pytest diff --git a/mne/tests/test_dipole.py b/mne/tests/test_dipole.py index 30300572fa5..e93d4031646 100644 --- a/mne/tests/test_dipole.py +++ b/mne/tests/test_dipole.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_docstring_parameters.py b/mne/tests/test_docstring_parameters.py index 196c981deb3..d32e62a454e 100644 --- a/mne/tests/test_docstring_parameters.py +++ b/mne/tests/test_docstring_parameters.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -110,7 +109,6 @@ def _func_name(func, cls=None): }, ), (list, {"append", "count", "extend", "index", "insert", "pop", "remove", "sort"}), - (mne.fixes.BaseEstimator, {"get_params", "set_params", "fit_transform"}), ) @@ -176,7 +174,12 @@ def test_docstring_parameters(): module = __import__(name, globals()) for submod in name.split(".")[1:]: module = getattr(module, submod) - classes = inspect.getmembers(module, inspect.isclass) + try: + classes = inspect.getmembers(module, inspect.isclass) + except ModuleNotFoundError as exc: # e.g., mne.decoding but no sklearn + if "'sklearn'" in str(exc): + continue + raise for cname, cls in classes: if cname.startswith("_"): continue @@ -327,7 +330,12 @@ def test_documented(): module = __import__(name, globals()) for submod in name.split(".")[1:]: module = getattr(module, submod) - classes = inspect.getmembers(module, inspect.isclass) + try: + classes = inspect.getmembers(module, inspect.isclass) + except ModuleNotFoundError as exc: # e.g., mne.decoding but no sklearn + if "'sklearn'" in str(exc): + continue + raise functions = inspect.getmembers(module, inspect.isfunction) checks = list(classes) + list(functions) for this_name, cf in checks: diff --git a/mne/tests/test_epochs.py b/mne/tests/test_epochs.py index 5fc3f628822..079a2b53ec9 100644 --- a/mne/tests/test_epochs.py +++ b/mne/tests/test_epochs.py @@ -1,7 +1,4 @@ -# Author: Alexandre Gramfort -# Denis Engemann -# Stefan Appelhoff -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1693,12 +1690,13 @@ def test_split_naming( if dst_fpath.parent != tmp_path: dst_fpath.parent.mkdir(parents=True) - epochs.save(dst_fpath, verbose=True, **save_kwargs) + split_fnames = epochs.save(dst_fpath, verbose=True, **save_kwargs) # check that the filenames match the intended pattern assert len(list(dst_fpath.parent.iterdir())) == n_files assert not (tmp_path / split_fname_fn(n_files)).is_file() want_paths = [tmp_path / split_fname_fn(i) for i in range(n_files)] + assert split_fnames == want_paths for want_path in want_paths: assert want_path.is_file() @@ -1728,9 +1726,9 @@ def test_split_naming( assert str(bad_path).count("_split-01") == 2 assert not bad_path.is_file(), bad_path bids_path.split = None - epochs.save(bids_path, verbose=True, **save_kwargs) - for want_path in want_paths: - assert want_path.is_file() + split_fnames = epochs.save(bids_path, verbose=True, **save_kwargs) + for split_fname in split_fnames: + assert split_fname.is_file() @pytest.mark.parametrize( @@ -1753,7 +1751,8 @@ def test_saved_fname_no_splitting( dst_fpath = tmp_path / dst_fname split_1_fpath = tmp_path / split_1_fname - epochs.save(dst_fpath, split_naming=split_naming, verbose=True) + filenames = epochs.save(dst_fpath, split_naming=split_naming, verbose=True) + assert filenames == [dst_fpath] assert dst_fpath.is_file() assert not split_1_fpath.is_file() diff --git a/mne/tests/test_event.py b/mne/tests/test_event.py index a5651c1b365..7e058912537 100644 --- a/mne/tests/test_event.py +++ b/mne/tests/test_event.py @@ -1,8 +1,7 @@ -# Author: Alexandre Gramfort -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os from pathlib import Path diff --git a/mne/tests/test_evoked.py b/mne/tests/test_evoked.py index 75333aa0ca5..e51eb6afd15 100644 --- a/mne/tests/test_evoked.py +++ b/mne/tests/test_evoked.py @@ -1,8 +1,4 @@ -# Author: Alexandre Gramfort -# Denis Engemann -# Andrew Dykstra -# Mads Jensen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_filter.py b/mne/tests/test_filter.py index 28e339f8ce1..e259ececbce 100644 --- a/mne/tests/test_filter.py +++ b/mne/tests/test_filter.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np import pytest from numpy.fft import fft, fftfreq diff --git a/mne/tests/test_freesurfer.py b/mne/tests/test_freesurfer.py index 4b100682329..202f6e31645 100644 --- a/mne/tests/test_freesurfer.py +++ b/mne/tests/test_freesurfer.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from pathlib import Path import numpy as np diff --git a/mne/tests/test_import_nesting.py b/mne/tests/test_import_nesting.py index d597d730cc1..6904e9ff755 100644 --- a/mne/tests/test_import_nesting.py +++ b/mne/tests/test_import_nesting.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -100,7 +99,7 @@ def __init__(self, *, rel_path, must_nest, must_not_nest): super().__init__() def generic_visit(self, node): - if not isinstance(node, (ast.Import, ast.ImportFrom)): + if not isinstance(node, ast.Import | ast.ImportFrom): super().generic_visit(node) return stmt = " " * node.col_offset @@ -142,7 +141,7 @@ def generic_visit(self, node): ("mne/utils/docs.py", " import mne", "non-relative mne import"), ( "mne/io/_read_raw.py", - " from . import read_raw_artemis123, read_raw_bdf, read_raw_boxy, read_raw_brainvision, read_raw_cnt, read_raw_ctf, read_raw_curry, read_raw_edf, read_raw_eeglab, read_raw_egi, read_raw_eximia, read_raw_fieldtrip, read_raw_fif, read_raw_fil, read_raw_gdf, read_raw_kit, read_raw_nedf, read_raw_nicolet, read_raw_nihon, read_raw_nirx, read_raw_snirf", # noqa: E501 + " from . import read_raw_ant, read_raw_artemis123, read_raw_bdf, read_raw_boxy, read_raw_brainvision, read_raw_cnt, read_raw_ctf, read_raw_curry, read_raw_edf, read_raw_eeglab, read_raw_egi, read_raw_eximia, read_raw_eyelink, read_raw_fieldtrip, read_raw_fif, read_raw_fil, read_raw_gdf, read_raw_kit, read_raw_nedf, read_raw_nicolet, read_raw_nihon, read_raw_nirx, read_raw_nsx, read_raw_persyst, read_raw_snirf", # noqa: E501 "non-explicit relative import", ), ( diff --git a/mne/tests/test_label.py b/mne/tests/test_label.py index f42a11306e0..c19ebb73c84 100644 --- a/mne/tests/test_label.py +++ b/mne/tests/test_label.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_line_endings.py b/mne/tests/test_line_endings.py index e7ce9540454..e61b5f3f166 100644 --- a/mne/tests/test_line_endings.py +++ b/mne/tests/test_line_endings.py @@ -1,6 +1,4 @@ -# Author: Eric Larson -# Adapted from vispy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_misc.py b/mne/tests/test_misc.py index 54286669e57..718c6e634d5 100644 --- a/mne/tests/test_misc.py +++ b/mne/tests/test_misc.py @@ -1,5 +1,4 @@ -# Authors: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_morph.py b/mne/tests/test_morph.py index 6dc556b808e..7cb7d0cb9d9 100644 --- a/mne/tests/test_morph.py +++ b/mne/tests/test_morph.py @@ -1,7 +1,7 @@ -# Author: Tommy Clausner -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from inspect import signature import numpy as np @@ -1137,7 +1137,11 @@ def test_resample_equiv(from_shape, from_affine, to_shape, to_affine, order, see interp = "linear" if order == 1 else "nearest" got_dipy = dipy.align.imaffine.AffineMap( - None, to_shape, to_affine, from_shape, from_affine + None, + domain_grid_shape=to_shape, + domain_grid2world=to_affine, + codomain_grid_shape=from_shape, + codomain_grid2world=from_affine, ).transform(from_data, interpolation=interp, resample_only=True) # XXX possibly some error in dipy or nibabel (/SciPy), or some boundary # condition? diff --git a/mne/tests/test_morph_map.py b/mne/tests/test_morph_map.py index c0f4c1a9098..59b05538c57 100644 --- a/mne/tests/test_morph_map.py +++ b/mne/tests/test_morph_map.py @@ -1,5 +1,4 @@ -# Authors: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_ola.py b/mne/tests/test_ola.py index 966636fbcf7..26ddafd8475 100644 --- a/mne/tests/test_ola.py +++ b/mne/tests/test_ola.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np import pytest from numpy.testing import assert_allclose diff --git a/mne/tests/test_parallel.py b/mne/tests/test_parallel.py index 7e7812bcace..f72f3281a59 100644 --- a/mne/tests/test_parallel.py +++ b/mne/tests/test_parallel.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_proj.py b/mne/tests/test_proj.py index 36437238f90..d7bb2e35059 100644 --- a/mne/tests/test_proj.py +++ b/mne/tests/test_proj.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import copy as cp from pathlib import Path diff --git a/mne/tests/test_rank.py b/mne/tests/test_rank.py index bc7fd3b8839..8452f48a756 100644 --- a/mne/tests/test_rank.py +++ b/mne/tests/test_rank.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import itertools from pathlib import Path diff --git a/mne/tests/test_read_vectorview_selection.py b/mne/tests/test_read_vectorview_selection.py index e0ed6f0af20..e812509c0b9 100644 --- a/mne/tests/test_read_vectorview_selection.py +++ b/mne/tests/test_read_vectorview_selection.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from pathlib import Path import pytest diff --git a/mne/tests/test_source_estimate.py b/mne/tests/test_source_estimate.py index 86d44e95ed8..7eafd2517b2 100644 --- a/mne/tests/test_source_estimate.py +++ b/mne/tests/test_source_estimate.py @@ -1,4 +1,5 @@ # +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_surface.py b/mne/tests/test_surface.py index 5fa5aa4fd49..86074f417c1 100644 --- a/mne/tests/test_surface.py +++ b/mne/tests/test_surface.py @@ -1,5 +1,4 @@ -# Authors: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/tests/test_transforms.py b/mne/tests/test_transforms.py index 62329a88d25..b17adead4c3 100644 --- a/mne/tests/test_transforms.py +++ b/mne/tests/test_transforms.py @@ -1,5 +1,4 @@ -# Author: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/__init__.py b/mne/time_frequency/__init__.py index 51189f461d7..74cfd53ec71 100644 --- a/mne/time_frequency/__init__.py +++ b/mne/time_frequency/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Time frequency analysis tools.""" import lazy_loader as lazy diff --git a/mne/time_frequency/_stft.py b/mne/time_frequency/_stft.py index f1555cc1638..8fb80b43fcc 100644 --- a/mne/time_frequency/_stft.py +++ b/mne/time_frequency/_stft.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from math import ceil import numpy as np diff --git a/mne/time_frequency/_stockwell.py b/mne/time_frequency/_stockwell.py index 08acf28b357..0f20aa30bdf 100644 --- a/mne/time_frequency/_stockwell.py +++ b/mne/time_frequency/_stockwell.py @@ -1,7 +1,4 @@ -# Authors : Denis A. Engemann -# Alexandre Gramfort -# -# License : BSD-3-Clause +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/ar.py b/mne/time_frequency/ar.py index db632a77aa0..82b863a0807 100644 --- a/mne/time_frequency/ar.py +++ b/mne/time_frequency/ar.py @@ -1,6 +1,4 @@ -# Authors: Alexandre Gramfort -# The statsmodels folks for AR yule_walker -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/csd.py b/mne/time_frequency/csd.py index 818a4372a70..c858dd52e57 100644 --- a/mne/time_frequency/csd.py +++ b/mne/time_frequency/csd.py @@ -1,7 +1,4 @@ -# Authors: Marijn van Vliet -# Susanna Aro -# Roman Goj -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/multitaper.py b/mne/time_frequency/multitaper.py index 43fccb64038..73a3308685d 100644 --- a/mne/time_frequency/multitaper.py +++ b/mne/time_frequency/multitaper.py @@ -1,5 +1,4 @@ -# Author : Martin Luessi mluessi@nmr.mgh.harvard.edu (2012) -# License : BSD-3-Clause +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/psd.py b/mne/time_frequency/psd.py index 133b73761c2..19cced38305 100644 --- a/mne/time_frequency/psd.py +++ b/mne/time_frequency/psd.py @@ -1,6 +1,4 @@ -# Authors : Alexandre Gramfort, alexandre.gramfort@inria.fr (2011) -# Denis A. Engemann -# License : BSD-3-Clause +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/spectrum.py b/mne/time_frequency/spectrum.py index 902d1c70e30..25c3b6f3110 100644 --- a/mne/time_frequency/spectrum.py +++ b/mne/time_frequency/spectrum.py @@ -1,4 +1,6 @@ """Container classes for spectral data.""" + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/tests/__init__.py b/mne/time_frequency/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/time_frequency/tests/__init__.py +++ b/mne/time_frequency/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/tests/test_ar.py b/mne/time_frequency/tests/test_ar.py index f0ea9db2a1e..00908b30ee8 100644 --- a/mne/time_frequency/tests/test_ar.py +++ b/mne/time_frequency/tests/test_ar.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from pathlib import Path import numpy as np diff --git a/mne/time_frequency/tests/test_csd.py b/mne/time_frequency/tests/test_csd.py index 027eae6d9a2..d5372da3bd0 100644 --- a/mne/time_frequency/tests/test_csd.py +++ b/mne/time_frequency/tests/test_csd.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import pickle from itertools import product from os import path as op diff --git a/mne/time_frequency/tests/test_multitaper.py b/mne/time_frequency/tests/test_multitaper.py index 5f6982f7311..426b148f86a 100644 --- a/mne/time_frequency/tests/test_multitaper.py +++ b/mne/time_frequency/tests/test_multitaper.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np import pytest from numpy.testing import assert_array_almost_equal diff --git a/mne/time_frequency/tests/test_psd.py b/mne/time_frequency/tests/test_psd.py index 363a4207ce9..ad1c24c10e6 100644 --- a/mne/time_frequency/tests/test_psd.py +++ b/mne/time_frequency/tests/test_psd.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np import pytest from numpy.testing import assert_allclose, assert_array_almost_equal, assert_array_equal diff --git a/mne/time_frequency/tests/test_spectrum.py b/mne/time_frequency/tests/test_spectrum.py index 980df42d791..cf06b72b9ed 100644 --- a/mne/time_frequency/tests/test_spectrum.py +++ b/mne/time_frequency/tests/test_spectrum.py @@ -1,3 +1,4 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/tests/test_stft.py b/mne/time_frequency/tests/test_stft.py index 9432ba92d8c..47f45f8c238 100644 --- a/mne/time_frequency/tests/test_stft.py +++ b/mne/time_frequency/tests/test_stft.py @@ -1,7 +1,4 @@ -# Authors : Alexandre Gramfort -# Eric Larson -# -# License : BSD-3-Clause +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/tests/test_stockwell.py b/mne/time_frequency/tests/test_stockwell.py index 54d71b907ed..2cfe8c69d68 100644 --- a/mne/time_frequency/tests/test_stockwell.py +++ b/mne/time_frequency/tests/test_stockwell.py @@ -1,7 +1,4 @@ -# Authors : Denis A. Engemann -# Alexandre Gramfort -# -# License : BSD-3-Clause +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/time_frequency/tests/test_tfr.py b/mne/time_frequency/tests/test_tfr.py index bec82665d1c..cd3a97ab90a 100644 --- a/mne/time_frequency/tests/test_tfr.py +++ b/mne/time_frequency/tests/test_tfr.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import datetime import re from itertools import product @@ -1528,6 +1530,13 @@ def test_epochs_compute_tfr_stockwell(epochs, freqs, return_itc): assert tfr.comment == "1" +@pytest.mark.parametrize("output", ("complex", "phase")) +def test_epochs_compute_tfr_multitaper_complex_phase(epochs, output): + """Test Epochs.compute_tfr(output="complex"/"phase").""" + tfr = epochs.compute_tfr("multitaper", freqs_linspace, output=output) + assert len(tfr.shape) == 5 + + @pytest.mark.parametrize("copy", (False, True)) def test_epochstfr_iter_evoked(epochs_tfr, copy): """Test EpochsTFR.iter_evoked().""" diff --git a/mne/time_frequency/tfr.py b/mne/time_frequency/tfr.py index 5e61695bc88..eaf173092bb 100644 --- a/mne/time_frequency/tfr.py +++ b/mne/time_frequency/tfr.py @@ -2,12 +2,8 @@ Morlet code inspired by Matlab code from Sheraz Khan & Brainstorm & SPM """ -# Authors : Alexandre Gramfort -# Hari Bharadwaj -# Clement Moutard -# Jean-Remi King -# -# License : BSD-3-Clause + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -597,7 +593,7 @@ def _check_tfr_param( ): """Aux. function to _compute_tfr to check the params validity.""" # Check freqs - if not isinstance(freqs, (list, np.ndarray)): + if not isinstance(freqs, list | np.ndarray): raise ValueError(f"freqs must be an array-like, got {type(freqs)} instead.") freqs = np.asarray(freqs, dtype=float) if freqs.ndim != 1: @@ -607,7 +603,7 @@ def _check_tfr_param( ) # Check sfreq - if not isinstance(sfreq, (float, int)): + if not isinstance(sfreq, float | int): raise ValueError(f"sfreq must be a float or an int, got {type(sfreq)} instead.") sfreq = float(sfreq) @@ -620,9 +616,9 @@ def _check_tfr_param( freqs = np.asarray(freqs) # Check n_cycles - if isinstance(n_cycles, (int, float)): + if isinstance(n_cycles, int | float): n_cycles = float(n_cycles) - elif isinstance(n_cycles, (list, np.ndarray)): + elif isinstance(n_cycles, list | np.ndarray): n_cycles = np.array(n_cycles) if len(n_cycles) != len(freqs): raise ValueError( @@ -1537,7 +1533,8 @@ def _compute_tfr(self, data, n_jobs, verbose): ] # deal with the "taper" dimension if self._needs_taper_dim: - expected_shape.insert(1, self._data.shape[1]) + tapers_dim = 1 if _get_instance_type_string(self) != "Epochs" else 2 + expected_shape.insert(1, self._data.shape[tapers_dim]) self._shape = tuple(expected_shape) @verbose @@ -1874,8 +1871,6 @@ def plot( combine=None, layout=None, # TODO deprecate? not used in orig implementation either yscale="auto", - vmin=None, - vmax=None, vlim=(None, None), cnorm=None, cmap=None, @@ -1910,7 +1905,6 @@ def plot( %(yscale_tfr_plot)s .. versionadded:: 0.14.0 - %(vmin_vmax_tfr_plot)s %(vlim_tfr_plot)s %(cnorm)s @@ -1939,8 +1933,6 @@ def plot( figs : list of instances of matplotlib.figure.Figure A list of figures containing the time-frequency power. """ - # deprecations - vlim = _warn_deprecated_vmin_vmax(vlim, vmin, vmax) # the rectangle selector plots topomaps, which needs all channels uncombined, # so we keep a reference to that state here, and (because the topomap plotting # function wants an AverageTFR) update it with `comment` and `nave` values in @@ -2127,8 +2119,6 @@ def plot_joint( mode="mean", dB=False, yscale="auto", - vmin=None, - vmax=None, vlim=(None, None), cnorm=None, cmap=None, @@ -2159,7 +2149,6 @@ def plot_joint( %(mode_tfr_plot)s %(dB_tfr_plot_topo)s %(yscale_tfr_plot)s - %(vmin_vmax_tfr_plot)s %(vlim_tfr_plot_joint)s %(cnorm)s %(cmap_tfr_plot_topo)s @@ -2184,8 +2173,6 @@ def plot_joint( from matplotlib import ticker from matplotlib.patches import ConnectionPatch - # deprecations - vlim = _warn_deprecated_vmin_vmax(vlim, vmin, vmax) # handle recursion picks = _picks_to_idx( self.info, picks, "data_or_ica", exclude=exclude, with_ref_meg=False @@ -2721,37 +2708,12 @@ class AverageTFR(BaseTFR): Parameters ---------- - %(info_not_none)s - - .. deprecated:: 1.7 - Pass an instance of :class:`~mne.Epochs` or :class:`~mne.Evoked` instead, or - use :class:`~mne.time_frequency.AverageTFRArray` which retains the old API. - data : ndarray, shape (n_channels, n_freqs, n_times) - The data. - - .. deprecated:: 1.7 - Pass an instance of :class:`~mne.Epochs` or :class:`~mne.Evoked` instead, or - use :class:`~mne.time_frequency.AverageTFRArray` which retains the old API. - times : ndarray, shape (n_times,) - The time values in seconds. - - .. deprecated:: 1.7 - Pass an instance of :class:`~mne.Epochs` or :class:`~mne.Evoked` instead and - (optionally) use ``tmin`` and ``tmax`` to restrict the time domain; or use - :class:`~mne.time_frequency.AverageTFRArray` which retains the old API. - freqs : ndarray, shape (n_freqs,) - The frequencies in Hz. - nave : int - The number of averaged TFRs. - - .. deprecated:: 1.7 - Pass an instance of :class:`~mne.Epochs` or :class:`~mne.Evoked` instead; - ``nave`` will be inferred automatically. Or, use - :class:`~mne.time_frequency.AverageTFRArray` which retains the old API. inst : instance of Evoked | instance of Epochs | dict The data from which to compute the time-frequency representation. Passing a :class:`dict` will create the AverageTFR using the ``__setstate__`` interface and is not recommended for typical use cases. + freqs : ndarray, shape (n_freqs,) + The frequencies in Hz. %(method_tfr)s %(freqs_tfr)s %(tmin_tmax_psd)s @@ -2809,13 +2771,9 @@ class AverageTFR(BaseTFR): def __init__( self, - info=None, - data=None, - times=None, - freqs=None, - nave=None, *, inst=None, + freqs=None, method=None, tmin=None, tmax=None, @@ -2980,33 +2938,10 @@ class EpochsTFR(BaseTFR, GetEpochsMixin): Parameters ---------- - %(info_not_none)s - - .. deprecated:: 1.7 - Pass an instance of :class:`~mne.Epochs` as ``inst`` instead, or use - :class:`~mne.time_frequency.EpochsTFRArray` which retains the old API. - data : ndarray, shape (n_channels, n_freqs, n_times) - The data. - - .. deprecated:: 1.7 - Pass an instance of :class:`~mne.Epochs` as ``inst`` instead, or use - :class:`~mne.time_frequency.EpochsTFRArray` which retains the old API. - times : ndarray, shape (n_times,) - The time values in seconds. - - .. deprecated:: 1.7 - Pass an instance of :class:`~mne.Epochs` as ``inst`` instead and - (optionally) use ``tmin`` and ``tmax`` to restrict the time domain; or use - :class:`~mne.time_frequency.EpochsTFRArray` which retains the old API. - %(freqs_tfr_epochs)s inst : instance of Epochs The data from which to compute the time-frequency representation. + %(freqs_tfr_epochs)s %(method_tfr_epochs)s - %(comment_tfr_attr)s - - .. deprecated:: 1.7 - Pass an instance of :class:`~mne.Epochs` as ``inst`` instead, or use - :class:`~mne.time_frequency.EpochsTFRArray` which retains the old API. %(tmin_tmax_psd)s %(picks_good_data_noref)s %(proj_psd)s @@ -3087,14 +3022,10 @@ class EpochsTFR(BaseTFR, GetEpochsMixin): def __init__( self, - info=None, - data=None, - times=None, - freqs=None, *, inst=None, + freqs=None, method=None, - comment=None, tmin=None, tmax=None, picks=None, @@ -3111,44 +3042,6 @@ def __init__( ): from ..epochs import BaseEpochs - # deprecations. TODO remove after 1.7 release - depr_params = dict(info=info, data=data, times=times, comment=comment) - bad_params = list() - for name, param in depr_params.items(): - if param is not None: - bad_params.append(name) - if len(bad_params): - _s = _pl(bad_params) - is_are = _pl(bad_params, "is", "are") - bad_params_list = '", "'.join(bad_params) - warn( - f'Parameter{_s} "{bad_params_list}" {is_are} deprecated and will be ' - "removed in version 1.8. For a quick fix, use ``EpochsTFRArray`` with " - "the same parameters. For a long-term fix, see the docstring notes.", - FutureWarning, - ) - if inst is not None: - raise ValueError( - "Do not pass `inst` alongside deprecated params " - f'"{bad_params_list}"; see docstring of AverageTFR for guidance.' - ) - # sensible defaults are created in __setstate__ so only pass these through - # if they're user-specified - optional = dict( - freqs=freqs, - method=method, - events=events, - event_id=event_id, - selection=selection, - drop_log=drop_log, - metadata=metadata, - ) - optional_params = { - key: val for key, val in optional.items() if val is not None - } - inst = depr_params | optional_params - # end TODO ↑↑↑↑↑↑ - # dict is allowed for __setstate__ compatibility _validate_type( inst, (BaseEpochs, dict), "object passed to EpochsTFR constructor", "Epochs" @@ -3448,8 +3341,6 @@ def plot( combine=None, layout=None, # TODO deprecate; not used in orig implementation yscale="auto", - vmin=None, - vmax=None, vlim=(None, None), cnorm=None, cmap=None, @@ -3477,8 +3368,6 @@ def plot( combine=combine, layout=layout, yscale=yscale, - vmin=vmin, - vmax=vmax, vlim=vlim, cnorm=cnorm, cmap=cmap, @@ -3563,8 +3452,6 @@ def plot_joint( mode="mean", dB=False, yscale="auto", - vmin=None, - vmax=None, vlim=(None, None), cnorm=None, cmap=None, @@ -3589,8 +3476,6 @@ def plot_joint( mode=mode, dB=dB, yscale=yscale, - vmin=vmin, - vmax=vmax, vlim=vlim, cnorm=cnorm, cmap=cmap, @@ -3988,7 +3873,7 @@ def _get_data(inst, return_itc): from ..epochs import BaseEpochs from ..evoked import Evoked - if not isinstance(inst, (BaseEpochs, Evoked)): + if not isinstance(inst, BaseEpochs | Evoked): raise TypeError("inst must be Epochs or Evoked") if isinstance(inst, BaseEpochs): data = inst.get_data(copy=False) @@ -4116,7 +4001,7 @@ def write_tfrs(fname, tfr, overwrite=False, *, verbose=None): """ # noqa E501 _, write_hdf5 = _import_h5io_funcs() out = [] - if not isinstance(tfr, (list, tuple)): + if not isinstance(tfr, list | tuple): tfr = [tfr] for ii, tfr_ in enumerate(tfr): comment = ii if getattr(tfr_, "comment", None) is None else tfr_.comment @@ -4329,17 +4214,3 @@ def _prep_data_for_plot( if dB: data = 10 * np.log10(data) return data, times, freqs - - -def _warn_deprecated_vmin_vmax(vlim, vmin, vmax): - if vmin is not None or vmax is not None: - warning = "Parameters `vmin` and `vmax` are deprecated, use `vlim` instead." - if vlim[0] is None and vlim[1] is None: - vlim = (vmin, vmax) - else: - warning += ( - " You've also provided a (non-default) value for `vlim`, " - "so `vmin` and `vmax` will be ignored." - ) - warn(warning, FutureWarning) - return vlim diff --git a/mne/transforms.py b/mne/transforms.py index 0f3201b2c17..024ff0073a4 100644 --- a/mne/transforms.py +++ b/mne/transforms.py @@ -1,8 +1,6 @@ """Helpers for various transformations.""" -# Authors: Alexandre Gramfort -# Christian Brodbeck -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -445,7 +443,7 @@ def _ensure_trans(trans, fro="mri", to="head"): to_const = to del to err_str = f"trans must be a Transform between {from_str}<->{to_str}, got" - if not isinstance(trans, (list, tuple)): + if not isinstance(trans, list | tuple): trans = [trans] # Ensure that we have exactly one match idx = list() @@ -1820,10 +1818,10 @@ def _compute_volume_registration( sigma_diff_vox = sigma_diff_mm / current_zoom affine_map = AffineMap( reg_affine, # apply registration here - static_zoomed.shape, - static_affine, - moving_zoomed.shape, - moving_affine, + domain_grid_shape=static_zoomed.shape, + domain_grid2world=static_affine, + codomain_grid_shape=moving_zoomed.shape, + codomain_grid2world=moving_affine, ) moving_zoomed = affine_map.transform(moving_zoomed) metric = metrics.CCMetric( @@ -1831,10 +1829,16 @@ def _compute_volume_registration( sigma_diff=sigma_diff_vox, radius=max(int(np.ceil(2 * sigma_diff_vox)), 1), ) - sdr = imwarp.SymmetricDiffeomorphicRegistration(metric, niter[step]) + sdr = imwarp.SymmetricDiffeomorphicRegistration( + metric, + level_iters=niter[step], + ) with wrapped_stdout(indent=" ", cull_newlines=True): sdr_morph = sdr.optimize( - static_zoomed, moving_zoomed, static_affine, static_affine + static_zoomed, + moving_zoomed, + static_grid2world=static_affine, + moving_grid2world=static_affine, ) moved_zoomed = sdr_morph.transform(moving_zoomed) else: @@ -1843,8 +1847,8 @@ def _compute_volume_registration( moved_zoomed, reg_affine = affine_registration( moving_zoomed, static_zoomed, - moving_affine, - static_affine, + moving_affine=moving_affine, + static_affine=static_affine, nbins=32, metric="MI", pipeline=pipeline_options[step], @@ -1938,7 +1942,11 @@ def apply_volume_registration( moving -= cval static, static_affine = np.asarray(static.dataobj), static.affine affine_map = AffineMap( - reg_affine, static.shape, static_affine, moving.shape, moving_affine + reg_affine, + domain_grid_shape=static.shape, + domain_grid2world=static_affine, + codomain_grid_shape=moving.shape, + codomain_grid2world=moving_affine, ) reg_data = affine_map.transform(moving, interpolation=interpolation) if sdr_morph is not None: @@ -2031,7 +2039,9 @@ def apply_volume_registration_points( if sdr_morph is not None: _require_version("dipy", "SDR morph", "1.6.0") locs = sdr_morph.transform_points( - locs, sdr_morph.domain_grid2world, sdr_morph.domain_world2grid + locs, + coord2world=sdr_morph.domain_grid2world, + world2coord=sdr_morph.domain_world2grid, ) locs = apply_trans( Transform( # to static voxels diff --git a/mne/utils/__init__.py b/mne/utils/__init__.py index bb4c2af7739..dbfedccd82b 100644 --- a/mne/utils/__init__.py +++ b/mne/utils/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import lazy_loader as lazy (__getattr__, __dir__, __all__) = lazy.attach_stub(__name__, __file__) diff --git a/mne/utils/_bunch.py b/mne/utils/_bunch.py index 5795be4ad5c..4fc5c454519 100644 --- a/mne/utils/_bunch.py +++ b/mne/utils/_bunch.py @@ -1,8 +1,6 @@ """Bunch-related classes.""" -# Authors: Alexandre Gramfort -# Eric Larson -# Joan Massich -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/_logging.py b/mne/utils/_logging.py index 02beae6224d..68963feaf61 100644 --- a/mne/utils/_logging.py +++ b/mne/utils/_logging.py @@ -1,6 +1,6 @@ """Some utility functions.""" -# Authors: Alexandre Gramfort -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -12,8 +12,9 @@ import re import sys import warnings +from collections.abc import Callable from io import StringIO -from typing import Any, Callable, TypeVar +from typing import Any, TypeVar from decorator import FunctionMaker @@ -290,7 +291,7 @@ def set_log_file(fname=None, output_format="%(message)s", overwrite=None): def _remove_close_handlers(logger): for h in list(logger.handlers): # only remove our handlers (get along nicely with nose) - if isinstance(h, (logging.FileHandler, logging.StreamHandler)): + if isinstance(h, logging.FileHandler | logging.StreamHandler): if isinstance(h, logging.FileHandler): h.close() logger.removeHandler(h) diff --git a/mne/utils/_testing.py b/mne/utils/_testing.py index 729769a2829..cdc65d7ce5c 100644 --- a/mne/utils/_testing.py +++ b/mne/utils/_testing.py @@ -1,6 +1,6 @@ """Testing functions.""" -# Authors: Alexandre Gramfort -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/_typing.py b/mne/utils/_typing.py index 5e4e9f57e6b..e1d5fdde107 100644 --- a/mne/utils/_typing.py +++ b/mne/utils/_typing.py @@ -1,5 +1,9 @@ """Shared objects used for type annotations.""" +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + import sys if sys.version_info >= (3, 11): diff --git a/mne/utils/check.py b/mne/utils/check.py index 4033abfa723..45df016746f 100644 --- a/mne/utils/check.py +++ b/mne/utils/check.py @@ -1,6 +1,6 @@ """The check functions.""" -# Authors: Alexandre Gramfort -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -167,7 +167,35 @@ def _import_h5py(): def _import_h5io_funcs(): h5io = _soft_import("h5io", "HDF5-based I/O") - return h5io.read_hdf5, h5io.write_hdf5 + + # Saving to HDF5 does not support pathlib.Path objects, which are more and more used + # in MNE-Python. + # Related issue in h5io: https://github.com/h5io/h5io/issues/113 + def cast_path_to_str(data: dict) -> dict: + """Cast all paths value to string in data.""" + keys2cast = [] + for key, value in data.items(): + if isinstance(value, dict): + cast_path_to_str(value) + if isinstance(value, Path): + data[key] = value.as_posix() + if isinstance(key, Path): + keys2cast.append(key) + for key in keys2cast: + data[key.as_posix()] = data.pop(key) + return data + + def write_hdf5(fname, data, *args, **kwargs): + """Write h5 and cast all paths to string in data.""" + if isinstance(data, dict): + data = cast_path_to_str(data) + elif isinstance(data, list): + for k, elt in enumerate(data): + if isinstance(elt, dict): + data[k] = cast_path_to_str(elt) + h5io.write_hdf5(fname, data, *args, **kwargs) + + return h5io.read_hdf5, write_hdf5 def _import_pymatreader_funcs(purpose): @@ -186,7 +214,7 @@ def check_random_state(seed): """ if seed is None or seed is np.random: return np.random.mtrand._rand - if isinstance(seed, (int, np.integer)): + if isinstance(seed, int | np.integer): return np.random.mtrand.RandomState(seed) if isinstance(seed, np.random.mtrand.RandomState): return seed @@ -309,7 +337,7 @@ def _check_preload(inst, msg): from ..time_frequency import BaseTFR from ..time_frequency.spectrum import BaseSpectrum - if isinstance(inst, (BaseTFR, Evoked, BaseSpectrum, _BaseSourceEstimate)): + if isinstance(inst, BaseTFR | Evoked | BaseSpectrum | _BaseSourceEstimate): pass else: name = "epochs" if isinstance(inst, BaseEpochs) else "raw" @@ -578,7 +606,7 @@ def _validate_type(item, types=None, item_name=None, type_name=None, *, extra="" elif types == "info": from .._fiff.meas_info import Info as types - if not isinstance(types, (list, tuple)): + if not isinstance(types, list | tuple): types = [types] check_types = sum( diff --git a/mne/utils/config.py b/mne/utils/config.py index 4bd25362fc2..8c0b827c9a6 100644 --- a/mne/utils/config.py +++ b/mne/utils/config.py @@ -1,6 +1,6 @@ """The config functions.""" -# Authors: Eric Larson -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -30,6 +30,10 @@ _temp_home_dir = None +class UnknownPlatformError(Exception): + """Exception raised for unknown platforms.""" + + def set_cache_dir(cache_dir): """Set the directory to be used for temporary file storage. @@ -605,12 +609,53 @@ def _get_gpu_info(): return out +def _get_total_memory(): + """Return the total memory of the system in bytes.""" + if platform.system() == "Windows": + o = subprocess.check_output( + [ + "powershell.exe", + "(Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory", + ] + ).decode() + total_memory = int(o) + elif platform.system() == "Linux": + o = subprocess.check_output(["free", "-b"]).decode() + total_memory = int(o.splitlines()[1].split()[1]) + elif platform.system() == "Darwin": + o = subprocess.check_output(["sysctl", "hw.memsize"]).decode() + total_memory = int(o.split(":")[1].strip()) + else: + raise UnknownPlatformError("Could not determine total memory") + + return total_memory + + +def _get_cpu_brand(): + """Return the CPU brand string.""" + if platform.system() == "Windows": + o = subprocess.check_output( + ["powershell.exe", "(Get-CimInstance Win32_Processor).Name"] + ).decode() + cpu_brand = o.strip().splitlines()[-1] + elif platform.system() == "Linux": + o = subprocess.check_output(["grep", "model name", "/proc/cpuinfo"]).decode() + cpu_brand = o.splitlines()[0].split(": ")[1] + elif platform.system() == "Darwin": + o = subprocess.check_output(["sysctl", "machdep.cpu"]).decode() + cpu_brand = o.split("brand_string: ")[1].strip() + else: + cpu_brand = "?" + + return cpu_brand + + def sys_info( fid=None, show_paths=False, *, dependencies="user", - unicode=True, + unicode="auto", check_version=True, ): """Print system information. @@ -627,8 +672,9 @@ def sys_info( dependencies : 'user' | 'developer' Show dependencies relevant for users (default) or for developers (i.e., output includes additional dependencies). - unicode : bool - Include Unicode symbols in output. + unicode : bool | "auto" + Include Unicode symbols in output. If "auto", corresponds to True on Linux and + macOS, and False on Windows. .. versionadded:: 0.24 check_version : bool | float @@ -641,6 +687,13 @@ def sys_info( _validate_type(dependencies, str) _check_option("dependencies", dependencies, ("user", "developer")) _validate_type(check_version, (bool, "numeric"), "check_version") + _validate_type(unicode, (bool, str), "unicode") + _check_option("unicode", unicode, ("auto", True, False)) + if unicode == "auto": + if platform.system() in ("Darwin", "Linux"): + unicode = True + else: # Windows + unicode = False ljust = 24 if dependencies == "developer" else 21 platform_str = platform.platform() @@ -648,15 +701,20 @@ def sys_info( out("Platform".ljust(ljust) + platform_str + "\n") out("Python".ljust(ljust) + str(sys.version).replace("\n", " ") + "\n") out("Executable".ljust(ljust) + sys.executable + "\n") - out("CPU".ljust(ljust) + f"{platform.processor()} ") + try: + cpu_brand = _get_cpu_brand() + except Exception: + cpu_brand = "?" + out("CPU".ljust(ljust) + f"{cpu_brand} ") out(f"({multiprocessing.cpu_count()} cores)\n") out("Memory".ljust(ljust)) try: - import psutil - except ImportError: - out('Unavailable (requires "psutil" package)') + total_memory = _get_total_memory() + except UnknownPlatformError: + total_memory = "?" else: - out(f"{psutil.virtual_memory().total / float(2 ** 30):0.1f} GB\n") + total_memory = f"{total_memory / 1024**3:.1f}" # convert to GiB + out(f"{total_memory} GiB\n") out("\n") ljust -= 3 # account for +/- symbols libs = _get_numpy_libs() diff --git a/mne/utils/dataframe.py b/mne/utils/dataframe.py index 95618c614fa..0511433001d 100644 --- a/mne/utils/dataframe.py +++ b/mne/utils/dataframe.py @@ -1,6 +1,6 @@ """inst.to_data_frame() helper functions.""" -# Authors: Daniel McCloy -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/docs.py b/mne/utils/docs.py index 57a0999fd1e..3e59d751d93 100644 --- a/mne/utils/docs.py +++ b/mne/utils/docs.py @@ -1,6 +1,6 @@ """The documentation functions.""" -# Authors: Eric Larson -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -3997,6 +3997,19 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): shape ``(n_eeg, 3)`` or ``(n_eeg, 4)``. """ +docdict["sensor_scales"] = """ +sensor_scales : int | float | array-like | dict | None + Scale to use for the sensor glyphs. Can be None (default) to use default scale. + A dict should provide the Scale (values) for each channel type (keys), e.g.:: + + dict(eeg=eeg_scales) + + Where the value (``eeg_scales`` above) can be broadcast to an array of values with + length that matches the number of channels of that type. A few examples of this + for the case above are the value ``10e-3``, a list of ``n_eeg`` values, or an NumPy + ndarray of shape ``(n_eeg,)``. +""" + docdict["sensors_topomap"] = """ sensors : bool | str Whether to add markers for sensor locations. If :class:`str`, should be a @@ -4921,14 +4934,6 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): ``min(data)`` or ``max(data)``, respectively.{extra} """ -docdict["vmin_vmax_tfr_plot"] = """ -vmin, vmax : float | None - Lower and upper bounds of the colormap. See ``vlim``. - - .. deprecated:: 1.7 - ``vmin`` and ``vmax`` will be removed in version 1.8. - Use ``vlim`` parameter instead. -""" # ↓↓↓ this one still used, needs helper func refactor before we can migrate to `vlim` docdict["vmin_vmax_tfr_plot_topo"] = _vmin_vmax_template.format( allowed="", bounds=_bounds_symmetric, extra="" diff --git a/mne/utils/fetching.py b/mne/utils/fetching.py index 2e4d39c59f8..548b4fbf2d0 100644 --- a/mne/utils/fetching.py +++ b/mne/utils/fetching.py @@ -1,6 +1,6 @@ """File downloading functions.""" -# Authors: Alexandre Gramfort -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/linalg.py b/mne/utils/linalg.py index 9bc2b927c10..4e4c9ba23c5 100644 --- a/mne/utils/linalg.py +++ b/mne/utils/linalg.py @@ -17,8 +17,8 @@ are Fortran contiguous because that's what LAPACK requires. Without this, inputs will be memcopied. """ -# Authors: Eric Larson -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/misc.py b/mne/utils/misc.py index 88a7d7f1f80..bbefaf0cecb 100644 --- a/mne/utils/misc.py +++ b/mne/utils/misc.py @@ -1,6 +1,6 @@ """Some miscellaneous utility functions.""" -# Authors: Alexandre Gramfort -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -43,7 +43,7 @@ def _empty_hash(kind="md5"): def _pl(x, non_pl="", pl="s"): """Determine if plural should be used.""" - len_x = x if isinstance(x, (int, np.generic)) else len(x) + len_x = x if isinstance(x, int | np.generic) else len(x) return non_pl if len_x == 1 else pl @@ -389,7 +389,7 @@ def _assert_no_instances(cls, when=""): and r is not locals() and not inspect.isframe(r) ): - if isinstance(r, (list, dict, tuple)): + if isinstance(r, list | dict | tuple): rep = f"len={len(r)}" r_ = gc.get_referrers(r) types = (_fullname(x) for x in r_) diff --git a/mne/utils/mixin.py b/mne/utils/mixin.py index 6a8c16e6daf..741636115e2 100644 --- a/mne/utils/mixin.py +++ b/mne/utils/mixin.py @@ -1,6 +1,6 @@ """Some utility functions.""" -# Authors: Alexandre Gramfort -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -66,7 +66,7 @@ def __hash__(self): if isinstance(self, Evoked): return object_hash(dict(info=self.info, data=self.data)) - elif isinstance(self, (BaseEpochs, BaseRaw)): + elif isinstance(self, BaseEpochs | BaseRaw): _check_preload(self, "Hashing ") return object_hash(dict(info=self.info, data=self._data)) else: @@ -153,7 +153,7 @@ def _item_to_select(self, item): # Convert string to indices if ( - isinstance(item, (list, tuple)) + isinstance(item, list | tuple) and len(item) > 0 and isinstance(item[0], str) ): @@ -213,7 +213,7 @@ def _getitem( drop_log = list(inst.drop_log) if reason is not None: _validate_type(reason, (list, tuple, str), "reason") - if isinstance(reason, (list, tuple)): + if isinstance(reason, list | tuple): for r in reason: _validate_type(r, str, r) if isinstance(reason, str): @@ -256,7 +256,7 @@ def _keys_to_idx(self, keys): """Find entries in event dict.""" from ..event import match_event_names # avoid circular import - keys = keys if isinstance(keys, (list, tuple)) else [keys] + keys = keys if isinstance(keys, list | tuple) else [keys] try: # Assume it's a condition name return np.where( @@ -749,7 +749,7 @@ def _update_first_last(self): from ..dipole import DipoleFixed from ..evoked import Evoked - if isinstance(self, (Evoked, DipoleFixed)): + if isinstance(self, Evoked | DipoleFixed): self.first = int(round(self.times[0] * self.info["sfreq"])) self.last = len(self.times) + self.first - 1 diff --git a/mne/utils/numerics.py b/mne/utils/numerics.py index 433c1eb6445..07ba9ff7f56 100644 --- a/mne/utils/numerics.py +++ b/mne/utils/numerics.py @@ -1,7 +1,6 @@ """Some utility functions.""" -# Authors: Alexandre Gramfort -# Clemens Brunner -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -637,10 +636,10 @@ def object_hash(x, h=None): elif isinstance(x, bytes): # must come before "str" below h.update(x) - elif isinstance(x, (str, float, int, type(None))): + elif isinstance(x, str | float | int | type(None)): h.update(str(type(x)).encode("utf-8")) h.update(str(x).encode("utf-8")) - elif isinstance(x, (np.ndarray, np.number, np.bool_)): + elif isinstance(x, np.ndarray | np.number | np.bool_): x = np.asarray(x) h.update(str(x.shape).encode("utf-8")) h.update(str(x.dtype).encode("utf-8")) @@ -649,7 +648,7 @@ def object_hash(x, h=None): object_hash(_dt_to_stamp(x)) elif sparse.issparse(x): h.update(str(type(x)).encode("utf-8")) - if not isinstance(x, (sparse.csr_array, sparse.csc_array)): + if not isinstance(x, sparse.csr_array | sparse.csc_array): raise RuntimeError(f"Unsupported sparse type {type(x)}") h.update(x.data.tobytes()) h.update(x.indices.tobytes()) @@ -688,7 +687,7 @@ def object_size(x, memo=None): id_ = id(x) if id_ in memo: return 0 # do not add already existing ones - if isinstance(x, (bytes, str, int, float, type(None), Path)): + if isinstance(x, bytes | str | int | float | type(None) | Path): size = sys.getsizeof(x) elif isinstance(x, np.ndarray): # On newer versions of NumPy, just doing sys.getsizeof(x) works, @@ -703,7 +702,7 @@ def object_size(x, memo=None): for key, value in x.items(): size += object_size(key, memo) size += object_size(value, memo) - elif isinstance(x, (list, tuple)): + elif isinstance(x, list | tuple): size = sys.getsizeof(x) + sum(object_size(xx, memo) for xx in x) elif isinstance(x, datetime): size = object_size(_dt_to_stamp(x), memo) @@ -719,7 +718,7 @@ def object_size(x, memo=None): def _is_sparse_cs(x): return isinstance( - x, (sparse.csr_matrix, sparse.csc_matrix, sparse.csr_array, sparse.csc_array) + x, sparse.csr_matrix | sparse.csc_matrix | sparse.csr_array | sparse.csc_array ) @@ -788,7 +787,7 @@ def object_diff(a, b, pre="", *, allclose=False): out += object_diff( a[key], b[key], pre=(pre + f"[{repr(key)}]"), allclose=allclose ) - elif isinstance(a, (list, tuple)): + elif isinstance(a, list | tuple): if len(a) != len(b): out += pre + f" length mismatch ({len(a)}, {len(b)})\n" else: @@ -797,7 +796,7 @@ def object_diff(a, b, pre="", *, allclose=False): elif isinstance(a, float): if not _array_equal_nan(a, b, allclose): out += pre + f" value mismatch ({a}, {b})\n" - elif isinstance(a, (str, int, bytes, np.generic)): + elif isinstance(a, str | int | bytes | np.generic): if a != b: out += pre + f" value mismatch ({a}, {b})\n" elif a is None: @@ -806,10 +805,10 @@ def object_diff(a, b, pre="", *, allclose=False): elif isinstance(a, np.ndarray): if not _array_equal_nan(a, b, allclose): out += pre + " array mismatch\n" - elif isinstance(a, (StringIO, BytesIO)): + elif isinstance(a, StringIO | BytesIO): if a.getvalue() != b.getvalue(): out += pre + " StringIO mismatch\n" - elif isinstance(a, (datetime, date)): + elif isinstance(a, datetime | date): if (a - b).total_seconds() != 0: out += pre + f" {a.__class__.__name__} mismatch\n" elif sparse.issparse(a): @@ -878,7 +877,7 @@ def _fit(self, X): "svd_solver='full'" ) elif n_components >= 1: - if not isinstance(n_components, (numbers.Integral, np.integer)): + if not isinstance(n_components, numbers.Integral | np.integer): raise ValueError( f"n_components={repr(n_components)} must be of type int " f"when greater than or equal to 1, " diff --git a/mne/utils/progressbar.py b/mne/utils/progressbar.py index b8b4e6722ff..4ada836ade7 100644 --- a/mne/utils/progressbar.py +++ b/mne/utils/progressbar.py @@ -1,6 +1,6 @@ """Some utility functions.""" -# Authors: Alexandre Gramfort -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/spectrum.py b/mne/utils/spectrum.py index 4425616f93d..69052f21797 100644 --- a/mne/utils/spectrum.py +++ b/mne/utils/spectrum.py @@ -1,7 +1,9 @@ """Utility functions for spectral and spectrotemporal analysis.""" +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from inspect import currentframe, getargvalues, signature from ..utils import warn diff --git a/mne/utils/tests/test_bunch.py b/mne/utils/tests/test_bunch.py index 683d8467238..360edd2f152 100644 --- a/mne/utils/tests/test_bunch.py +++ b/mne/utils/tests/test_bunch.py @@ -1,6 +1,4 @@ -# Authors: Clemens Brunner -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/tests/test_check.py b/mne/utils/tests/test_check.py index 4ec7450df99..4b519198e39 100644 --- a/mne/utils/tests/test_check.py +++ b/mne/utils/tests/test_check.py @@ -1,7 +1,6 @@ """Test check utilities.""" -# Authors: MNE Developers -# Stefan Appelhoff -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/tests/test_config.py b/mne/utils/tests/test_config.py index 0706e84996c..e7611081b55 100644 --- a/mne/utils/tests/test_config.py +++ b/mne/utils/tests/test_config.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os import platform import re @@ -108,7 +110,7 @@ def test_sys_info_basic(): assert "numpy" in out # replace all in-line whitespace with single space out = "\n".join(" ".join(o.split()) for o in out.splitlines()) - + assert "? GiB" not in out if platform.system() == "Darwin": assert "Platform macOS-" in out elif platform.system() == "Linux": diff --git a/mne/utils/tests/test_docs.py b/mne/utils/tests/test_docs.py index c5ab49d3167..64ebc2c6916 100644 --- a/mne/utils/tests/test_docs.py +++ b/mne/utils/tests/test_docs.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import webbrowser import pytest diff --git a/mne/utils/tests/test_linalg.py b/mne/utils/tests/test_linalg.py index 03050b29f03..a5c542e3894 100644 --- a/mne/utils/tests/test_linalg.py +++ b/mne/utils/tests/test_linalg.py @@ -1,6 +1,6 @@ """Test linalg utilities.""" -# Authors: Britta Westner -# + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/tests/test_logging.py b/mne/utils/tests/test_logging.py index 4343b9d22de..8060ed1a398 100644 --- a/mne/utils/tests/test_logging.py +++ b/mne/utils/tests/test_logging.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import logging import os import re diff --git a/mne/utils/tests/test_misc.py b/mne/utils/tests/test_misc.py index 2ea08baadc1..c3bc63dea76 100644 --- a/mne/utils/tests/test_misc.py +++ b/mne/utils/tests/test_misc.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os import subprocess import sys diff --git a/mne/utils/tests/test_mixin.py b/mne/utils/tests/test_mixin.py index b208335fada..7ac54294b89 100644 --- a/mne/utils/tests/test_mixin.py +++ b/mne/utils/tests/test_mixin.py @@ -1,5 +1,4 @@ -# Author: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/tests/test_numerics.py b/mne/utils/tests/test_numerics.py index 3c1eadf74cd..0786ac068a6 100644 --- a/mne/utils/tests/test_numerics.py +++ b/mne/utils/tests/test_numerics.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from copy import deepcopy from datetime import date from io import StringIO diff --git a/mne/utils/tests/test_progressbar.py b/mne/utils/tests/test_progressbar.py index 92d2d37cfc3..58c052f0415 100644 --- a/mne/utils/tests/test_progressbar.py +++ b/mne/utils/tests/test_progressbar.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/utils/tests/test_testing.py b/mne/utils/tests/test_testing.py index 02791ffc3d8..ab6b0a6fdd7 100644 --- a/mne/utils/tests/test_testing.py +++ b/mne/utils/tests/test_testing.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/_3d.py b/mne/viz/_3d.py index 099b6a84e32..7dbabfa1ef6 100644 --- a/mne/viz/_3d.py +++ b/mne/viz/_3d.py @@ -1,12 +1,6 @@ """Functions to make 3D plots with M/EEG data.""" -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Mainak Jas -# Mark Wronkiewicz -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -195,7 +189,7 @@ def plot_head_positions( destination = destination["trans"][:3].copy() destination[:, 3] *= 1000 - if not isinstance(pos, (list, tuple)): + if not isinstance(pos, list | tuple): pos = [pos] pos = list(pos) # make our own mutable copy for ii, p in enumerate(pos): @@ -532,6 +526,8 @@ def plot_alignment( fig=None, interaction="terrain", sensor_colors=None, + *, + sensor_scales=None, verbose=None, ): """Plot head, sensor, and source space alignment in 3D. @@ -623,6 +619,9 @@ def plot_alignment( .. versionchanged:: 1.6 Support for passing a ``dict`` was added. + %(sensor_scales)s + + .. versionadded:: 1.9 %(verbose)s Returns @@ -912,6 +911,7 @@ def plot_alignment( "m", sensor_alpha=sensor_alpha, sensor_colors=sensor_colors, + sensor_scales=sensor_scales, ) if src is not None: @@ -1216,7 +1216,7 @@ def _plot_mri_fiducials( mri_fiducials = subjects_dir / subject / "bem" / (subject + "-fiducials.fif") if isinstance(mri_fiducials, str) and mri_fiducials == "estimated": mri_fiducials = get_mni_fiducials(subject, subjects_dir) - elif isinstance(mri_fiducials, (str, Path, os.PathLike)): + elif isinstance(mri_fiducials, str | Path | os.PathLike): mri_fiducials, cf = read_fiducials(mri_fiducials) if cf != FIFF.FIFFV_COORD_MRI: raise ValueError("Fiducials are not in MRI space") @@ -1486,6 +1486,7 @@ def _plot_sensors_3d( check_inside=None, nearest=None, sensor_colors=None, + sensor_scales=None, ): """Render sensors in a 3D scene.""" from matplotlib.colors import to_rgba_array @@ -1541,23 +1542,44 @@ def _plot_sensors_3d( sensor_colors = { list(locs)[0]: to_rgba_array(sensor_colors), } + if sensor_scales is not None and not isinstance(sensor_scales, dict): + sensor_scales = { + list(locs)[0]: sensor_scales, + } else: extra = f"when more than one channel type ({list(locs)}) is plotted" _validate_type(sensor_colors, types, "sensor_colors", extra=extra) + _validate_type(sensor_scales, types, "sensor_scales", extra=extra) del extra, types if sensor_colors is None: sensor_colors = dict() + if sensor_scales is None: + sensor_scales = dict() assert isinstance(sensor_colors, dict) + assert isinstance(sensor_scales, dict) for ch_type, sens_loc in locs.items(): logger.debug(f"Drawing {ch_type} sensors") assert len(sens_loc) # should be guaranteed above colors = to_rgba_array(sensor_colors.get(ch_type, defaults[ch_type + "_color"])) + scales = np.atleast_1d( + sensor_scales.get(ch_type, defaults[ch_type + "_scale"] * unit_scalar) + ) _check_option( f"len(sensor_colors[{repr(ch_type)}])", colors.shape[0], (len(sens_loc), 1), ) - scale = defaults[ch_type + "_scale"] * unit_scalar + _check_option( + f"len(sensor_scales[{repr(ch_type)}])", + scales.shape[0], + (len(sens_loc), 1), + ) + # Check that the scale is numerical + assert np.issubdtype(scales.dtype, np.number), ( + f"scales for {ch_type} must contain only numerical values, " + f"got {scales} instead." + ) + this_alpha = sensor_alpha[ch_type] if isinstance(sens_loc[0], dict): # meg coil if len(colors) == 1: @@ -1573,13 +1595,13 @@ def _plot_sensors_3d( else: sens_loc = np.array(sens_loc, float) mask = ~np.isnan(sens_loc).any(axis=1) - if len(colors) == 1: + if len(colors) == 1 and len(scales) == 1: # Single color mode (one actor) actor, _ = _plot_glyphs( renderer=renderer, loc=sens_loc[mask] * unit_scalar, color=colors[0, :3], - scale=scale, + scale=scales[0], opacity=this_alpha * colors[0, 3], orient_glyphs=orient_glyphs, scale_by_distance=scale_by_distance, @@ -1589,9 +1611,47 @@ def _plot_sensors_3d( nearest=nearest, ) actors[ch_type].append(actor) - else: - # Multi-color mode (multiple actors) + elif len(colors) == len(sens_loc) and len(scales) == 1: + # Multi-color single scale mode (multiple actors) for loc, color, usable in zip(sens_loc, colors, mask): + if not usable: + continue + actor, _ = _plot_glyphs( + renderer=renderer, + loc=loc * unit_scalar, + color=color[:3], + scale=scales[0], + opacity=this_alpha * color[3], + orient_glyphs=orient_glyphs, + scale_by_distance=scale_by_distance, + project_points=project_points, + surf=surf, + check_inside=check_inside, + nearest=nearest, + ) + actors[ch_type].append(actor) + elif len(colors) == 1 and len(scales) == len(sens_loc): + # Multi-scale single color mode (multiple actors) + for loc, scale, usable in zip(sens_loc, scales, mask): + if not usable: + continue + actor, _ = _plot_glyphs( + renderer=renderer, + loc=loc * unit_scalar, + color=colors[0, :3], + scale=scale, + opacity=this_alpha * colors[0, 3], + orient_glyphs=orient_glyphs, + scale_by_distance=scale_by_distance, + project_points=project_points, + surf=surf, + check_inside=check_inside, + nearest=nearest, + ) + actors[ch_type].append(actor) + else: + # Multi-color multi-scale mode (multiple actors) + for loc, color, scale, usable in zip(sens_loc, colors, scales, mask): if not usable: continue actor, _ = _plot_glyphs( @@ -3402,7 +3462,7 @@ def plot_sparse_source_estimates( ] known_modes = ["cone", "sphere"] - if not isinstance(modes, (list, tuple)) or not all( + if not isinstance(modes, list | tuple) or not all( mode in known_modes for mode in modes ): raise ValueError('mode must be a list containing only "cone" or "sphere"') @@ -3481,7 +3541,7 @@ def plot_sparse_source_estimates( mode = modes[1] if is_common else modes[0] scale_factor = scale_factors[1] if is_common else scale_factors[0] - if isinstance(scale_factor, (np.ndarray, list, tuple)) and len( + if isinstance(scale_factor, np.ndarray | list | tuple) and len( unique_vertnos ) == len(scale_factor): scale_factor = scale_factor[idx] diff --git a/mne/viz/_3d_overlay.py b/mne/viz/_3d_overlay.py index 203cb686360..3ebc308c127 100644 --- a/mne/viz/_3d_overlay.py +++ b/mne/viz/_3d_overlay.py @@ -1,8 +1,6 @@ """Classes to handle overlapping surfaces.""" -# Authors: Guillaume Favelier -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/__init__.py b/mne/viz/__init__.py index 4fea8fd82c9..ae043dc12ab 100644 --- a/mne/viz/__init__.py +++ b/mne/viz/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Visualization routines.""" import lazy_loader as lazy diff --git a/mne/viz/_brain/__init__.py b/mne/viz/_brain/__init__.py index b65f65c7757..7638c65a11d 100644 --- a/mne/viz/_brain/__init__.py +++ b/mne/viz/_brain/__init__.py @@ -1,12 +1,6 @@ """Plot Cortex Surface.""" -# Authors: Alexandre Gramfort -# Eric Larson -# Oleh Kozynets -# Guillaume Favelier -# jona-sassenhagen -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/_brain/_brain.py b/mne/viz/_brain/_brain.py index de37c26ea1c..247c0840858 100644 --- a/mne/viz/_brain/_brain.py +++ b/mne/viz/_brain/_brain.py @@ -1,10 +1,4 @@ -# Authors: Alexandre Gramfort -# Eric Larson -# Oleh Kozynets -# Guillaume Favelier -# jona-sassenhagen -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -163,8 +157,6 @@ class Brain: .. versionchanged:: 0.23 Default changed to "auto". - offscreen : bool - Deprecated and will be removed in 1.9, do not use. interaction : str Can be "trackball" (default) or "terrain", i.e. a turntable-style camera. @@ -179,9 +171,6 @@ class Brain: %(theme_3d)s show : bool Display the window as soon as it is ready. Defaults to True. - block : bool - Deprecated and will be removed in 1.9, do not use. Consider using - :func:`matplotlib.pyplot.show` with ``block=True`` instead. Attributes ---------- @@ -298,25 +287,17 @@ def __init__( views="auto", *, offset="auto", - offscreen=None, interaction="trackball", units="mm", view_layout="vertical", silhouette=False, theme=None, show=True, - block=None, ): from ..backends.renderer import _get_renderer, backend _validate_type(subject, str, "subject") self._surf = surf - if offscreen is not None: - warn( - "The 'offscreen' parameter is deprecated and will be removed in 1.9. " - "as it has no effect", - FutureWarning, - ) if hemi is None: hemi = "vol" hemi = self._check_hemi(hemi, extras=("both", "split", "vol")) @@ -358,15 +339,9 @@ def __init__( subjects_dir = get_subjects_dir(subjects_dir) if subjects_dir is not None: subjects_dir = str(subjects_dir) - if block is not None: - warn( - "block is deprecated and will be removed in 1.9, use " - "plt.show(block=True) instead" - ) self.time_viewer = False self._hash = time.time_ns() - self._block = block self._hemi = hemi self._units = units self._alpha = float(alpha) @@ -535,8 +510,6 @@ def setup_time_viewer(self, time_viewer=True, show_traces=True): 'Left': Decrease camera azimuth angle 'Right': Increase camera azimuth angle """ - from ..backends._utils import _qt_app_exec - if self.time_viewer: return if not self._data: @@ -624,8 +597,6 @@ def setup_time_viewer(self, time_viewer=True, show_traces=True): # finally, show the MplCanvas if self.show_traces: self.mpl_canvas.show() - if self._block: - _qt_app_exec(self._renderer.figure.store["app"]) @safe_event def _clean(self): @@ -1676,7 +1647,7 @@ def _cortex_colormap(self, cortex): cortex = colormap_map[cortex] else: cortex = [cortex] * 2 - if isinstance(cortex, (list, tuple)): + if isinstance(cortex, list | tuple): _check_option( "len(cortex)", len(cortex), @@ -2391,7 +2362,7 @@ def add_dipole(self, dipole, trans, colors="red", alpha=1, scales=None): head_mri_t = _get_trans(trans, "head", "mri", allow_none=False)[0] del trans n_dipoles = len(dipole) - if not isinstance(colors, (list, tuple)): + if not isinstance(colors, list | tuple): colors = [colors] * n_dipoles # make into list if len(colors) != n_dipoles: raise ValueError( @@ -2403,7 +2374,7 @@ def add_dipole(self, dipole, trans, colors="red", alpha=1, scales=None): ] if scales is None: scales = 5 if self._units == "mm" else 5e-3 - if not isinstance(scales, (list, tuple)): + if not isinstance(scales, list | tuple): scales = [scales] * n_dipoles # make into list if len(scales) != n_dipoles: raise ValueError( @@ -2572,7 +2543,7 @@ def add_volume_labels( if colors is None: colors = [fs_colors[label] / 255 for label in labels] - elif not isinstance(colors, (list, tuple)): + elif not isinstance(colors, list | tuple): colors = [colors] * len(labels) # make into list colors = [ _to_rgb(color, name=f"colors[{ci}]") for ci, color in enumerate(colors) @@ -2719,6 +2690,7 @@ def add_sensors( max_dist=0.004, *, sensor_colors=None, + sensor_scales=None, verbose=None, ): """Add mesh objects to represent sensor positions. @@ -2737,6 +2709,9 @@ def add_sensors( %(sensor_colors)s .. versionadded:: 1.6 + %(sensor_scales)s + + .. versionadded:: 1.9 %(verbose)s Notes @@ -2793,6 +2768,7 @@ def add_sensors( self._units, sensor_alpha=sensor_alpha, sensor_colors=sensor_colors, + sensor_scales=sensor_scales, ) # sensors_actors can still be None for item, actors in (sensors_actors or {}).items(): @@ -3073,11 +3049,7 @@ def close(self): def show(self): """Display the window.""" - from ..backends._utils import _qt_app_exec - self._renderer.show() - if self._block: - _qt_app_exec(self._renderer.figure.store["app"]) @fill_doc def get_view(self, row=0, col=0, *, align=True): @@ -4026,7 +3998,7 @@ def _check_hemis(self, hemi): def _to_borders(self, label, hemi, borders, restrict_idx=None): """Convert a label/parc to borders.""" - if not isinstance(borders, (bool, int)) or borders < 0: + if not isinstance(borders, bool | int) or borders < 0: raise ValueError("borders must be a bool or positive integer") if borders: n_vertices = label.size diff --git a/mne/viz/_brain/_linkviewer.py b/mne/viz/_brain/_linkviewer.py index ba7140aa9a6..e61a4b1c75b 100644 --- a/mne/viz/_brain/_linkviewer.py +++ b/mne/viz/_brain/_linkviewer.py @@ -1,9 +1,7 @@ -# Authors: Alexandre Gramfort -# Eric Larson -# Guillaume Favelier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import numpy as np from ...utils import warn diff --git a/mne/viz/_brain/_scraper.py b/mne/viz/_brain/_scraper.py index 41d79ef79ef..931caaaa0e8 100644 --- a/mne/viz/_brain/_scraper.py +++ b/mne/viz/_brain/_scraper.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os import os.path as op diff --git a/mne/viz/_brain/colormap.py b/mne/viz/_brain/colormap.py index 31c42456995..2bdb71ab609 100644 --- a/mne/viz/_brain/colormap.py +++ b/mne/viz/_brain/colormap.py @@ -1,8 +1,4 @@ -# Authors: Alexandre Gramfort -# Eric Larson -# Oleh Kozynets -# Guillaume Favelier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/_brain/surface.py b/mne/viz/_brain/surface.py index 884045888d9..d4ee918b9b1 100644 --- a/mne/viz/_brain/surface.py +++ b/mne/viz/_brain/surface.py @@ -1,9 +1,4 @@ -# Authors: Alexandre Gramfort -# Eric Larson -# Oleh Kozynets -# Guillaume Favelier -# jona-sassenhagen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/_brain/tests/test_brain.py b/mne/viz/_brain/tests/test_brain.py index e22d906af6e..2a1c943250b 100644 --- a/mne/viz/_brain/tests/test_brain.py +++ b/mne/viz/_brain/tests/test_brain.py @@ -1,15 +1,11 @@ # -# Authors: Alexandre Gramfort -# Eric Larson -# Joan Massich -# Guillaume Favelier -# Oleh Kozynets -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import os import platform +from contextlib import nullcontext from pathlib import Path from shutil import copyfile @@ -549,6 +545,116 @@ def __init__(self): brain.close() +# TODO: Figure out why brain_gc is problematic here on PyQt5 +@pytest.mark.allow_unclosed +@testing.requires_testing_data +@pytest.mark.parametrize( + "sensor_colors, sensor_scales, expectation", + [ + ( + {"seeg": ["k"] * 5}, + {"seeg": [2] * 6}, + pytest.raises( + ValueError, + match=r"Invalid value for the 'len\(sensor_colors\['seeg'\]\)' " + r"parameter. Allowed values are \d+ and \d+, but got \d+ instead", + ), + ), + ( + {"seeg": ["k"] * 6}, + {"seeg": [2] * 5}, + pytest.raises( + ValueError, + match=r"Invalid value for the 'len\(sensor_scales\['seeg'\]\)' " + r"parameter. Allowed values are \d+ and \d+, but got \d+ instead", + ), + ), + ( + "NotAColor", + 2, + pytest.raises( + ValueError, + match=r".* is not a valid color value", + ), + ), + ( + "k", + "k", + pytest.raises( + AssertionError, + match=r"scales for .* must contain only numerical values, got .* " + r"instead.", + ), + ), + ( + "k", + 2, + nullcontext(), + ), + ( + ["k"] * 6, + [2] * 6, + nullcontext(), + ), + ( + {"seeg": ["k"] * 6}, + {"seeg": [2] * 6}, + nullcontext(), + ), + ], +) +def test_add_sensors_scales( + renderer_interactive_pyvistaqt, + sensor_colors, + sensor_scales, + expectation, +): + """Test sensor_scales parameter.""" + kwargs = dict(subject=subject, subjects_dir=subjects_dir) + hemi = "lh" + surf = "white" + cortex = "low_contrast" + title = "test" + size = (300, 300) + + brain = Brain( + hemi=hemi, + surf=surf, + size=size, + title=title, + cortex=cortex, + units="m", + silhouette=dict(decimate=0.95), + **kwargs, + ) + + proj_info = create_info([f"Ch{i}" for i in range(1, 7)], 1000, "seeg") + pos = ( + np.array( + [ + [25.85, 9.04, -5.38], + [33.56, 9.04, -5.63], + [40.44, 9.04, -5.06], + [46.75, 9.04, -6.78], + [-30.08, 9.04, 28.23], + [-32.95, 9.04, 37.99], + ] + ) + / 1000 + ) + proj_info.set_montage( + make_dig_montage(ch_pos=dict(zip(proj_info.ch_names, pos)), coord_frame="head") + ) + with expectation: + brain.add_sensors( + proj_info, + trans=fname_trans, + sensor_colors=sensor_colors, + sensor_scales=sensor_scales, + ) + brain.close() + + def _assert_view_allclose( brain, roll, diff --git a/mne/viz/_brain/tests/test_notebook.py b/mne/viz/_brain/tests/test_notebook.py index 0fd253357f8..0f856724c77 100644 --- a/mne/viz/_brain/tests/test_notebook.py +++ b/mne/viz/_brain/tests/test_notebook.py @@ -1,5 +1,4 @@ -# Authors: Guillaume Favelier -# Eric Larson +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/_brain/view.py b/mne/viz/_brain/view.py index dfef3605097..1550c3868fb 100644 --- a/mne/viz/_brain/view.py +++ b/mne/viz/_brain/view.py @@ -1,9 +1,4 @@ -# Authors: Alexandre Gramfort -# Eric Larson -# Oleh Kozynets -# Guillaume Favelier -# jona-sassenhagen -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/_dipole.py b/mne/viz/_dipole.py index c22340aa220..ffcc898becd 100644 --- a/mne/viz/_dipole.py +++ b/mne/viz/_dipole.py @@ -1,7 +1,6 @@ """Dipole viz specific functions.""" -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/_figure.py b/mne/viz/_figure.py index de5284f10a3..ffb1c57dafd 100644 --- a/mne/viz/_figure.py +++ b/mne/viz/_figure.py @@ -1,10 +1,9 @@ """Base classes and functions for 2D browser backends.""" -# Authors: Daniel McCloy -# Martin Schulz -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import importlib from abc import ABC, abstractmethod from collections import OrderedDict diff --git a/mne/viz/_mpl_figure.py b/mne/viz/_mpl_figure.py index 36f19ee5fa8..2e552bd4012 100644 --- a/mne/viz/_mpl_figure.py +++ b/mne/viz/_mpl_figure.py @@ -31,8 +31,7 @@ - evoked.plot_joint() TODO Not yet implemented """ -# Authors: Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/_proj.py b/mne/viz/_proj.py index 011efd4b066..5d21afb0594 100644 --- a/mne/viz/_proj.py +++ b/mne/viz/_proj.py @@ -1,7 +1,6 @@ """Functions for plotting projectors.""" -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/_scraper.py b/mne/viz/_scraper.py index 01be6c312f1..a6b74106b30 100644 --- a/mne/viz/_scraper.py +++ b/mne/viz/_scraper.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/backends/__init__.py b/mne/viz/backends/__init__.py index 5e05db0bc2e..334dc5bb678 100644 --- a/mne/viz/backends/__init__.py +++ b/mne/viz/backends/__init__.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Visualization backend.""" from . import renderer diff --git a/mne/viz/backends/_abstract.py b/mne/viz/backends/_abstract.py index c31023401ed..b17927688f4 100644 --- a/mne/viz/backends/_abstract.py +++ b/mne/viz/backends/_abstract.py @@ -1,9 +1,6 @@ """ABCs.""" -# Authors: Guillaume Favelier -# Alex Rockhill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/backends/_notebook.py b/mne/viz/backends/_notebook.py index 4601ef1fc6a..1bfba915ce0 100644 --- a/mne/viz/backends/_notebook.py +++ b/mne/viz/backends/_notebook.py @@ -1,8 +1,6 @@ """Notebook implementation of _Renderer and GUI.""" -# Authors: Guillaume Favelier -# Alex Rockhill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/backends/_pyvista.py b/mne/viz/backends/_pyvista.py index 4f395344f41..2f27df4bd45 100644 --- a/mne/viz/backends/_pyvista.py +++ b/mne/viz/backends/_pyvista.py @@ -4,11 +4,7 @@ Actual implementation of _Renderer and _Projection classes. """ -# Authors: Alexandre Gramfort -# Eric Larson -# Guillaume Favelier -# Joan Massich -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index 6e59c2b6c20..110c0552e94 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -1,9 +1,6 @@ """Qt implementation of _Renderer and GUI.""" -# Authors: Guillaume Favelier -# Eric Larson -# Alex Rockhill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1657,7 +1654,7 @@ def set_value(self, idx, value): class _QtWidget(_AbstractWdgt): def set_value(self, value): - if isinstance(self._widget, (QRadioButton, QToolButton, QPushButton)): + if isinstance(self._widget, QRadioButton | QToolButton | QPushButton): self._widget.click() else: if hasattr(self._widget, "setValue"): diff --git a/mne/viz/backends/_utils.py b/mne/viz/backends/_utils.py index 25e87fcff22..c415d83e456 100644 --- a/mne/viz/backends/_utils.py +++ b/mne/viz/backends/_utils.py @@ -1,11 +1,8 @@ # -# Authors: Alexandre Gramfort -# Eric Larson -# Joan Massich -# Guillaume Favelier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import collections.abc import functools import os diff --git a/mne/viz/backends/renderer.py b/mne/viz/backends/renderer.py index 22ad863a38b..f13aeabc441 100644 --- a/mne/viz/backends/renderer.py +++ b/mne/viz/backends/renderer.py @@ -1,10 +1,6 @@ """Core visualization operations.""" -# Authors: Alexandre Gramfort -# Eric Larson -# Joan Massich -# Guillaume Favelier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/backends/tests/_utils.py b/mne/viz/backends/tests/_utils.py index e45ccc5ba1f..5e668a4dc75 100644 --- a/mne/viz/backends/tests/_utils.py +++ b/mne/viz/backends/tests/_utils.py @@ -1,8 +1,4 @@ -# Authors: Alexandre Gramfort -# Eric Larson -# Joan Massich -# Guillaume Favelier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/backends/tests/test_abstract.py b/mne/viz/backends/tests/test_abstract.py index f12e615d0d7..bfb3663146a 100644 --- a/mne/viz/backends/tests/test_abstract.py +++ b/mne/viz/backends/tests/test_abstract.py @@ -1,5 +1,4 @@ -# Authors: Alex Rockhill -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/backends/tests/test_renderer.py b/mne/viz/backends/tests/test_renderer.py index b20bb6e4865..a52942c804b 100644 --- a/mne/viz/backends/tests/test_renderer.py +++ b/mne/viz/backends/tests/test_renderer.py @@ -1,8 +1,4 @@ -# Authors: Alexandre Gramfort -# Eric Larson -# Joan Massich -# Guillaume Favelier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/backends/tests/test_utils.py b/mne/viz/backends/tests/test_utils.py index 26636004026..add488ad537 100644 --- a/mne/viz/backends/tests/test_utils.py +++ b/mne/viz/backends/tests/test_utils.py @@ -1,8 +1,4 @@ -# Authors: Alexandre Gramfort -# Eric Larson -# Joan Massich -# Guillaume Favelier -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/circle.py b/mne/viz/circle.py index 47b94953aa8..fdcbd5a26bb 100644 --- a/mne/viz/circle.py +++ b/mne/viz/circle.py @@ -1,9 +1,6 @@ """Functions to plot on circle as for connectivity.""" -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/conftest.py b/mne/viz/conftest.py index 66c7f2be7c8..ae953e5e2d2 100644 --- a/mne/viz/conftest.py +++ b/mne/viz/conftest.py @@ -1,7 +1,4 @@ -# Authors: Robert Luke -# Eric Larson -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/epochs.py b/mne/viz/epochs.py index 6b927c9ba7f..c691915f132 100644 --- a/mne/viz/epochs.py +++ b/mne/viz/epochs.py @@ -1,14 +1,6 @@ """Functions to plot epochs data.""" -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Jaakko Leppakangas -# Jona Sassenhagen -# Stefan Repplinger -# Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/evoked.py b/mne/viz/evoked.py index 05ad966264d..0343a5b7d62 100644 --- a/mne/viz/evoked.py +++ b/mne/viz/evoked.py @@ -1,13 +1,6 @@ """Functions to plot evoked M/EEG data (besides topographies).""" -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Cathy Nangini -# Mainak Jas -# Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -676,7 +669,7 @@ def _plot_lines( ) bad_color = (0.5, 0.5, 0.5) else: - if isinstance(_spat_col, (tuple, str)): + if isinstance(_spat_col, tuple | str): col = [_spat_col] else: col = ["k"] @@ -1245,7 +1238,7 @@ def plot_evoked_topo( axis_facecolor = background_color font_color = "k" - if isinstance(color, (tuple, list)): + if isinstance(color, tuple | list): if len(color) != len(evoked): raise ValueError( "Lists of evoked objects and colors must have the same length" @@ -1559,7 +1552,7 @@ def plot_evoked_white( time_unit, times = _check_time_unit(time_unit, evoked.times) _validate_type(noise_cov, (list, tuple, Covariance, "path-like")) - if not isinstance(noise_cov, (list, tuple)): + if not isinstance(noise_cov, list | tuple): noise_cov = [noise_cov] for ci, c in enumerate(noise_cov): noise_cov[ci] = _ensure_cov(noise_cov[ci], f"noise_cov[{ci}]", verbose=False) @@ -1998,7 +1991,7 @@ def plot_evoked_joint( norm = ch_type == "grad" vmin = 0 if norm else vmin vmin, vmax = _setup_vmin_vmax(evoked.data, vmin, vmax, norm) - if not isinstance(contours, (list, np.ndarray)): + if not isinstance(contours, list | np.ndarray): locator, contours = _set_contour_locator(vmin, vmax, contours) else: locator = None @@ -2016,7 +2009,7 @@ def plot_evoked_joint( cbar = fig.colorbar(map_ax[0].images[0], ax=map_ax, cax=cbar_ax, shrink=0.8) cbar.ax.grid(False) # auto-removal deprecated as of 2021/10/05 - if isinstance(contours, (list, np.ndarray)): + if isinstance(contours, list | np.ndarray): cbar.set_ticks(contours) else: if locator is None: @@ -2062,7 +2055,7 @@ def plot_evoked_joint( def _check_loc_legal(loc, what="your choice", default=1): """Check if loc is a legal location for MPL subordinate axes.""" true_default = {"legend": 2, "show_sensors": 1}.get(what, default) - if isinstance(loc, (bool, np.bool_)) and loc: + if isinstance(loc, bool | np.bool_) and loc: loc = true_default loc_dict = { "upper right": 1, @@ -2126,7 +2119,7 @@ def _validate_colors_pce(colors, cmap, conditions, tags): else: colors = list(range(len(conditions))) # convert color list to dict - if isinstance(colors, (list, tuple, np.ndarray)): + if isinstance(colors, list | tuple | np.ndarray): if len(conditions) > len(colors): raise ValueError( f"Trying to plot {len(conditions)} conditions, but there are only " @@ -2179,9 +2172,9 @@ def _validate_cmap_pce(cmap, colors, color_vals): all_int = all(isinstance(_color, Integral) for _color in color_vals) colorbar_title = "" - if isinstance(cmap, (list, tuple, np.ndarray)) and len(cmap) == 2: + if isinstance(cmap, list | tuple | np.ndarray) and len(cmap) == 2: colorbar_title, cmap = cmap - if isinstance(cmap, (str, Colormap)): + if isinstance(cmap, str | Colormap): lut = len(color_vals) if all_int else None cmap = _get_cmap(cmap, lut) return cmap, colorbar_title @@ -2193,7 +2186,7 @@ def _validate_linestyles_pce(linestyles, conditions, tags): if linestyles is None: linestyles = [None] * len(conditions) # will get changed to defaults # convert linestyle list to dict - if isinstance(linestyles, (list, tuple, np.ndarray)): + if isinstance(linestyles, list | tuple | np.ndarray): if len(conditions) > len(linestyles): raise ValueError( f"Trying to plot {len(conditions)} conditions, but there are only " @@ -2808,7 +2801,7 @@ def plot_compare_evokeds( if isinstance(evokeds, Evoked): evokeds = [evokeds] - if isinstance(evokeds, (list, tuple)): + if isinstance(evokeds, list | tuple): evokeds_copy = evokeds.copy() evokeds = dict() diff --git a/mne/viz/evoked_field.py b/mne/viz/evoked_field.py index b247b3fc092..2a93febba4e 100644 --- a/mne/viz/evoked_field.py +++ b/mne/viz/evoked_field.py @@ -3,8 +3,10 @@ author: Marijn van Vliet """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from functools import partial import numpy as np diff --git a/mne/viz/eyetracking/__init__.py b/mne/viz/eyetracking/__init__.py index 9dfb9a5ec19..04bbb1c7216 100644 --- a/mne/viz/eyetracking/__init__.py +++ b/mne/viz/eyetracking/__init__.py @@ -1,5 +1,6 @@ """Eye-tracking visualization routines.""" # +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/eyetracking/heatmap.py b/mne/viz/eyetracking/heatmap.py index e6e6832084e..46aa34b7d31 100644 --- a/mne/viz/eyetracking/heatmap.py +++ b/mne/viz/eyetracking/heatmap.py @@ -1,5 +1,4 @@ -# Authors: Scott Huberty -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/eyetracking/tests/__init__.py b/mne/viz/eyetracking/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/viz/eyetracking/tests/__init__.py +++ b/mne/viz/eyetracking/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/eyetracking/tests/test_heatmap.py b/mne/viz/eyetracking/tests/test_heatmap.py index 0f0b0bfc4d5..ae0efb547ae 100644 --- a/mne/viz/eyetracking/tests/test_heatmap.py +++ b/mne/viz/eyetracking/tests/test_heatmap.py @@ -1,5 +1,4 @@ -# Authors: Scott Huberty -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/ica.py b/mne/viz/ica.py index 621211d4aa6..91bd5c279a5 100644 --- a/mne/viz/ica.py +++ b/mne/viz/ica.py @@ -1,10 +1,6 @@ """Functions to plot ICA specific data (besides topographies).""" -# Authors: Denis Engemann -# Alexandre Gramfort -# Teon Brooks -# Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -126,7 +122,7 @@ def plot_ica_sources( exclude = ica.exclude picks = _picks_to_idx(ica.n_components_, picks, picks_on="components") - if isinstance(inst, (BaseRaw, BaseEpochs)): + if isinstance(inst, BaseRaw | BaseEpochs): fig = _plot_sources( ica, inst, @@ -969,7 +965,7 @@ def plot_ica_scores( if exclude is None: exclude = ica.exclude exclude = np.unique(exclude) - if not isinstance(scores[0], (list, np.ndarray)): + if not isinstance(scores[0], list | np.ndarray): scores = [scores] n_scores = len(scores) @@ -1107,7 +1103,7 @@ def plot_ica_overlay( picks = _picks_to_idx(inst.info, picks, exclude=()) if exclude is None: exclude = ica.exclude - if not isinstance(exclude, (np.ndarray, list)): + if not isinstance(exclude, np.ndarray | list): raise TypeError(f"exclude must be of type list. Got {type(exclude)}") if isinstance(inst, BaseRaw): start = 0.0 if start is None else start diff --git a/mne/viz/misc.py b/mne/viz/misc.py index 524f4c2700c..af1345aa69d 100644 --- a/mne/viz/misc.py +++ b/mne/viz/misc.py @@ -1,12 +1,6 @@ """Functions to make simple plots with M/EEG data.""" -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Cathy Nangini -# Mainak Jas -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -703,7 +697,7 @@ def plot_bem( raise OSError(f"Surface {surf_fname} does not exist.") # TODO: Refactor with / improve _ensure_src to do this - if isinstance(src, (str, Path, os.PathLike)): + if isinstance(src, str | Path | os.PathLike): src = Path(src) if not src.exists(): # convert to Path until get_subjects_dir returns a Path object @@ -973,7 +967,7 @@ def adjust_axes(axes, remove_spines=("top", "right"), grid=True): grid : bool Turn grid on (True) or off (False). """ - axes = [axes] if not isinstance(axes, (list, tuple, np.ndarray)) else axes + axes = [axes] if not isinstance(axes, list | tuple | np.ndarray) else axes for ax in axes: if grid: ax.grid(zorder=0) diff --git a/mne/viz/montage.py b/mne/viz/montage.py index 4e45ac0a513..b7f1724cb87 100644 --- a/mne/viz/montage.py +++ b/mne/viz/montage.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """Functions to plot EEG sensor montages or digitizer montages.""" from copy import deepcopy diff --git a/mne/viz/raw.py b/mne/viz/raw.py index 5366f8feec4..a36bc89d24a 100644 --- a/mne/viz/raw.py +++ b/mne/viz/raw.py @@ -1,9 +1,6 @@ """Functions to plot raw M/EEG data.""" -# Authors: Eric Larson -# Jaakko Leppakangas -# Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/__init__.py b/mne/viz/tests/__init__.py index bdfc6e7b46e..04c673b4e4d 100644 --- a/mne/viz/tests/__init__.py +++ b/mne/viz/tests/__init__.py @@ -1,2 +1,3 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_3d.py b/mne/viz/tests/test_3d.py index 584e70432c4..9c398f94dec 100644 --- a/mne/viz/tests/test_3d.py +++ b/mne/viz/tests/test_3d.py @@ -1,13 +1,8 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Mainak Jas -# Mark Wronkiewicz -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. +from contextlib import nullcontext from pathlib import Path import matplotlib.pyplot as plt @@ -268,6 +263,161 @@ def _assert_n_actors(fig, renderer, n_actors): assert len(fig.plotter.renderer.actors) == n_actors +@pytest.mark.slowtest # can be slow on OSX +@testing.requires_testing_data +@pytest.mark.parametrize( + "test_ecog, test_seeg, sensor_colors, sensor_scales, expectation", + [ + ( + True, + True, + "k", + 2, + pytest.raises( + TypeError, + match="sensor_colors must be an instance of dict or " + "None when more than one channel type", + ), + ), + ( + True, + True, + {"ecog": "k", "seeg": "k"}, + 2, + pytest.raises( + TypeError, + match="sensor_scales must be an instance of dict or " + "None when more than one channel type", + ), + ), + ( + True, + True, + {"ecog": ["k"] * 2, "seeg": "k"}, + {"ecog": 2, "seeg": 2}, + pytest.raises( + ValueError, + match=r"Invalid value for the 'len\(sensor_colors\['ecog'\]\)' " + r"parameter. Allowed values are \d+ and \d+, but got \d+ instead", + ), + ), + ( + True, + True, + {"ecog": "k", "seeg": ["k"] * 2}, + {"ecog": 2, "seeg": 2}, + pytest.raises( + ValueError, + match=r"Invalid value for the 'len\(sensor_colors\['seeg'\]\)' " + r"parameter. Allowed values are \d+ and \d+, but got \d+ instead", + ), + ), + ( + True, + True, + {"ecog": "k", "seeg": "k"}, + {"ecog": [2] * 2, "seeg": 2}, + pytest.raises( + ValueError, + match=r"Invalid value for the 'len\(sensor_scales\['ecog'\]\)' " + r"parameter. Allowed values are \d+ and \d+, but got \d+ instead", + ), + ), + ( + True, + True, + {"ecog": "k", "seeg": "k"}, + {"ecog": 2, "seeg": [2] * 2}, + pytest.raises( + ValueError, + match=r"Invalid value for the 'len\(sensor_scales\['seeg'\]\)' " + r"parameter. Allowed values are \d+ and \d+, but got \d+ instead", + ), + ), + ( + True, + True, + {"ecog": "NotAColor", "seeg": "NotAColor"}, + {"ecog": 2, "seeg": 2}, + pytest.raises( + ValueError, + match=r".* is not a valid color value", + ), + ), + ( + True, + True, + {"ecog": "k", "seeg": "k"}, + {"ecog": "k", "seeg": 2}, + pytest.raises( + AssertionError, + match=r"scales for .* must contain only numerical values, got .* " + r"instead.", + ), + ), + ( + True, + True, + {"ecog": "k", "seeg": "k"}, + {"ecog": 2, "seeg": 2}, + nullcontext(), + ), + ( + True, + True, + {"ecog": [0, 0, 0], "seeg": [0, 0, 0]}, + {"ecog": 2, "seeg": 2}, + nullcontext(), + ), + ( + True, + True, + {"ecog": ["k"] * 10, "seeg": ["k"] * 10}, + {"ecog": [2] * 10, "seeg": [2] * 10}, + nullcontext(), + ), + ( + True, + False, + "k", + 2, + nullcontext(), + ), + ], +) +def test_plot_alignment_ieeg( + renderer, test_ecog, test_seeg, sensor_colors, sensor_scales, expectation +): + """Test plotting of iEEG sensors.""" + # Load evoked: + evoked = read_evokeds(evoked_fname)[0] + # EEG only + evoked_eeg = evoked.copy().pick_types(eeg=True) + with evoked_eeg.info._unlock(): + evoked_eeg.info["projs"] = [] # "remove" avg proj + eeg_channels = pick_types(evoked_eeg.info, eeg=True) + # Set 10 EEG channels to ecog, 10 to seeg + evoked_eeg.set_channel_types( + {evoked_eeg.ch_names[ch]: "ecog" for ch in eeg_channels[:10]} + ) + evoked_eeg.set_channel_types( + {evoked_eeg.ch_names[ch]: "seeg" for ch in eeg_channels[10:20]} + ) + evoked_ecog_seeg = evoked_eeg.pick_types(seeg=True, ecog=True) + this_info = evoked_ecog_seeg.info + # Test plot: + with expectation: + fig = plot_alignment( + this_info, + ecog=test_ecog, + seeg=test_seeg, + sensor_colors=sensor_colors, + sensor_scales=sensor_scales, + ) + assert isinstance(fig, Figure3D) + renderer.backend._close_all() + + @pytest.mark.slowtest # Slow on Azure @testing.requires_testing_data # all use trans + head surf @pytest.mark.parametrize( diff --git a/mne/viz/tests/test_3d_mpl.py b/mne/viz/tests/test_3d_mpl.py index 082541d10f5..ed9e51df972 100644 --- a/mne/viz/tests/test_3d_mpl.py +++ b/mne/viz/tests/test_3d_mpl.py @@ -1,10 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Mainak Jas -# Mark Wronkiewicz -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_circle.py b/mne/viz/tests/test_circle.py index 357a140456d..a26379f6ccc 100644 --- a/mne/viz/tests/test_circle.py +++ b/mne/viz/tests/test_circle.py @@ -1,7 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_epochs.py b/mne/viz/tests/test_epochs.py index 7de511affe7..d5182aa1026 100644 --- a/mne/viz/tests/test_epochs.py +++ b/mne/viz/tests/test_epochs.py @@ -1,10 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Jaakko Leppakangas -# Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_evoked.py b/mne/viz/tests/test_evoked.py index 92281323ec4..035008dd87f 100644 --- a/mne/viz/tests/test_evoked.py +++ b/mne/viz/tests/test_evoked.py @@ -1,12 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Cathy Nangini -# Mainak Jas -# Jona Sassenhagen -# Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_figure.py b/mne/viz/tests/test_figure.py index 6a67c7572e2..4ea2d1f8df6 100644 --- a/mne/viz/tests/test_figure.py +++ b/mne/viz/tests/test_figure.py @@ -1,5 +1,4 @@ -# Authors: Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_ica.py b/mne/viz/tests/test_ica.py index 39d4b616431..086bb369743 100644 --- a/mne/viz/tests/test_ica.py +++ b/mne/viz/tests/test_ica.py @@ -1,6 +1,4 @@ -# Authors: Denis Engemann -# Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_misc.py b/mne/viz/tests/test_misc.py index aa0fa0f1959..fe179756c53 100644 --- a/mne/viz/tests/test_misc.py +++ b/mne/viz/tests/test_misc.py @@ -1,10 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Cathy Nangini -# Mainak Jas -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_montage.py b/mne/viz/tests/test_montage.py index adf818b2651..e9954d2c115 100644 --- a/mne/viz/tests/test_montage.py +++ b/mne/viz/tests/test_montage.py @@ -1,7 +1,4 @@ -# Authors: Denis Engemann -# Alexandre Gramfort -# Teon Brooks -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_proj.py b/mne/viz/tests/test_proj.py index 36fe9054363..19699677205 100644 --- a/mne/viz/tests/test_proj.py +++ b/mne/viz/tests/test_proj.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_raw.py b/mne/viz/tests/test_raw.py index 85da1dfe56f..a2565927feb 100644 --- a/mne/viz/tests/test_raw.py +++ b/mne/viz/tests/test_raw.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_scraper.py b/mne/viz/tests/test_scraper.py index ed95428a097..e24ecfa0953 100644 --- a/mne/viz/tests/test_scraper.py +++ b/mne/viz/tests/test_scraper.py @@ -1,5 +1,4 @@ -# Authors: Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_topo.py b/mne/viz/tests/test_topo.py index 344572dcfc9..85b4b43dcf8 100644 --- a/mne/viz/tests/test_topo.py +++ b/mne/viz/tests/test_topo.py @@ -1,9 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Robert Luke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/tests/test_topomap.py b/mne/viz/tests/test_topomap.py index a2ebc6b3eea..afa9341c00e 100644 --- a/mne/viz/tests/test_topomap.py +++ b/mne/viz/tests/test_topomap.py @@ -1,9 +1,4 @@ -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Robert Luke -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -573,6 +568,24 @@ def patch(): assert_array_equal(evoked_grad.info["bads"], orig_bads) +def test_plot_psds_topomap_colorbar(): + """Test plot_psds_topomap colorbar option.""" + raw = read_raw_fif(raw_fname) + picks = pick_types(raw.info, meg="grad") + info = pick_info(raw.info, picks) + freqs = np.arange(3.0, 9.5) + rng = np.random.default_rng(42) + psd = np.abs(rng.standard_normal((len(picks), len(freqs)))) + bands = {"theta": [4, 8]} + + plt.close("all") + fig_cbar = plot_psds_topomap(psd, freqs, info, colorbar=True, bands=bands) + assert len(fig_cbar.axes) == 2 + + fig_nocbar = plot_psds_topomap(psd, freqs, info, colorbar=False, bands=bands) + assert len(fig_nocbar.axes) == 1 + + def test_plot_tfr_topomap(): """Test plotting of TFR data.""" raw = read_raw_fif(raw_fname) diff --git a/mne/viz/tests/test_ui_events.py b/mne/viz/tests/test_ui_events.py index 480ac783f8e..a2be4445ff9 100644 --- a/mne/viz/tests/test_ui_events.py +++ b/mne/viz/tests/test_ui_events.py @@ -1,7 +1,7 @@ -# Authors: Marijn van Vliet -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import matplotlib.pyplot as plt import pytest diff --git a/mne/viz/tests/test_utils.py b/mne/viz/tests/test_utils.py index 816f984ca77..59e2976e464 100644 --- a/mne/viz/tests/test_utils.py +++ b/mne/viz/tests/test_utils.py @@ -1,5 +1,4 @@ -# Authors: Alexandre Gramfort -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/topo.py b/mne/viz/topo.py index 71f7049490f..3364a455aed 100644 --- a/mne/viz/topo.py +++ b/mne/viz/topo.py @@ -1,10 +1,6 @@ """Functions to plot M/EEG data on topo (one axes per channel).""" -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. diff --git a/mne/viz/topomap.py b/mne/viz/topomap.py index 8b5aa597a02..147919a9c9d 100644 --- a/mne/viz/topomap.py +++ b/mne/viz/topomap.py @@ -1,13 +1,6 @@ """Functions to plot M/EEG data e.g. topographies.""" -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Robert Luke -# Mikołaj Magnuski -# Marijn van Vliet -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -1326,7 +1319,7 @@ def _plot_topomap( # because mpl has probably fixed it linewidth = mask_params["markeredgewidth"] cont = True - if isinstance(contours, (np.ndarray, list)): + if isinstance(contours, np.ndarray | list): pass elif contours == 0 or ((Zi == Zi[0, 0]) | np.isnan(Zi)).all(): cont = None # can't make contours for constant-valued functions @@ -1741,7 +1734,7 @@ def onclick_title(event, ica=ica, titles=subplot_titles, fig=fig): fig.canvas.mpl_connect("button_press_event", onclick_title) # add plot_properties interactivity only if inst was passed - if isinstance(inst, (BaseRaw, BaseEpochs)): + if isinstance(inst, BaseRaw | BaseEpochs): topomap_args = dict( sensors=sensors, contours=contours, @@ -1929,7 +1922,7 @@ def plot_tfr_topomap( _hide_frame(axes) locator = None - if not isinstance(contours, (list, np.ndarray)): + if not isinstance(contours, list | np.ndarray): locator, contours = _set_contour_locator(*vlim, contours) fig_wrapper = list() @@ -1946,7 +1939,7 @@ def plot_tfr_topomap( fig=fig_wrapper, ) - if not isinstance(contours, (list, np.ndarray)): + if not isinstance(contours, list | np.ndarray): _, contours = _set_contour_locator(*vlim, contours) names = _prepare_sensor_names(names, show_names) @@ -2297,7 +2290,7 @@ def plot_evoked_topomap( _vlim = (np.min(_vlim), np.max(_vlim)) cmap = _setup_cmap(cmap, n_axes=n_times, norm=_vlim[0] >= 0) # set up contours - if not isinstance(contours, (list, np.ndarray)): + if not isinstance(contours, list | np.ndarray): _, contours = _set_contour_locator(*_vlim, contours) # prepare for main loop over times kwargs = dict( @@ -2842,7 +2835,7 @@ def plot_psds_topomap( for ax, _mask, _data, (title, (fmin, fmax)) in zip( axes, freq_masks, band_data, bands.items() ): - colorbar = (not joint_vlim) or ax == axes[-1] + plot_colorbar = False if not colorbar else (not joint_vlim) or ax == axes[-1] _plot_topomap_multi_cbar( _data, pos, @@ -2851,7 +2844,7 @@ def plot_psds_topomap( vlim=vlim, cmap=cmap, outlines=outlines, - colorbar=colorbar, + colorbar=plot_colorbar, unit=unit, cbar_fmt=cbar_fmt, sphere=sphere, diff --git a/mne/viz/ui_events.py b/mne/viz/ui_events.py index 35efa79e210..256d5741ad3 100644 --- a/mne/viz/ui_events.py +++ b/mne/viz/ui_events.py @@ -10,8 +10,10 @@ Authors: Marijn van Vliet """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + from __future__ import annotations # only needed for Python ≤ 3.9 import contextlib diff --git a/mne/viz/utils.py b/mne/viz/utils.py index e8affb0bacb..675b89b2852 100644 --- a/mne/viz/utils.py +++ b/mne/viz/utils.py @@ -1,16 +1,9 @@ """Utility functions for plotting M/EEG data.""" -# Authors: Alexandre Gramfort -# Denis Engemann -# Martin Luessi -# Eric Larson -# Mainak Jas -# Stefan Appelhoff -# Clemens Brunner -# Daniel McCloy -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import difflib import math import os @@ -391,7 +384,7 @@ def _get_channel_plotting_order(order, ch_types, picks=None): for pick_idx, pick_type in enumerate(ch_types) if order_type == pick_type ] - elif not isinstance(order, (np.ndarray, list, tuple)): + elif not isinstance(order, np.ndarray | list | tuple): raise ValueError(f'order should be array-like; got "{order}" ({type(order)}).') if picks is not None: order = [ch for ch in order if ch in picks] @@ -1290,7 +1283,7 @@ def _plot_sensors_2d( connect_picker = True if show_names: - if isinstance(show_names, (list, np.ndarray)): # only given channels + if isinstance(show_names, list | np.ndarray): # only given channels indices = [list(ch_names).index(name) for name in show_names] else: # all channels indices = range(len(pos)) @@ -1359,7 +1352,7 @@ def _compute_scalings(scalings, inst, remove_dc=False, duration=10): from ..io import BaseRaw scalings = _handle_default("scalings_plot_raw", scalings) - if not isinstance(inst, (BaseRaw, BaseEpochs)): + if not isinstance(inst, BaseRaw | BaseEpochs): raise ValueError("Must supply either Raw or Epochs") for key, value in scalings.items(): diff --git a/pyproject.toml b/pyproject.toml index c0fabebc5c0..e82012b8d6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ authors = [ maintainers = [{ name = "Dan McCloy", email = "dan@mccloy.info" }] license = { text = "BSD-3-Clause" } readme = { file = "README.rst", content-type = "text/x-rst" } -requires-python = ">=3.9" +requires-python = ">=3.10" keywords = [ "neuroscience", "neuroimaging", @@ -78,7 +78,6 @@ full-no-qt = [ "jupyter", "python-picard", "joblib", - "psutil", "dipy", "vtk", "nilearn", @@ -107,6 +106,7 @@ full-no-qt = [ "snirf", "defusedxml", "neo", + "antio>=0.4.0", ] full = ["mne[full-no-qt]", "PyQt6!=6.6.0", "PyQt6-Qt6!=6.6.0,!=6.7.0"] full-pyqt6 = ["mne[full]"] @@ -174,6 +174,7 @@ doc = [ "intersphinx_registry>=0.2405.27", # https://github.com/sphinx-contrib/sphinxcontrib-towncrier/issues/92 "towncrier<24.7", + "psutil", ] dev = ["mne[test,doc]", "rcssmin"] @@ -254,6 +255,10 @@ ignore-decorators = [ "examples/preprocessing/eeg_bridging.py" = [ "E501", # line too long ] +"mne/decoding/tests/test_*.py" = [ + "E402", # Module level import not at top of file +] + [tool.pytest.ini_options] # -r f (failed), E (error), s (skipped), x (xfail), X (xpassed), w (warnings) @@ -274,6 +279,8 @@ skips = ["*/test_*.py"] # assert statements are good practice with pytest report_level = "WARNING" ignore_roles = [ "attr", + "bdg-primary-line", + "bdg-info-line", "class", "doc", "eq", @@ -298,6 +305,7 @@ ignore_directives = [ "automodule", "autosummary", "bibliography", + "card", "cssclass", "currentmodule", "dropdown", @@ -358,7 +366,7 @@ package = "mne" directory = "doc/changes/devel/" filename = "doc/changes/devel.rst" title_format = "{version} ({project_date})" -issue_format = "`#{issue} `__" +issue_format = "`#{issue} `__" [[tool.towncrier.type]] directory = "notable" diff --git a/tools/check_mne_location.py b/tools/check_mne_location.py index 8dccf9df091..150c841abed 100755 --- a/tools/check_mne_location.py +++ b/tools/check_mne_location.py @@ -1,8 +1,11 @@ #!/usr/bin/env python + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. from pathlib import Path + import mne want_mne_dir = Path(__file__).parents[1] / "mne" diff --git a/tools/dev/check_steering_committee.py b/tools/dev/check_steering_committee.py index 419e9fd4164..94ce2ab69f4 100755 --- a/tools/dev/check_steering_committee.py +++ b/tools/dev/check_steering_committee.py @@ -1,14 +1,20 @@ -# Install pygithub and add GITHUB_TOKEN as env var using a personal access token -# with read:org, read:user, and read:project -# https://docs.github.com/en/enterprise-server@3.6/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens -# https://pygithub.readthedocs.io/ +"""Check the steering committee membership. + +Install pygithub and add GITHUB_TOKEN as env var using a personal access token +with read:org, read:user, and read:project +https://docs.github.com/en/enterprise-server@3.6/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens +https://pygithub.readthedocs.io/ +""" # noqa: E501 + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. -from collections import Counter import os import pprint -from datetime import timezone, datetime, timedelta +from collections import Counter +from datetime import datetime, timedelta, timezone + from github import Auth, Github from github.Commit import Commit from tqdm import tqdm diff --git a/tools/dev/ensure_headers.py b/tools/dev/ensure_headers.py index 435376ace37..b5b425b5900 100644 --- a/tools/dev/ensure_headers.py +++ b/tools/dev/ensure_headers.py @@ -14,6 +14,8 @@ This script ensures that we use consistent license naming in consistent locations toward the top of each file. """ + +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. @@ -25,11 +27,18 @@ repo = Repo(Path(__file__).parents[2]) +AUTHOR_LINE = "# Authors: The MNE-Python contributors." LICENSE_LINE = "# License: BSD-3-Clause" COPYRIGHT_LINE = "# Copyright the MNE-Python contributors." +# Cover how lines can start (regex or tuple to be used with startswith) +AUTHOR_RE = re.compile(r"^# (A|@a)uthors? ?: .*$") +LICENSE_STARTS = ("# License: ", "# SPDX-License-Identifier: ") +COPYRIGHT_STARTS = ("# Copyright ",) + def get_paths_from_tree(root, level=0): + """Get paths from a GitPython tree.""" for entry in root: if entry.type == "tree": yield from get_paths_from_tree(entry, level + 1) @@ -37,58 +46,102 @@ def get_paths_from_tree(root, level=0): yield Path(entry.path) # entry.type -def _ensure_license(lines, path): - # 1. Keep existing - license_idx = np.where([line.startswith("# License: ") for line in lines])[0] - assert len(license_idx) <= 1, len(license_idx) - if len(license_idx): # If existing, ensure it's correct - lines[license_idx[0]] = LICENSE_LINE - return - # 2. First non-comment line after author line - author_idx = np.where([re.match(r"^# Authors? ?: .*$", line) for line in lines])[0] - assert len(author_idx) <= 1, len(author_idx) - if len(author_idx): - insert = author_idx[0] - for extra in range(1, 100): - if not lines[insert + extra].startswith("#"): - break +def first_commentable_line(lines): + """Find the first line where we can add a comment.""" + max_len = 100 + if lines[0].startswith(('"""', 'r"""')): + if lines[0].count('"""') == 2: + return 1 + for insert in range(1, min(max_len, len(lines))): + if '"""' in lines[insert]: + return insert + 1 else: raise RuntimeError( - "Failed to find non-comment line within 100 of end of author line" + f"Failed to find end of file docstring within {max_len} lines" ) - lines.insert(insert + extra, LICENSE_LINE) - return - # 3. First line after docstring - insert = 0 - max_len = 100 - if lines[0].startswith('"""'): - if lines[0].count('"""') != 2: - for insert in range(1, max_len): - if '"""' in lines[insert]: - # Find next non-blank line: - for extra in range(1, 3): # up to 2 blank lines - if lines[insert + extra].strip(): - break - else: - raise RuntimeError( - "Failed to find non-blank line within 2 of end of " - f"docstring at line {insert + 1}" - ) - insert += extra - break - else: - raise RuntimeError( - f"Failed to find end of file docstring within {max_len} lines" - ) - lines.insert(insert, LICENSE_LINE) - return - # 4. First non-comment line - for insert in range(100): - if not lines[insert].startswith("#"): - lines.insert(insert, LICENSE_LINE) + if lines[0].startswith("#!"): + return 1 + else: + return 0 + + +def path_multi_author(path): + """Check if a file allows multi-author comments.""" + return path.parts[0] in ("examples", "tutorials") + + +def get_author_idx(path, lines): + """Get the index of the author line, if available.""" + author_idx = np.where([AUTHOR_RE.match(line) is not None for line in lines])[0] + assert len(author_idx) <= 1, f"{len(author_idx)=} for {path=}" + return author_idx[0] if len(author_idx) else None + + +def get_license_idx(path, lines): + """Get the license index.""" + license_idx = np.where([line.startswith(LICENSE_STARTS) for line in lines])[0] + assert len(license_idx) <= 1, f"{len(license_idx)=} for {path=}" + return license_idx[0] if len(license_idx) else None + + +def _ensure_author(lines, path): + author_idx = get_author_idx(path, lines) + license_idx = get_license_idx(path, lines) + first_idx = first_commentable_line(lines) + # 1. Keep existing + if author_idx is not None: + # We have to be careful here -- examples and tutorials are allowed multiple + # authors + if path_multi_author(path): + # Just assume it's correct and return return + assert license_idx is not None, f"{license_idx=} for {path=}" + for _ in range(license_idx - author_idx - 1): + lines.pop(author_idx + 1) + assert lines[author_idx + 1].startswith(LICENSE_STARTS), lines[license_idx + 1] + del license_idx + lines[author_idx] = AUTHOR_LINE + elif license_idx is not None: + # 2. Before license line if present + lines.insert(license_idx, AUTHOR_LINE) else: - raise RuntimeError("Failed to find non-comment line within 100 lines") + # 3. First line after docstring + lines.insert(first_idx, AUTHOR_LINE) + # Now make sure it's in the right spot + author_idx = get_author_idx(path, lines) + if author_idx != 0: + if author_idx == first_idx: + # Insert a blank line + lines.insert(author_idx, "") + author_idx += 1 + first_idx += 1 + if author_idx != first_idx: + raise RuntimeError( + "\nLine should have comments as docstring or author line needs to be moved " + "manually to be one blank line after the docstring:\n" + f"{path}: {author_idx=} != {first_idx=}" + ) + + +def _ensure_license(lines, path): + # 1. Keep/replace existing + insert = get_license_idx(path, lines) + + # 2. After author line(s) + if insert is None: + author_idx = get_author_idx(path, lines) + assert author_idx is not None, f"{author_idx=} for {path=}" + insert = author_idx + 1 + if path_multi_author: + # Figure out where to insert the license: + for insert, line in enumerate(lines[author_idx + 1 :], insert): + if not line.startswith("# "): + break + if lines[insert].startswith(LICENSE_STARTS): + lines[insert] = LICENSE_LINE + else: + lines.insert(insert, LICENSE_LINE) + assert lines.count(LICENSE_LINE) == 1, f"{lines.count(LICENSE_LINE)=} for {path=}" def _ensure_copyright(lines, path): @@ -96,14 +149,25 @@ def _ensure_copyright(lines, path): "mne/preprocessing/_csd.py": 2, "mne/transforms.py": 2, } - n_copyright = sum(line.startswith("# Copyright ") for line in lines) + n_copyright = sum(line.startswith(COPYRIGHT_STARTS) for line in lines) assert n_copyright <= n_expected.get(str(path), 1), n_copyright insert = lines.index(LICENSE_LINE) + 1 - if lines[insert].startswith("# Copyright"): + if lines[insert].startswith(COPYRIGHT_STARTS): lines[insert] = COPYRIGHT_LINE else: lines.insert(insert, COPYRIGHT_LINE) - assert lines.count(COPYRIGHT_LINE) == 1, lines.count(COPYRIGHT_LINE) + assert ( + lines.count(COPYRIGHT_LINE) == 1 + ), f"{lines.count(COPYRIGHT_LINE)=} for {path=}" + + +def _ensure_blank(lines, path): + assert ( + lines.count(COPYRIGHT_LINE) == 1 + ), f"{lines.count(COPYRIGHT_LINE)=} for {path=}" + insert = lines.index(COPYRIGHT_LINE) + 1 + if lines[insert].strip(): # actually has content + lines.insert(insert, "") for path in get_paths_from_tree(repo.tree()): @@ -112,10 +176,21 @@ def _ensure_copyright(lines, path): lines = path.read_text("utf-8").split("\n") # Remove the UTF-8 file coding stuff orig_lines = list(lines) - if lines[0] == "# -*- coding: utf-8 -*-": + if lines[0] in ("# -*- coding: utf-8 -*-", "# -*- coding: UTF-8 -*-"): + lines = lines[1:] + if lines[0] == "": + lines = lines[1:] + # We had these with mne/commands without an executable bit, and don't really + # need them executable, so let's get rid of the line. + if lines[0].startswith("#!/usr/bin/env python") and path.parts[:2] == ( + "mne", + "commands", + ): lines = lines[1:] + _ensure_author(lines, path) _ensure_license(lines, path) _ensure_copyright(lines, path) + _ensure_blank(lines, path) if lines != orig_lines: print(path) path.write_text("\n".join(lines), "utf-8") diff --git a/tools/dev/gen_css_for_mne.py b/tools/dev/gen_css_for_mne.py index ca7210c8918..2d277857348 100644 --- a/tools/dev/gen_css_for_mne.py +++ b/tools/dev/gen_css_for_mne.py @@ -10,17 +10,17 @@ bootstrap-icons.mne.min.css """ -# Author: Richard Höchenberger -# +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. import base64 -import mne from pathlib import Path import rcssmin +import mne + base_dir = Path(mne.__file__).parent / "report" / "js_and_css" / "bootstrap-icons" css_path_in = base_dir / "bootstrap-icons.css" css_path_out = base_dir / "bootstrap-icons.mne.css" diff --git a/tools/dev/generate_pyi_files.py b/tools/dev/generate_pyi_files.py index 97deb34f837..c6ae36e7dd4 100644 --- a/tools/dev/generate_pyi_files.py +++ b/tools/dev/generate_pyi_files.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import os import sys from importlib import import_module @@ -7,6 +9,7 @@ import ast_comments as ast import black + import mne diff --git a/tools/dev/update_credit_json.py b/tools/dev/update_credit_json.py new file mode 100644 index 00000000000..e131fd3f33c --- /dev/null +++ b/tools/dev/update_credit_json.py @@ -0,0 +1,92 @@ +"""Collect credit information for PRs. + +The initial run takes a long time (hours!) due to GitHub rate limits, even with +a personal GITHUB_TOKEN. +""" + +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + +import json +import os +import re +from pathlib import Path + +from github import Auth, Github +from tqdm import tqdm + +auth = Auth.Token(os.environ["GITHUB_TOKEN"]) +g = Github(auth=auth, per_page=100) +out_path = Path(__file__).parents[2] / "doc" / "sphinxext" / "prs" +out_path.mkdir(exist_ok=True) +oldest_pr = 6915 # can update this when the oldest open PR changes to speed things up + +# JSON formatting +json_kwargs = dict(indent=2, ensure_ascii=False, sort_keys=False) +# If the above arguments are changed, existing JSON should also be reformatted with +# something like: +# for fname in sorted(glob.glob("doc/sphinxext/prs/*.json")): +# fname = Path(fname).resolve(strict=True) +# fname.write_text(json.dumps(json.loads(fname.read_text("utf-8")), **json_kwargs), "utf-8") # noqa: E501 + +repo = g.get_repo("mne-tools/mne-python") +co_re = re.compile("Co-authored-by: ([^<>]+) <([^()>]+)>") +# We go in descending order of updates and `break` when we encounter a PR we have +# already committed a file for. +pulls_iter = repo.get_pulls(state="closed", sort="created", direction="desc") +iter_ = tqdm(pulls_iter, unit="pr", desc="Traversing") +last = 0 +n_added = 0 +for pull in iter_: + fname_out = out_path / f"{pull.number}.json" + if pull.number < oldest_pr: + iter_.close() + print( + f"After checking {iter_.n + 1} and adding {n_added} PR(s), " + f"found PR number less than oldest existing file {fname_out}, stopping" + ) + break + if fname_out.is_file(): + continue + + # PR diff credit + if not pull.merged: + continue + out = dict() + # One option is to do a git diff between pull.base and pull.head, + # but let's see if we can stay pythonic + out["merge_commit_sha"] = pull.merge_commit_sha + # Prefer the GitHub username information because it should be most up to date + name, email = pull.user.name, pull.user.email + if name is None and email is None: + # no usable GitHub user information, pull it from the first commit + author = pull.get_commits()[0].commit.author + name, email = author.name, author.email + out["authors"] = [dict(n=name, e=email)] + # For PR 54 for example this is empty for some reason! + if out["merge_commit_sha"]: + try: + merge_commit = repo.get_commit(out["merge_commit_sha"]) + except Exception: + pass # this happens on a lot of old PRs for some reason + else: + msg = merge_commit.commit.message.replace("\r", "") + for n, e in co_re.findall(msg): + # sometimes commit messages like for 9754 contain all + # commit messages and include some repeated co-authorship messages + if n not in {a["n"] for a in out["authors"]}: + out["authors"].append(dict(n=n, e=e)) + out["changes"] = dict() + for file in pull.get_files(): + out["changes"][file.filename] = { + k[0]: getattr(file, k) for k in ("additions", "deletions") + } + n_added += 1 + fname_out.write_text(json.dumps(out, **json_kwargs), encoding="utf-8") + + # TODO: Should add: + # pull.get_comments() + # pull.get_review_comments() + +g.close() diff --git a/tools/environment_old.yml b/tools/environment_old.yml index 852d87844b3..4515f9cd611 100644 --- a/tools/environment_old.yml +++ b/tools/environment_old.yml @@ -2,12 +2,12 @@ name: mne channels: - conda-forge dependencies: - - python=3.9 - - numpy=1.23 - - scipy=1.9 + - python=3.10 + - numpy=1.24 + - scipy=1.10 - matplotlib=3.6 - - pandas=1.3.2 - - scikit-learn=1.1 + - pandas=1.5.2 + - scikit-learn=1.2 - nibabel # whichever one works - tqdm - pooch diff --git a/tools/generate_codemeta.py b/tools/generate_codemeta.py index a1c1fac77b4..a82a521e067 100644 --- a/tools/generate_codemeta.py +++ b/tools/generate_codemeta.py @@ -1,11 +1,14 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import subprocess -import tomllib from argparse import ArgumentParser from datetime import date from pathlib import Path +import tomllib + parser = ArgumentParser(description="Generate codemeta.json and CITATION.cff") parser.add_argument("release_version", type=str) release_version = parser.parse_args().release_version diff --git a/tools/github_actions_test.sh b/tools/github_actions_test.sh index 78cc063d016..4cdd202223f 100755 --- a/tools/github_actions_test.sh +++ b/tools/github_actions_test.sh @@ -19,10 +19,13 @@ if [[ ! -z "$CONDA_ENV" ]] && [[ "${RUNNER_OS}" != "Windows" ]]; then cd .. INSTALL_PATH=$(python -c "import mne, pathlib; print(str(pathlib.Path(mne.__file__).parents[1]))") echo "Copying tests from $(pwd)/mne-python/mne/ to ${INSTALL_PATH}/mne/" + echo "::group::rsync" rsync -a --partial --progress --prune-empty-dirs --exclude="*.pyc" --include="**/" --include="**/tests/*" --include="**/tests/data/**" --exclude="**" ./mne-python/mne/ ${INSTALL_PATH}/mne/ + echo "::endgroup::" cd $INSTALL_PATH echo "Executing from $(pwd)" fi + set -x pytest -m "${CONDITION}" --tb=short --cov=mne --cov-report xml --color=yes --junit-xml=$JUNIT_PATH -vv ${USE_DIRS} set +x diff --git a/tools/vulture_allowlist.py b/tools/vulture_allowlist.py index 3de48b3b906..ce5e95124d4 100644 --- a/tools/vulture_allowlist.py +++ b/tools/vulture_allowlist.py @@ -1,4 +1,14 @@ -# Testing stuff +"""Vulture allowlist. + +Python names that we want Vulture to ignore need to be added to this file, see: + +https://github.com/jendrikseipp/vulture/blob/main/README.md#whitelists +""" + +# Authors: The MNE-Python contributors. +# License: BSD-3-Clause +# Copyright the MNE-Python contributors. + numba_conditional options_3d invisible_fig @@ -31,6 +41,10 @@ verbose_debug metadata_routing +# Decoding +_._more_tags +deep + # Backward compat or rarely used RawFIF estimate_head_mri_t @@ -63,6 +77,10 @@ _notebook_vtk_works _.drop_inds_ +# mne/io/ant/tests/test_ant.py +andy_101 +na_271 + # mne/io/snirf/tests/test_snirf.py _.dataTimeSeries _.sourceIndex diff --git a/tutorials/epochs/10_epochs_overview.py b/tutorials/epochs/10_epochs_overview.py index 7726bc754a2..7d92da73a77 100644 --- a/tutorials/epochs/10_epochs_overview.py +++ b/tutorials/epochs/10_epochs_overview.py @@ -16,8 +16,10 @@ As usual we'll start by importing the modules we need: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import mne diff --git a/tutorials/epochs/20_visualize_epochs.py b/tutorials/epochs/20_visualize_epochs.py index e311b324ee8..04eca026b7e 100644 --- a/tutorials/epochs/20_visualize_epochs.py +++ b/tutorials/epochs/20_visualize_epochs.py @@ -12,8 +12,10 @@ We'll start by importing the modules we need, loading the continuous (raw) sample data, and cropping it to save memory: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import mne diff --git a/tutorials/epochs/30_epochs_metadata.py b/tutorials/epochs/30_epochs_metadata.py index 21728346e19..a9019318034 100644 --- a/tutorials/epochs/30_epochs_metadata.py +++ b/tutorials/epochs/30_epochs_metadata.py @@ -17,8 +17,10 @@ need and loading the data: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import numpy as np diff --git a/tutorials/epochs/40_autogenerate_metadata.py b/tutorials/epochs/40_autogenerate_metadata.py index 7da978373fc..cd43699cd13 100644 --- a/tutorials/epochs/40_autogenerate_metadata.py +++ b/tutorials/epochs/40_autogenerate_metadata.py @@ -42,8 +42,10 @@ by calling `mne.events_from_annotations`. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import matplotlib.pyplot as plt diff --git a/tutorials/epochs/50_epochs_to_data_frame.py b/tutorials/epochs/50_epochs_to_data_frame.py index e86c1111809..a6c5558fb2b 100644 --- a/tutorials/epochs/50_epochs_to_data_frame.py +++ b/tutorials/epochs/50_epochs_to_data_frame.py @@ -16,8 +16,10 @@ need and loading the data: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import matplotlib.pyplot as plt diff --git a/tutorials/epochs/60_make_fixed_length_epochs.py b/tutorials/epochs/60_make_fixed_length_epochs.py index 9ca097deab3..04a4ec87c7d 100644 --- a/tutorials/epochs/60_make_fixed_length_epochs.py +++ b/tutorials/epochs/60_make_fixed_length_epochs.py @@ -28,8 +28,10 @@ $ pip install mne-connectivity """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import matplotlib.pyplot as plt diff --git a/tutorials/evoked/10_evoked_overview.py b/tutorials/evoked/10_evoked_overview.py index 9116bb19ea6..75e63692bd2 100644 --- a/tutorials/evoked/10_evoked_overview.py +++ b/tutorials/evoked/10_evoked_overview.py @@ -15,8 +15,10 @@ As usual, we start by importing the modules we need: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import mne diff --git a/tutorials/evoked/20_visualize_evoked.py b/tutorials/evoked/20_visualize_evoked.py index f19c3863453..f92bd6052ac 100644 --- a/tutorials/evoked/20_visualize_evoked.py +++ b/tutorials/evoked/20_visualize_evoked.py @@ -11,8 +11,10 @@ As usual we'll start by importing the modules we need: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import numpy as np diff --git a/tutorials/evoked/30_eeg_erp.py b/tutorials/evoked/30_eeg_erp.py index 7c542476b84..9ebfd4e845e 100644 --- a/tutorials/evoked/30_eeg_erp.py +++ b/tutorials/evoked/30_eeg_erp.py @@ -17,8 +17,10 @@ we'll crop the raw data from ~4.5 minutes down to 90 seconds. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import matplotlib.pyplot as plt diff --git a/tutorials/evoked/40_whitened.py b/tutorials/evoked/40_whitened.py index a254111ce90..a3110139b4e 100644 --- a/tutorials/evoked/40_whitened.py +++ b/tutorials/evoked/40_whitened.py @@ -15,8 +15,10 @@ that we'll consider to be noise. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import mne diff --git a/tutorials/forward/10_background_freesurfer.py b/tutorials/forward/10_background_freesurfer.py index 900e3c720ee..4975a191d7b 100644 --- a/tutorials/forward/10_background_freesurfer.py +++ b/tutorials/forward/10_background_freesurfer.py @@ -85,8 +85,10 @@ :footcite:`DestrieuxEtAl2010`). """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import mne diff --git a/tutorials/forward/20_source_alignment.py b/tutorials/forward/20_source_alignment.py index 5329862eed5..dd26f610907 100644 --- a/tutorials/forward/20_source_alignment.py +++ b/tutorials/forward/20_source_alignment.py @@ -13,8 +13,10 @@ Let's start out by loading some data. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import nibabel as nib diff --git a/tutorials/forward/30_forward.py b/tutorials/forward/30_forward.py index 89bfab0ec6a..6c55d0bfe3c 100644 --- a/tutorials/forward/30_forward.py +++ b/tutorials/forward/30_forward.py @@ -11,8 +11,10 @@ modeling, see :ref:`ch_forward`. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import mne diff --git a/tutorials/forward/50_background_freesurfer_mne.py b/tutorials/forward/50_background_freesurfer_mne.py index 1d71f94606d..a4cb07848c5 100644 --- a/tutorials/forward/50_background_freesurfer_mne.py +++ b/tutorials/forward/50_background_freesurfer_mne.py @@ -16,8 +16,10 @@ readable on top of an MRI image. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import matplotlib.patheffects as path_effects diff --git a/tutorials/forward/90_compute_covariance.py b/tutorials/forward/90_compute_covariance.py index da0d40d0103..37c2329f439 100644 --- a/tutorials/forward/90_compute_covariance.py +++ b/tutorials/forward/90_compute_covariance.py @@ -5,16 +5,17 @@ Computing a covariance matrix ============================= -Many methods in MNE, including source estimation and some classification -algorithms, require covariance estimations from the recordings. -In this tutorial we cover the basics of sensor covariance computations and -construct a noise covariance matrix that can be used when computing the -minimum-norm inverse solution. For more information, see +Many methods in MNE, including source estimation and some classification algorithms, +require covariance estimations from the recordings. In this tutorial we cover the basics +of sensor covariance computations and construct a noise covariance matrix that can be +used when computing the minimum-norm inverse solution. For more information, see :ref:`minimum_norm_estimates`. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import mne diff --git a/tutorials/intro/10_overview.py b/tutorials/intro/10_overview.py index 2c9a68a1baf..89c1ccc3505 100644 --- a/tutorials/intro/10_overview.py +++ b/tutorials/intro/10_overview.py @@ -14,8 +14,10 @@ We begin by importing the necessary Python modules: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import numpy as np diff --git a/tutorials/intro/15_inplace.py b/tutorials/intro/15_inplace.py index 2c7f6261569..0c68843d4c8 100644 --- a/tutorials/intro/15_inplace.py +++ b/tutorials/intro/15_inplace.py @@ -17,8 +17,10 @@ :ref:`example data `: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import mne diff --git a/tutorials/intro/20_events_from_raw.py b/tutorials/intro/20_events_from_raw.py index cddbe7cf57e..2c368646908 100644 --- a/tutorials/intro/20_events_from_raw.py +++ b/tutorials/intro/20_events_from_raw.py @@ -26,8 +26,10 @@ to just 60 seconds before loading it into RAM: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import numpy as np diff --git a/tutorials/intro/30_info.py b/tutorials/intro/30_info.py index 3f8c0dc624b..c549688a8a9 100644 --- a/tutorials/intro/30_info.py +++ b/tutorials/intro/30_info.py @@ -14,8 +14,10 @@ `: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import mne diff --git a/tutorials/intro/40_sensor_locations.py b/tutorials/intro/40_sensor_locations.py index a0a03152eeb..23de4cdce9a 100644 --- a/tutorials/intro/40_sensor_locations.py +++ b/tutorials/intro/40_sensor_locations.py @@ -9,8 +9,10 @@ MNE-Python handles physical locations of sensors. As usual we'll start by importing the modules we need: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% from pathlib import Path diff --git a/tutorials/intro/50_configure_mne.py b/tutorials/intro/50_configure_mne.py index a8fa106986e..9e6896eaf98 100644 --- a/tutorials/intro/50_configure_mne.py +++ b/tutorials/intro/50_configure_mne.py @@ -11,8 +11,10 @@ We begin by importing the necessary Python modules: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/intro/70_report.py b/tutorials/intro/70_report.py index 575c641989e..8c709197957 100644 --- a/tutorials/intro/70_report.py +++ b/tutorials/intro/70_report.py @@ -20,8 +20,10 @@ building a report. As usual, we will start by importing the modules and data we need: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import tempfile diff --git a/tutorials/inverse/10_stc_class.py b/tutorials/inverse/10_stc_class.py index 8638b4eaf2a..4c10fb05446 100644 --- a/tutorials/inverse/10_stc_class.py +++ b/tutorials/inverse/10_stc_class.py @@ -52,8 +52,10 @@ is. We first set up the environment and load some data: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% from mne import read_source_estimate diff --git a/tutorials/inverse/20_dipole_fit.py b/tutorials/inverse/20_dipole_fit.py index 958ff809ede..2b640aa8fc2 100644 --- a/tutorials/inverse/20_dipole_fit.py +++ b/tutorials/inverse/20_dipole_fit.py @@ -11,8 +11,10 @@ `this gist `__. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import matplotlib.pyplot as plt diff --git a/tutorials/inverse/30_mne_dspm_loreta.py b/tutorials/inverse/30_mne_dspm_loreta.py index f8a93e73474..923ee534d71 100644 --- a/tutorials/inverse/30_mne_dspm_loreta.py +++ b/tutorials/inverse/30_mne_dspm_loreta.py @@ -9,8 +9,10 @@ minimum-norm inverse method on evoked/raw/epochs data. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import matplotlib.pyplot as plt diff --git a/tutorials/inverse/35_dipole_orientations.py b/tutorials/inverse/35_dipole_orientations.py index 6e2260e3fdb..99ddb8f0657 100644 --- a/tutorials/inverse/35_dipole_orientations.py +++ b/tutorials/inverse/35_dipole_orientations.py @@ -15,8 +15,10 @@ See :ref:`inverse_orientation_constraints` for related information. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% # Load data # --------- diff --git a/tutorials/inverse/60_visualize_stc.py b/tutorials/inverse/60_visualize_stc.py index d9c7cd58134..78301c4ee88 100644 --- a/tutorials/inverse/60_visualize_stc.py +++ b/tutorials/inverse/60_visualize_stc.py @@ -12,8 +12,10 @@ First, we get the paths for the evoked data and the source time courses (stcs). """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import matplotlib.pyplot as plt diff --git a/tutorials/inverse/70_eeg_mri_coords.py b/tutorials/inverse/70_eeg_mri_coords.py index 9783435f26c..20d6b62e4c9 100644 --- a/tutorials/inverse/70_eeg_mri_coords.py +++ b/tutorials/inverse/70_eeg_mri_coords.py @@ -5,8 +5,8 @@ EEG source localization given electrode locations on an MRI =========================================================== -This tutorial explains how to compute the forward operator from EEG data when -the electrodes are in MRI voxel coordinates. +This tutorial explains how to compute the forward operator from EEG data when the +electrodes are in MRI voxel coordinates. """ # Authors: Eric Larson @@ -104,7 +104,12 @@ # You can also verify that these are correct (or manually convert voxels # to MRI coords) by looking at the points in Freeview or tkmedit. -dig_montage = read_custom_montage(fname_mon, head_size=None, coord_frame="mri") +dig_montage = read_custom_montage( + fname_mon, + head_size=None, + coord_frame="mri", + verbose="error", # because it contains a duplicate point +) dig_montage.plot() ############################################################################## diff --git a/tutorials/io/10_reading_meg_data.py b/tutorials/io/10_reading_meg_data.py index 14cc31ff8b5..90ad8a44693 100644 --- a/tutorials/io/10_reading_meg_data.py +++ b/tutorials/io/10_reading_meg_data.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + r""" .. _tut-imorting-meg-data: diff --git a/tutorials/io/20_reading_eeg_data.py b/tutorials/io/20_reading_eeg_data.py index 94f4f644ccc..2544e57f60c 100644 --- a/tutorials/io/20_reading_eeg_data.py +++ b/tutorials/io/20_reading_eeg_data.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + r""" .. _tut-imorting-eeg-data: @@ -118,6 +120,7 @@ non-data channel does not fit to the sphere, it is assigned a z-value of 0. .. warning:: + Reading channel locations from the file header may be dangerous, as the x_coord and y_coord in the ELECTLOC section of the header do not necessarily translate to absolute locations. Furthermore, EEG electrode locations that @@ -125,6 +128,32 @@ If you are not sure about the channel locations in the header, using a montage is encouraged. +.. warning:: + + ANT Neuro also uses a file format with the ``.cnt`` extension, but it is different + from the Neuroscan CNT format. The ANT Neuro format is supported by the function + :func:`mne.io.read_raw_ant`. + + +.. _import-ant: + +ANT Neuro CNT (.cnt) +==================== + +CNT files from the eego software of ANT Neuro can be read using +:func:`mne.io.read_raw_ant`. The channels can be automatically recognized as auxiliary +``'misc'`` channels if the regular expression in the argument ``misc`` correctly +captures the channel names. Same for EOG channels with the regular expression in the +argument ``eog``. Note that if a montage with specific bipolar channels is applied on +export, they can be loaded as EEG bipolar channel pairs by providing the argument +``bipolars``. All other EEG channels will be loaded as regular EEG channels referenced +to the same electrode. + +.. warning:: + + Neuroscan also uses a file format with the ``.cnt`` extension, but it is different + from the eego CNT format. The Neuroscan CNT format is supported by the function + :func:`mne.io.read_raw_cnt`. .. _import-egi: @@ -246,6 +275,6 @@ When using locations of fiducial points, the digitization data are converted to the MEG head coordinate system employed in the MNE software, see :ref:`coordinate_systems`. -""" # noqa:E501 +""" # noqa: E501 # %% diff --git a/tutorials/io/30_reading_fnirs_data.py b/tutorials/io/30_reading_fnirs_data.py index 017664be61e..a40935e9e19 100644 --- a/tutorials/io/30_reading_fnirs_data.py +++ b/tutorials/io/30_reading_fnirs_data.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + r""" .. _tut-importing-fnirs-data: diff --git a/tutorials/io/70_reading_eyetracking_data.py b/tutorials/io/70_reading_eyetracking_data.py index 781b89fab9e..3cf72719e4c 100644 --- a/tutorials/io/70_reading_eyetracking_data.py +++ b/tutorials/io/70_reading_eyetracking_data.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + r""" .. _tut-importing-eyetracking-data: @@ -76,29 +78,43 @@ new line, the y-coordinate *increased*, which is why the ``ypos_right`` channel in the plot below increases over time (for example, at about 4-seconds, and at about 8-seconds). + +.. seealso:: + + :ref:`tut-eyetrack` """ # %% -from mne.datasets import misc -from mne.io import read_raw_eyelink +import mne # %% -fpath = misc.data_path() / "eyetracking" / "eyelink" -raw = read_raw_eyelink(fpath / "px_textpage_ws.asc", create_annotations=["blinks"]) -custom_scalings = dict(eyegaze=1e3) -raw.pick(picks="eyetrack").plot(scalings=custom_scalings) +fpath = mne.datasets.misc.data_path() / "eyetracking" / "eyelink" +fname = fpath / "px_textpage_ws.asc" +raw = mne.io.read_raw_eyelink(fname, create_annotations=["blinks"]) +cal = mne.preprocessing.eyetracking.read_eyelink_calibration( + fname, + screen_distance=0.7, + screen_size=(0.53, 0.3), + screen_resolution=(1920, 1080), +)[0] +mne.preprocessing.eyetracking.convert_units(raw, calibration=cal, to="radians") +# %% +# Visualizing the data +# ^^^^^^^^^^^^^^^^^^^^ # %% -# .. important:: The (0, 0) pixel coordinates are at the top-left of the -# trackable area of the screen. Gaze towards lower areas of the -# the screen will yield a relatively higher y-coordinate. -# -# Note that we passed a custom `dict` to the ``'scalings'`` argument of -# `mne.io.Raw.plot`. This is because MNE's default plot scalings for eye -# position data are calibrated for HREF data, which are stored in radians -# (read below). +cal.plot() +# %% +custom_scalings = dict(pupil=1e3) +raw.pick(picks="eyetrack").plot(scalings=custom_scalings) + +# %% +# Note that we passed a custom `dict` to the ``'scalings'`` argument of +# `mne.io.Raw.plot`. This is because MNE expects the data to be in SI units +# (radians for eyegaze data, and meters for pupil size data), but we did not convert +# the pupil size data in this example. # %% # Head-Referenced Eye Angle (HREF) @@ -122,9 +138,11 @@ # %% -fpath = misc.data_path() / "eyetracking" / "eyelink" -raw = read_raw_eyelink(fpath / "HREF_textpage_ws.asc", create_annotations=["blinks"]) -raw.pick(picks="eyetrack").plot() +fpath = mne.datasets.misc.data_path() / "eyetracking" / "eyelink" +fname_href = fpath / "HREF_textpage_ws.asc" +raw = mne.io.read_raw_eyelink(fname_href, create_annotations=["blinks"]) +custom_scalings = dict(pupil=1e3) +raw.pick(picks="eyetrack").plot(scalings=custom_scalings) # %% # Pupil Position diff --git a/tutorials/machine-learning/50_decoding.py b/tutorials/machine-learning/50_decoding.py index 01820ef0043..c2a56ce0555 100644 --- a/tutorials/machine-learning/50_decoding.py +++ b/tutorials/machine-learning/50_decoding.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + r""" .. _tut-mvpa: diff --git a/tutorials/preprocessing/10_preprocessing_overview.py b/tutorials/preprocessing/10_preprocessing_overview.py index d70fa4b4811..b7679579b26 100644 --- a/tutorials/preprocessing/10_preprocessing_overview.py +++ b/tutorials/preprocessing/10_preprocessing_overview.py @@ -12,8 +12,10 @@ :ref:`example data `: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/preprocessing/15_handling_bad_channels.py b/tutorials/preprocessing/15_handling_bad_channels.py index 7ddc36af026..80b2b7315d3 100644 --- a/tutorials/preprocessing/15_handling_bad_channels.py +++ b/tutorials/preprocessing/15_handling_bad_channels.py @@ -12,8 +12,10 @@ data: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/preprocessing/20_rejecting_bad_data.py b/tutorials/preprocessing/20_rejecting_bad_data.py index a04005f3532..749ed42d2c9 100644 --- a/tutorials/preprocessing/20_rejecting_bad_data.py +++ b/tutorials/preprocessing/20_rejecting_bad_data.py @@ -17,8 +17,10 @@ array to use when converting the continuous data to epochs: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/preprocessing/25_background_filtering.py b/tutorials/preprocessing/25_background_filtering.py index dc035b61f86..537da6a22b2 100644 --- a/tutorials/preprocessing/25_background_filtering.py +++ b/tutorials/preprocessing/25_background_filtering.py @@ -1,5 +1,7 @@ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + r""" .. _disc-filtering: diff --git a/tutorials/preprocessing/30_filtering_resampling.py b/tutorials/preprocessing/30_filtering_resampling.py index cf9b3335949..e4ebccbc28d 100644 --- a/tutorials/preprocessing/30_filtering_resampling.py +++ b/tutorials/preprocessing/30_filtering_resampling.py @@ -13,8 +13,10 @@ (to save memory on the documentation server): """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/preprocessing/35_artifact_correction_regression.py b/tutorials/preprocessing/35_artifact_correction_regression.py index 30416ec0f41..77e7447c268 100644 --- a/tutorials/preprocessing/35_artifact_correction_regression.py +++ b/tutorials/preprocessing/35_artifact_correction_regression.py @@ -38,8 +38,10 @@ blink artifacts, especially during the presentation of visual stimuli. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import numpy as np diff --git a/tutorials/preprocessing/40_artifact_correction_ica.py b/tutorials/preprocessing/40_artifact_correction_ica.py index fc3e8865ec2..87db02be1f8 100644 --- a/tutorials/preprocessing/40_artifact_correction_ica.py +++ b/tutorials/preprocessing/40_artifact_correction_ica.py @@ -18,8 +18,10 @@ and classes from that submodule: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/preprocessing/45_projectors_background.py b/tutorials/preprocessing/45_projectors_background.py index 00de570229b..128229e516a 100644 --- a/tutorials/preprocessing/45_projectors_background.py +++ b/tutorials/preprocessing/45_projectors_background.py @@ -14,8 +14,10 @@ function to make it easier to make several plots that look similar: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/preprocessing/50_artifact_correction_ssp.py b/tutorials/preprocessing/50_artifact_correction_ssp.py index bc0b9081f64..57be25803d5 100644 --- a/tutorials/preprocessing/50_artifact_correction_ssp.py +++ b/tutorials/preprocessing/50_artifact_correction_ssp.py @@ -15,8 +15,10 @@ functions from that submodule: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/preprocessing/55_setting_eeg_reference.py b/tutorials/preprocessing/55_setting_eeg_reference.py index 22e247469ee..770af624de7 100644 --- a/tutorials/preprocessing/55_setting_eeg_reference.py +++ b/tutorials/preprocessing/55_setting_eeg_reference.py @@ -13,8 +13,10 @@ just a few EEG channels so the plots are easier to see: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/preprocessing/60_maxwell_filtering_sss.py b/tutorials/preprocessing/60_maxwell_filtering_sss.py index e0062d3bbe8..73c0bd5a73f 100644 --- a/tutorials/preprocessing/60_maxwell_filtering_sss.py +++ b/tutorials/preprocessing/60_maxwell_filtering_sss.py @@ -12,8 +12,10 @@ :ref:`example data `, and cropping it to save on memory: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/preprocessing/70_fnirs_processing.py b/tutorials/preprocessing/70_fnirs_processing.py index f197b2229b8..c7efa46c06c 100644 --- a/tutorials/preprocessing/70_fnirs_processing.py +++ b/tutorials/preprocessing/70_fnirs_processing.py @@ -12,8 +12,10 @@ Here we will work with the :ref:`fNIRS motor data `. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% from itertools import compress diff --git a/tutorials/preprocessing/80_opm_processing.py b/tutorials/preprocessing/80_opm_processing.py index 8d1642d88b8..25c30778a42 100644 --- a/tutorials/preprocessing/80_opm_processing.py +++ b/tutorials/preprocessing/80_opm_processing.py @@ -21,8 +21,10 @@ :footcite:`SeymourEtAl2022` """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import matplotlib.pyplot as plt diff --git a/tutorials/preprocessing/90_eyetracking_data.py b/tutorials/preprocessing/90_eyetracking_data.py index bad4eeeda67..85f5d80bf82 100644 --- a/tutorials/preprocessing/90_eyetracking_data.py +++ b/tutorials/preprocessing/90_eyetracking_data.py @@ -99,16 +99,32 @@ first_cal.plot() +# %% +# Standardizing eyetracking data to SI units +# ------------------------------------------ +# +# EyeLink stores eyegaze positions in pixels, and pupil size in arbitrary units. +# MNE-Python expects eyegaze positions to be in radians of visual angle, and pupil +# size to be in meters. We can convert the eyegaze positions to radians using +# :func:`~mne.preprocessing.eyetracking.convert_units`. We'll pass the calibration +# object we created above, after specifying the screen resolution, screen size, and +# screen distance. + +first_cal["screen_resolution"] = (1920, 1080) +first_cal["screen_size"] = (0.53, 0.3) +first_cal["screen_distance"] = 0.9 +mne.preprocessing.eyetracking.convert_units(raw_et, calibration=first_cal, to="radians") + # %% # Plot the raw eye-tracking data # ------------------------------ # -# Let's plot the raw eye-tracking data. We'll pass a custom `dict` into -# the scalings argument to make the eyegaze channel traces legible when plotting, -# since this file contains pixel position data (as opposed to eye angles, -# which are reported in radians). +# Let's plot the raw eye-tracking data. Since we did not convert the pupil size to +# meters, we'll pass a custom `dict` into the scalings argument to make the pupil size +# traces legible when plotting. -raw_et.plot(scalings=dict(eyegaze=1e3)) +ps_scalings = dict(pupil=1e3) +raw_et.plot(scalings=ps_scalings) # %% # Handling blink artifacts @@ -189,7 +205,13 @@ picks_idx = mne.pick_channels( raw_et.ch_names, frontal + occipital + pupil, ordered=True ) -raw_et.plot(events=et_events, event_id=event_dict, event_color="g", order=picks_idx) +raw_et.plot( + events=et_events, + event_id=event_dict, + event_color="g", + order=picks_idx, + scalings=ps_scalings, +) # %% @@ -203,14 +225,16 @@ raw_et, events=et_events, event_id=event_dict, tmin=-0.3, tmax=3, baseline=None ) del raw_et # free up some memory -epochs[:8].plot(events=et_events, event_id=event_dict, order=picks_idx) +epochs[:8].plot( + events=et_events, event_id=event_dict, order=picks_idx, scalings=ps_scalings +) # %% # For this experiment, the participant was instructed to fixate on a crosshair in the # center of the screen. Let's plot the gaze position data to confirm that the # participant primarily kept their gaze fixated at the center of the screen. -plot_gaze(epochs, width=1920, height=1080) +plot_gaze(epochs, calibration=first_cal) # %% # .. seealso:: :ref:`tut-eyetrack-heatmap` diff --git a/tutorials/raw/10_raw_overview.py b/tutorials/raw/10_raw_overview.py index bf8fe20effd..3a69230f377 100644 --- a/tutorials/raw/10_raw_overview.py +++ b/tutorials/raw/10_raw_overview.py @@ -16,8 +16,10 @@ As usual we'll start by importing the modules we need: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/raw/20_event_arrays.py b/tutorials/raw/20_event_arrays.py index e66db1003b7..41e8829f91d 100644 --- a/tutorials/raw/20_event_arrays.py +++ b/tutorials/raw/20_event_arrays.py @@ -13,8 +13,10 @@ object to just 60 seconds before loading it into RAM to save memory: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/raw/30_annotate_raw.py b/tutorials/raw/30_annotate_raw.py index 99c40506b66..673917a13a8 100644 --- a/tutorials/raw/30_annotate_raw.py +++ b/tutorials/raw/30_annotate_raw.py @@ -14,8 +14,10 @@ seconds before loading it into RAM to save memory: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/raw/40_visualize_raw.py b/tutorials/raw/40_visualize_raw.py index 091f44a1493..1d08017e63c 100644 --- a/tutorials/raw/40_visualize_raw.py +++ b/tutorials/raw/40_visualize_raw.py @@ -13,8 +13,10 @@ :ref:`example data `, and cropping the `~mne.io.Raw` object to just 60 seconds before loading it into RAM to save memory: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import os diff --git a/tutorials/simulation/10_array_objs.py b/tutorials/simulation/10_array_objs.py index 4367d880207..ef3123bcf18 100644 --- a/tutorials/simulation/10_array_objs.py +++ b/tutorials/simulation/10_array_objs.py @@ -11,8 +11,10 @@ We begin by importing the necessary Python modules: """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import numpy as np diff --git a/tutorials/simulation/70_point_spread.py b/tutorials/simulation/70_point_spread.py index 74913e98ec1..485714e2c17 100644 --- a/tutorials/simulation/70_point_spread.py +++ b/tutorials/simulation/70_point_spread.py @@ -10,8 +10,10 @@ signal with point-spread by applying a forward and inverse solution. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import numpy as np diff --git a/tutorials/stats-sensor-space/20_erp_stats.py b/tutorials/stats-sensor-space/20_erp_stats.py index 2f0efa387db..b17f16d2618 100644 --- a/tutorials/stats-sensor-space/20_erp_stats.py +++ b/tutorials/stats-sensor-space/20_erp_stats.py @@ -15,8 +15,10 @@ short words. TFCE is described in :footcite:`SmithNichols2009`. """ +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + # %% import matplotlib.pyplot as plt diff --git a/tutorials/stats-sensor-space/70_cluster_rmANOVA_time_freq.py b/tutorials/stats-sensor-space/70_cluster_rmANOVA_time_freq.py index 19a90decea8..c8ec0c5f0d5 100644 --- a/tutorials/stats-sensor-space/70_cluster_rmANOVA_time_freq.py +++ b/tutorials/stats-sensor-space/70_cluster_rmANOVA_time_freq.py @@ -239,14 +239,16 @@ def stat_fun(*args): n_permutations=n_permutations, buffer_size=None, out_type="mask", + seed=0, ) # %% # Create new stats image with only significant clusters: good_clusters = np.where(cluster_p_values < 0.05)[0] -F_obs_plot = F_obs.copy() -F_obs_plot[~clusters[np.squeeze(good_clusters)]] = np.nan +F_obs_plot = np.full_like(F_obs, np.nan) +for ii in good_clusters: + F_obs_plot[clusters[ii]] = F_obs[clusters[ii]] fig, ax = plt.subplots(figsize=(6, 4), layout="constrained") for f_image, cmap in zip([F_obs, F_obs_plot], ["gray", "autumn"]): diff --git a/tutorials/time-freq/10_spectrum_class.py b/tutorials/time-freq/10_spectrum_class.py index 9d7eb9fae5d..62f6103bfdb 100644 --- a/tutorials/time-freq/10_spectrum_class.py +++ b/tutorials/time-freq/10_spectrum_class.py @@ -1,6 +1,8 @@ # noqa: E501 +# Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. + """ .. _tut-spectrum-class: diff --git a/tutorials/visualization/20_ui_events.py b/tutorials/visualization/20_ui_events.py index e119b5032c1..1c4038276f4 100644 --- a/tutorials/visualization/20_ui_events.py +++ b/tutorials/visualization/20_ui_events.py @@ -21,6 +21,7 @@ # # License: BSD-3-Clause # Copyright the MNE-Python contributors. + import matplotlib.pyplot as plt import mne