From 49af3330e7b84f5e2bb0f3edc3101484a143b07c Mon Sep 17 00:00:00 2001 From: Adam Li Date: Thu, 28 Apr 2022 14:57:12 -0400 Subject: [PATCH 1/5] Adding doc folder --- .flake8 | 26 ++ .gitignore | 3 + CONTRIBUTING.md | 177 ++++++++++++ LICENSE | 29 ++ MANIFEST.in | 12 +- Makefile | 21 +- README.md | 9 +- doc/Makefile | 190 ++++++++++++ doc/_static/favicon.ico | Bin 0 -> 7738 bytes doc/_static/js/copybutton.js | 63 ++++ doc/_static/mne_helmet.png | Bin 0 -> 27218 bytes doc/_static/mne_logo_small.png | Bin 0 -> 980 bytes doc/_static/style.css | 26 ++ doc/_templates/autosummary/class.rst | 10 + doc/_templates/autosummary/function.rst | 12 + doc/_templates/docs-navbar.html | 20 ++ doc/_templates/docs-toc.html | 13 + doc/_templates/layout.html | 19 ++ doc/_templates/version-switcher.html | 11 + doc/api.rst | 27 ++ doc/authors.inc | 1 + doc/bibliography.rst | 12 + doc/conf.py | 273 ++++++++++++++++++ doc/index.rst | 39 +++ doc/install.rst | 65 +++++ doc/make.bat | 242 ++++++++++++++++ doc/references.bib | 22 ++ doc/sphinxext/gh_substitutions.py | 33 +++ doc/whats_new.rst | 46 +++ doc/whats_new_previous_releases.rst | 20 ++ examples/automatic_artifact_correction_ica.py | 7 +- mne_icalabel/features.py | 38 +-- mne_icalabel/network.py | 6 +- mne_icalabel/tests/test_features.py | 95 ++---- mne_icalabel/tests/test_network.py | 35 +-- mne_icalabel/tests/test_utils.py | 26 +- mne_icalabel/utils.py | 24 +- pyproject.toml | 24 ++ requirements.txt | 3 +- requirements_testing.txt | 1 + setup.cfg | 9 + 41 files changed, 1523 insertions(+), 166 deletions(-) create mode 100644 .flake8 create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 doc/Makefile create mode 100644 doc/_static/favicon.ico create mode 100644 doc/_static/js/copybutton.js create mode 100644 doc/_static/mne_helmet.png create mode 100644 doc/_static/mne_logo_small.png create mode 100644 doc/_static/style.css create mode 100644 doc/_templates/autosummary/class.rst create mode 100644 doc/_templates/autosummary/function.rst create mode 100644 doc/_templates/docs-navbar.html create mode 100644 doc/_templates/docs-toc.html create mode 100755 doc/_templates/layout.html create mode 100644 doc/_templates/version-switcher.html create mode 100644 doc/api.rst create mode 100644 doc/authors.inc create mode 100644 doc/bibliography.rst create mode 100644 doc/conf.py create mode 100644 doc/index.rst create mode 100644 doc/install.rst create mode 100644 doc/make.bat create mode 100644 doc/references.bib create mode 100644 doc/sphinxext/gh_substitutions.py create mode 100644 doc/whats_new.rst create mode 100644 doc/whats_new_previous_releases.rst create mode 100644 pyproject.toml diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..3e17d8ea --- /dev/null +++ b/.flake8 @@ -0,0 +1,26 @@ + +[flake8] +max-line-length = 115 + +ignore = + # these rules don't play well with black + # whitespace before : + E203 + # line break before binary operator + W503 + E241,E305,W504,W605,E731 + + +exclude = + .venv + .git + __pycache__ + docs/build + dist + .mypy_cache + __init__.py + +per-file-ignores = + # __init__.py files are allowed to have unused imports and lines-too-long + */__init__.py:F401 + */**/**/__init__.py:F401,E501 diff --git a/.gitignore b/.gitignore index 7050154d..dd0e8599 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,9 @@ share/python-wheels/ .installed.cfg *.egg MANIFEST +_build/ +generated/ +auto_examples/ # PyInstaller # Usually these files are written by a python script from a template diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..71c21b91 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,177 @@ +# Contributing + +Thanks for considering contributing! Please read this document to learn the various ways you can contribute to this project and how to go about doing it. + +## Bug reports and feature requests + +### Did you find a bug? + +First, do [a quick search](https://github.com/mne-tools/mne-icalabel/issues) to see whether your issue has already been reported. +If your issue has already been reported, please comment on the existing issue. + +Otherwise, open [a new GitHub issue](https://github.com/mne-tools/mne-icalabel/issues). Be sure to include a clear title +and description. The description should include as much relevant information as possible. The description should +explain how to reproduce the erroneous behavior as well as the behavior you expect to see. Ideally you would include a +code sample or an executable test case demonstrating the expected behavior. + +### Do you have a suggestion for an enhancement or new feature? + +We use GitHub issues to track feature requests. Before you create an feature request: + +* Make sure you have a clear idea of the enhancement you would like. If you have a vague idea, consider discussing +it first on a GitHub issue. +* Check the documentation to make sure your feature does not already exist. +* Do [a quick search](https://github.com/mne-tools/mne-icalabel/issues) to see whether your feature has already been suggested. + +When creating your request, please: + +* Provide a clear title and description. +* Explain why the enhancement would be useful. It may be helpful to highlight the feature in other libraries. +* Include code examples to demonstrate how the enhancement would be used. + +## Making a pull request + +When you're ready to contribute code to address an open issue, please follow these guidelines to help us be able to review your pull request (PR) quickly. + +1. **Initial setup** (only do this once) + +
Expand details 👇
+ + If you haven't already done so, please [fork](https://help.github.com/en/enterprise/2.13/user/articles/fork-a-repo) this repository on GitHub. + + Then clone your fork locally with + + git clone https://github.com/USERNAME/mne-icalabel.git + + or + + git clone git@github.com:USERNAME/mne-icalabel.git + + At this point the local clone of your fork only knows that it came from *your* repo, github.com/USERNAME/mne-icalabel.git, but doesn't know anything the *main* repo, [https://github.com/mne-tools/mne-icalabel.git](https://github.com/mne-tools/mne-icalabel). You can see this by running + + git remote -v + + which will output something like this: + + origin https://github.com/USERNAME/mne-icalabel.git (fetch) + origin https://github.com/USERNAME/mne-icalabel.git (push) + + This means that your local clone can only track changes from your fork, but not from the main repo, and so you won't be able to keep your fork up-to-date with the main repo over time. Therefore you'll need to add another "remote" to your clone that points to [https://github.com/mne-tools/mne-icalabel.git](https://github.com/mne-tools/mne-icalabel). To do this, run the following: + + git remote add upstream https://github.com/mne-tools/mne-icalabel.git + + Now if you do `git remote -v` again, you'll see + + origin https://github.com/USERNAME/mne-icalabel.git (fetch) + origin https://github.com/USERNAME/mne-icalabel.git (push) + upstream https://github.com/mne-tools/mne-icalabel.git (fetch) + upstream https://github.com/mne-tools/mne-icalabel.git (push) + + Finally, you'll need to create a Python 3 virtual environment suitable for working on this project. There a number of tools out there that making working with virtual environments easier. + The most direct way is with the [`venv` module](https://docs.python.org/3.7/library/venv.html) in the standard library, but if you're new to Python or you don't already have a recent Python 3 version installed on your machine, + we recommend [Miniconda](https://docs.conda.io/en/latest/miniconda.html). + + On Mac, for example, you can install Miniconda with [Homebrew](https://brew.sh/): + + brew install miniconda + + Then you can create and activate a new Python environment by running: + + conda create -n mne-icalabel python=3.9 + conda activate mne-icalabel + + Once your virtual environment is activated, you can install your local clone in "editable mode" with + + pip install -U pip setuptools wheel + pip install -e .[dev] + + The "editable mode" comes from the `-e` argument to `pip`, and essential just creates a symbolic link from the site-packages directory of your virtual environment to the source code in your local clone. That way any changes you make will be immediately reflected in your virtual environment. + +
+ +2. **Ensure your fork is up-to-date** + +
Expand details 👇
+ + Once you've added an "upstream" remote pointing to [https://github.com/allenai/python-package-temlate.git](https://github.com/mne-tools/mne-icalabel), keeping your fork up-to-date is easy: + + git checkout main # if not already on main + git pull --rebase upstream main + git push + +
+ +3. **Create a new branch to work on your fix or enhancement** + +
Expand details 👇
+ + Committing directly to the main branch of your fork is not recommended. It will be easier to keep your fork clean if you work on a separate branch for each contribution you intend to make. + + You can create a new branch with + + # replace BRANCH with whatever name you want to give it + git checkout -b BRANCH + git push -u origin BRANCH + +
+ +4. **Test your changes** + +
Expand details 👇
+ + Our continuous integration (CI) testing runs [a number of checks](https://github.com/mne-tools/mne-icalabel/actions) for each pull request on [GitHub Actions](https://github.com/features/actions). You can run most of these tests locally, which is something you should do *before* opening a PR to help speed up the review process and make it easier for us. + + For convenience you can run a check for all style components necessary: + + make run-checks + + This will run isort, black, flake8, mypy, check-manifest, and pydocstyle on the entire repository. Please fix your errors if you see any. + + First, you should run [`isort`](https://github.com/PyCQA/isort) and [`black`](https://github.com/psf/black) to make sure you code is formatted consistently. + Many IDEs support code formatters as plugins, so you may be able to setup isort and black to run automatically every time you save. + For example, [`black.vim`](https://github.com/psf/black/tree/master/plugin) will give you this functionality in Vim. But both `isort` and `black` are also easy to run directly from the command line. + Just run this from the root of your clone: + + isort . + black . + + Our CI also uses [`flake8`](https://github.com/mne-tools/mne-icalabel/tree/main/tests) to lint the code base and [`mypy`](http://mypy-lang.org/) for type-checking. You should run both of these next with + + flake8 . + + and + + mypy . + + We also strive to maintain high test coverage, so most contributions should include additions to [the unit tests](https://github.com/mne-tools/mne-icalabel/tree/main/tests). These tests are run with [`pytest`](https://docs.pytest.org/en/latest/), which you can use to locally run any test modules that you've added or changed. + + For example, if you've fixed a bug in `causal_networkx/a/b.py`, you can run the tests specific to that module with + + pytest -v tests/a/b_test.py + + Our CI will automatically check that test coverage stays above a certain threshold (around 90%). To check the coverage locally in this example, you could run + + pytest -v --cov causal_networkx.a.b tests/a/b_test.py + + If your contribution involves additions to any public part of the API, we require that you write docstrings + for each function, method, class, or module that you add. + See the [Writing docstrings](#writing-docstrings) section below for details on the syntax. + You should test to make sure the API documentation can build without errors by running + + make docs + + If the build fails, it's most likely due to small formatting issues. If the error message isn't clear, feel free to comment on this in your pull request. + + And finally, please update the [CHANGELOG](https://github.com/mne-tools/mne-icalabel/blob/main/CHANGELOG.md) with notes on your contribution in the "Unreleased" section at the top. + + After all of the above checks have passed, you can now open [a new GitHub pull request](https://github.com/mne-tools/mne-icalabel/pulls). + Make sure you have a clear description of the problem and the solution, and include a link to relevant issues. + + We look forward to reviewing your PR! + +
+ +### Writing docstrings + +We use [Sphinx](https://www.sphinx-doc.org/en/master/index.html) to build our API docs, which automatically parses all docstrings +of public classes and methods. All docstrings should adhere to the [Numpy styling convention](https://www.sphinx-doc.org/en/master/usage/extensions/example_numpy.html). diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..e51514ef --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, MNE +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/MANIFEST.in b/MANIFEST.in index 31eca89c..cd7c8478 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,16 +1,22 @@ include *.png include *.txt +include *.md include Makefile + +# examples recursive-include examples *.py recursive-include examples *.txt + +# main files recursive-include mne_icalabel *.pt recursive-include mne_icalabel *.py -recursive-include test_data *.mat +exclude .circleci/config.yml + +# exclude all data files +recursive-exclude mne_icalabel *.txt recursive-exclude mne_icalabel *.fif recursive-exclude mne_icalabel *.m - -exclude .circleci/config.yml recursive-exclude mne_icalabel *.fdt recursive-exclude mne_icalabel *.mat recursive-exclude mne_icalabel *.set \ No newline at end of file diff --git a/Makefile b/Makefile index 57cfd69a..3c2de902 100644 --- a/Makefile +++ b/Makefile @@ -91,7 +91,7 @@ flake: black: @if command -v black > /dev/null; then \ echo "Running black"; \ - black --check mne_icalabel examples; \ + black mne_icalabel examples; \ else \ echo "black not found, please install it!"; \ exit 1; \ @@ -114,11 +114,30 @@ check-manifest: check-readme: python setup.py check --restructuredtext --strict +isort: + @if command -v isort > /dev/null; then \ + echo "Running isort"; \ + isort mne_icalabel examples; \ + else \ + echo "isort not found, please install it!"; \ + exit 1; \ + fi; + @echo "isort passed" + pep: @$(MAKE) -k black pydocstyle codespell-error check-manifest docstyle: pydocstyle +run-checks: + isort --check . + black --check mne_icalabel examples + flake8 . + mypy . + @$(MAKE) pydocstyle + check-manifest + @$(MAKE) codespell-error + build-doc: @echo "Building documentation" make -C doc/ clean diff --git a/README.md b/README.md index c3b72e81..883403b2 100644 --- a/README.md +++ b/README.md @@ -19,22 +19,23 @@ This package aims at automating that process conforming to the popular MNE-Pytho TBD. Add example code for how this works. # Documentation -TBD +[Stable version](https://mne.tools/mne-icalabel/stable/index.html) documentation. +[Dev version](https://mne.tools/mne-icalabel/dev/index.html) documentation. # Installation To get the latest code using [git](https://git-scm.com/), open a terminal and type: - git clone git://github.com/jacobf18/iclabel-python.git + git clone git://github.com/mne-tools/mne-icalabel.git cd iclabel-python pip install -e . or one can install directly using pip - pip install --user -U https://api.github.com/repos/jacobf18/iclabel-python/zipball/main + pip install --user -U https://api.github.com/repos/mne-tools/mne-icalabel/zipball/main Alternatively, you can also download a -`zip file of the latest development version `__. +`zip file of the latest development version `__. ## Converting MatConvNet to PyTorch diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 00000000..51a51428 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,190 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = -nWT --keep-going +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + -rm -rf auto_examples/ + -rm -rf generated/* + -rm -rf modules/generated/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +html-noplot: + $(SPHINXBUILD) -D plot_gallery=0 -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/project-template.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/project-template.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/project-template" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/project-template" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +view: + @python -c "import webbrowser; webbrowser.open_new_tab('file://$(PWD)/_build/html/index.html')" + +show: view diff --git a/doc/_static/favicon.ico b/doc/_static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b0a1b57a5574966eb13a3c8bfaf36f0337ed5367 GIT binary patch literal 7738 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 AQUCw| literal 0 HcmV?d00001 diff --git a/doc/_static/js/copybutton.js b/doc/_static/js/copybutton.js new file mode 100644 index 00000000..d87f5699 --- /dev/null +++ b/doc/_static/js/copybutton.js @@ -0,0 +1,63 @@ +$(document).ready(function() { + /* Add a [>>>] button on the top-right corner of code samples to hide + * the >>> and ... prompts and the output and thus make the code + * copyable. */ + var div = $('.highlight-python .highlight,' + + '.highlight-python3 .highlight,' + + '.highlight-pycon .highlight,' + + '.highlight-default .highlight') + var pre = div.find('pre'); + + // get the styles from the current theme + pre.parent().parent().css('position', 'relative'); + var hide_text = 'Hide the prompts and output'; + var show_text = 'Show the prompts and output'; + var border_width = pre.css('border-top-width'); + var border_style = pre.css('border-top-style'); + var border_color = pre.css('border-top-color'); + var button_styles = { + 'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0', + 'border-color': border_color, 'border-style': border_style, + 'border-width': border_width, 'color': border_color, 'text-size': '75%', + 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em', + 'border-radius': '0 3px 0 0' + } + + // create and add the button to all the code blocks that contain >>> + div.each(function(index) { + var jthis = $(this); + if (jthis.find('.gp').length > 0) { + var button = $('>>>'); + button.css(button_styles) + button.attr('title', hide_text); + button.data('hidden', 'false'); + jthis.prepend(button); + } + // tracebacks (.gt) contain bare text elements that need to be + // wrapped in a span to work with .nextUntil() (see later) + jthis.find('pre:has(.gt)').contents().filter(function() { + return ((this.nodeType == 3) && (this.data.trim().length > 0)); + }).wrap(''); + }); + + // define the behavior of the button when it's clicked + $('.copybutton').click(function(e){ + e.preventDefault(); + var button = $(this); + if (button.data('hidden') === 'false') { + // hide the code output + button.parent().find('.go, .gp, .gt').hide(); + button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden'); + button.css('text-decoration', 'line-through'); + button.attr('title', show_text); + button.data('hidden', 'true'); + } else { + // show the code output + button.parent().find('.go, .gp, .gt').show(); + button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible'); + button.css('text-decoration', 'none'); + button.attr('title', hide_text); + button.data('hidden', 'false'); + } + }); +}); diff --git a/doc/_static/mne_helmet.png b/doc/_static/mne_helmet.png new file mode 100644 index 0000000000000000000000000000000000000000..bb2124669ea5e251bf5370321e7e4e312a8ff28f GIT binary patch literal 27218 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 diff --git a/doc/_templates/docs-navbar.html b/doc/_templates/docs-navbar.html new file mode 100644 index 00000000..84f4ba4c --- /dev/null +++ b/doc/_templates/docs-navbar.html @@ -0,0 +1,20 @@ +{%- extends "pydata_sphinx_theme/docs-navbar.html" %} + +{%- block icon_links -%} + + + +{%- include "icon-links.html" with context -%} +{%- endblock %} diff --git a/doc/_templates/docs-toc.html b/doc/_templates/docs-toc.html new file mode 100644 index 00000000..97dc4a69 --- /dev/null +++ b/doc/_templates/docs-toc.html @@ -0,0 +1,13 @@ +{% set page_toc = generate_toc_html() %} + +{%- if page_toc | length >= 1 %} +
+ On this page +
+{%- endif %} + + + +{% include "edit_this_page.html" %} diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html new file mode 100755 index 00000000..6b3d45b5 --- /dev/null +++ b/doc/_templates/layout.html @@ -0,0 +1,19 @@ +{%- extends "pydata_sphinx_theme/layout.html" %} + +{% block fonts %} + + + + + +{% endblock %} + +{% block extrahead %} + + + +{{ super() }} +{% endblock %} diff --git a/doc/_templates/version-switcher.html b/doc/_templates/version-switcher.html new file mode 100644 index 00000000..add61722 --- /dev/null +++ b/doc/_templates/version-switcher.html @@ -0,0 +1,11 @@ + diff --git a/doc/api.rst b/doc/api.rst new file mode 100644 index 00000000..819023b3 --- /dev/null +++ b/doc/api.rst @@ -0,0 +1,27 @@ +### +API +### + +:py:mod:`mne_icalabel`: + +.. automodule:: mne_icalabel + :no-members: + :no-inherited-members: + +This is the application programming interface (API) reference +for classes (``CamelCase`` names) and functions +(``underscore_case`` names) of MNE-Connectivity, grouped thematically by analysis +stage. The data structure classes contain different types of connectivity data +and are described below. + +Most-used functions +=================== + +.. currentmodule:: mne_icalabel + +.. autosummary:: + :toctree: generated/ + + label_components + generate_features + ICLabelNet \ No newline at end of file diff --git a/doc/authors.inc b/doc/authors.inc new file mode 100644 index 00000000..14975a20 --- /dev/null +++ b/doc/authors.inc @@ -0,0 +1 @@ +.. _Adam Li: https://github.com/adam2392 diff --git a/doc/bibliography.rst b/doc/bibliography.rst new file mode 100644 index 00000000..4a310352 --- /dev/null +++ b/doc/bibliography.rst @@ -0,0 +1,12 @@ +:orphan: + +.. _general_bibliography: + +General bibliography +==================== + +The references below are arranged alphabetically by first author. + +.. bibliography:: ./references.bib + :all: + :list: enumerated diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 00000000..7f7a6550 --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,273 @@ +"""Configure details for documentation with sphinx.""" +from datetime import date +import os +import sys +import warnings + +import sphinx_gallery # noqa: F401 +from sphinx_gallery.sorting import ExampleTitleSortKey + +import mne +sys.path.insert(0, os.path.abspath("..")) +import mne_icalabel # noqa: E402 + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +curdir = os.path.dirname(__file__) +sys.path.append(os.path.abspath(os.path.join(curdir, '..'))) +sys.path.append(os.path.abspath(os.path.join(curdir, '..', 'mne_icalabel'))) +sys.path.append(os.path.abspath(os.path.join(curdir, 'sphinxext'))) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +needs_sphinx = '4.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx_autodoc_typehints', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', + 'sphinx_gallery.gen_gallery', + 'sphinxcontrib.bibtex', + 'numpydoc', + 'sphinx_copybutton', + 'gh_substitutions', # custom extension, see sphinxext/gh_substitutions.py +] + +# configure sphinx-copybutton +copybutton_prompt_text = r">>> |\.\.\. |\$ " +copybutton_prompt_is_regexp = True + +# generate autosummary even if no references +# -- sphinx.ext.autosummary +autosummary_generate = True + +autodoc_default_options = {'inherited-members': None} +autodoc_typehints = 'signature' + +# prevent jupyter notebooks from being run even if empty cell +# nbsphinx_execute = 'never' +# nbsphinx_allow_errors = True + +error_ignores = { + # These we do not live by: + 'GL01', # Docstring should start in the line immediately after the quotes + 'EX01', 'EX02', # examples failed (we test them separately) + 'ES01', # no extended summary + 'SA01', # no see also + 'YD01', # no yields section + 'SA04', # no description in See Also + 'PR04', # Parameter "shape (n_channels" has no type + 'RT02', # The first line of the Returns section should contain only the type, unless multiple values are being returned # noqa + # XXX should also verify that | is used rather than , to separate params + # XXX should maybe also restore the parameter-desc-length < 800 char check +} + +# -- numpydoc +# Below is needed to prevent errors +numpydoc_xref_param_type = True +numpydoc_class_members_toctree = False +numpydoc_attributes_as_param_list = True +numpydoc_use_blockquotes = True +numpydoc_xref_ignore = { + # words + 'instance', 'instances', 'of', 'default', 'shape', 'or', + 'with', 'length', 'pair', 'matplotlib', 'optional', 'kwargs', 'in', + 'dtype', 'object', 'self.verbose', + # shapes + 'n_times', 'obj', 'n_chan', 'n_epochs', 'n_picks', 'n_ch_groups', + 'n_node_names', 'n_tapers', 'n_signals', 'n_step', 'n_freqs', + 'epochs', 'freqs', 'times', 'arrays', 'lists', 'func', 'n_nodes', + 'n_estimated_nodes', 'n_samples', 'n_channels', 'Renderer', + 'n_ytimes', 'n_ychannels', 'n_events' +} +numpydoc_xref_aliases = { + # Python + 'file-like': ':term:`file-like `', + # Matplotlib + 'colormap': ':doc:`colormap `', + 'color': ':doc:`color `', + 'collection': ':doc:`collections `', + 'Axes': 'matplotlib.axes.Axes', + 'Figure': 'matplotlib.figure.Figure', + 'Axes3D': 'mpl_toolkits.mplot3d.axes3d.Axes3D', + 'PolarAxes': 'matplotlib.projections.polar.PolarAxes', + 'ColorbarBase': 'matplotlib.colorbar.ColorbarBase', + # joblib + 'joblib.Parallel': 'joblib.Parallel', + # MNE + 'Label': 'mne.Label', 'Forward': 'mne.Forward', 'Evoked': 'mne.Evoked', + 'Info': 'mne.Info', 'SourceSpaces': 'mne.SourceSpaces', + 'SourceMorph': 'mne.SourceMorph', + 'Epochs': 'mne.Epochs', 'Layout': 'mne.channels.Layout', + 'EvokedArray': 'mne.EvokedArray', 'BiHemiLabel': 'mne.BiHemiLabel', + 'AverageTFR': 'mne.time_frequency.AverageTFR', + 'EpochsTFR': 'mne.time_frequency.EpochsTFR', + 'Raw': 'mne.io.Raw', 'ICA': 'mne.preprocessing.ICA', +} +numpydoc_validate = True +numpydoc_validation_checks = {'all'} | set(error_ignores) +numpydoc_validation_exclude = { # set of regex + # dict subclasses + r'\.clear', r'\.get$', r'\.copy$', r'\.fromkeys', r'\.items', r'\.keys', + r'\.pop', r'\.popitem', r'\.setdefault', r'\.update', r'\.values', + # list subclasses + r'\.append', r'\.count', r'\.extend', r'\.index', r'\.insert', r'\.remove', + r'\.sort', + # we currently don't document these properly (probably okay) + r'\.__getitem__', r'\.__contains__', r'\.__hash__', r'\.__mul__', + r'\.__sub__', r'\.__add__', r'\.__iter__', r'\.__div__', r'\.__neg__', + r'plot_circle' +} + + +default_role = 'py:obj' + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'MNE-ICALabel' +td = date.today() +copyright = u'2021-%s, MNE Developers. Last updated on %s' % (td.year, + td.isoformat()) + +author = u'Adam Li' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = mne_icalabel.__version__ +# The full version, including alpha/beta/rc tags. +release = version + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', "**.ipynb_checkpoints"] + +# HTML options (e.g., theme) +# see: https://sphinx-bootstrap-theme.readthedocs.io/en/latest/README.html +# Clean up sidebar: Do not show "Source" link +html_show_sourcelink = False +html_copy_source = False + +html_theme = 'pydata_sphinx_theme' + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] +html_static_path = ['_static'] +html_css_files = ['style.css'] + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + 'icon_links': [ + dict(name='GitHub', + url='https://github.com/mne-tools/MNE-ICALabel', + icon='fab fa-github-square'), + ], + 'use_edit_page_button': False, + 'navigation_with_keys': False, + 'show_toc_level': 1, + 'navbar_end': ['version-switcher', 'navbar-icon-links'], +} +# Custom sidebar templates, maps document names to template names. +html_sidebars = { + 'index': ['search-field.html'], +} + +html_context = { + 'versions_dropdown': { + 'dev': 'v0.1 (devel)', + }, +} + +# html_sidebars = {'**': ['localtoc.html']} + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + 'python': ('https://docs.python.org/3', None), + 'mne': ('https://mne.tools/dev', None), + 'numpy': ('https://numpy.org/devdocs', None), + 'scipy': ('https://scipy.github.io/devdocs', None), + 'matplotlib': ('https://matplotlib.org/stable', None), + 'pandas': ('https://pandas.pydata.org/pandas-docs/dev', None), + 'sklearn': ('https://scikit-learn.org/stable', None), + 'joblib': ('https://joblib.readthedocs.io/en/latest', None), + "torch": ("https://pytorch.org/docs/stable", None), +} +intersphinx_timeout = 5 + +# Resolve binder filepath_prefix. From the docs: +# "A prefix to append to the filepath in the Binder links. You should use this +# if you will store your built documentation in a sub-folder of a repository, +# instead of in the root." +# we will store dev docs in a `dev` subdirectory and all other docs in a +# directory "v" + version_str. E.g., "v0.3" +if 'dev' in version: + filepath_prefix = 'dev' +else: + filepath_prefix = 'v{}'.format(version) + +os.environ['_MNE_BUILDING_DOC'] = 'true' +scrapers = ('matplotlib',) +try: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + import pyvista + pyvista.OFF_SCREEN = False +except Exception: + pass +else: + scrapers += ('pyvista',) +if 'pyvista' in scrapers: + brain_scraper = mne.viz._brain._BrainScraper() + scrapers = list(scrapers) + scrapers.insert(scrapers.index('pyvista'), brain_scraper) + scrapers = tuple(scrapers) + +sphinx_gallery_conf = { + 'doc_module': 'mne_icalabel', + 'reference_url': { + 'mne_icalabel': None, + }, + 'backreferences_dir': 'generated', + 'plot_gallery': 'True', # Avoid annoying Unicode/bool default warning + 'within_subsection_order': ExampleTitleSortKey, + 'examples_dirs': ['../examples'], + 'gallery_dirs': ['auto_examples'], + 'filename_pattern': '^((?!sgskip).)*$', + 'matplotlib_animations': True, + 'compress_images': ('images', 'thumbnails'), + 'image_scrapers': scrapers, +} + +# sphinxcontrib-bibtex +bibtex_bibfiles = ['./references.bib'] +bibtex_style = 'unsrt' +bibtex_footbibliography_header = '' + + +# Enable nitpicky mode - which ensures that all references in the docs +# resolve. +nitpicky = True +nitpick_ignore = [] diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 00000000..20e931be --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,39 @@ +**mne-icalabel** +=================== + +mne-icalabel is a Python package for labeling independent components that stem +from an `Independent Component Analysis (ICA) `. + +We encourage you to use the package for your research and also build on top +with relevant Pull Requests. See our examples for walk-throughs of how to use the package. + +Contents +-------- + +.. toctree:: + :maxdepth: 2 + :caption: Getting started: + + whats_new + install + api + auto_examples/index + +.. toctree:: + :hidden: + :caption: Development + + License + Contributing + +License +------- + +**mne-icalabel** is licensed under `BSD 3.0 `_. +A full copy of the license can be found `on GitHub `_. + +Indices and tables +------------------ + +* :ref:`genindex` +* :ref:`modindex` diff --git a/doc/install.rst b/doc/install.rst new file mode 100644 index 00000000..db0d5f60 --- /dev/null +++ b/doc/install.rst @@ -0,0 +1,65 @@ +:orphan: + +Installation +============ + +Dependencies +------------ + +* ``mne`` (>=1.0) +* ``numpy`` (>=1.14) +* ``scipy`` (>=1.5.0) +* ``joblib`` (>=1.0.0) +* ``scikit-learn`` (>=1.1) +* ``torch`` (for running pytorch neural networks) +* ``python-picard`` (for running ICA) +* ``matplotlib`` (optional, for using the interactive data inspector) + +We require that you use Python 3.8 or higher. +You may choose to install ``mne-icalabel`` `via pip <#Installation via pip>`_, +or conda. + +Installation via Conda +---------------------- + +To install mne-icalabel using conda in a virtual environment, +simply run the following at the root of the repository: + +.. code-block:: bash + + # with python>=3.8 at least + conda create -n mne + conda activate mne + conda install -c conda-forge mne-icalabel + + +Installation via Pip +-------------------- + +To install mne-icalabel including all dependencies required to use all features, +simply run the following at the root of the repository: + +.. code-block:: bash + + python -m venv .venv + pip install -U mne-icalabel + +If you want to install a snapshot of the current development version, run: + +.. code-block:: bash + + pip install --user -U https://api.github.com/repos/mne-tools/mne-icalabel/zipball/main + +To check if everything worked fine, the following command should not give any +error messages: + +.. code-block:: bash + + python -c 'import mne_icalabel' + +mne-icalabel works best with the latest stable release of MNE-Python. To ensure +MNE-Python is up-to-date, run: + +.. code-block:: bash + + pip install --user -U mne diff --git a/doc/make.bat b/doc/make.bat new file mode 100644 index 00000000..79c1e198 --- /dev/null +++ b/doc/make.bat @@ -0,0 +1,242 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\project-template.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\project-template.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/doc/references.bib b/doc/references.bib new file mode 100644 index 00000000..4dd8060e --- /dev/null +++ b/doc/references.bib @@ -0,0 +1,22 @@ +% Encoding: UTF-8 +@article{AvantsEtAl2008, + author = {Avants, Brian B. and Epstein, Charles L. and Grossman, Murray C. and Gee, James C.}, + doi = {10.1016/j.media.2007.06.004}, + journal = {Medical Image Analysis}, + number = {1}, + pages = {26-41}, + shorttitle = {Symmetric Diffeomorphic Image Registration with Cross-Correlation}, + title = {Symmetric Diffeomorphic Image Registration with Cross-Correlation: Evaluating Automated Labeling of Elderly and Neurodegenerative Brain}, + volume = {12}, + year = {2008} +} + +@book{OppenheimEtAl1999, + address = {Upper Saddle River, NJ}, + edition = {2 edition}, + title = {Discrete-{Time} {Signal} {Processing}}, + isbn = {978-0-13-754920-7}, + publisher = {Prentice Hall}, + author = {Oppenheim, Alan V. and Schafer, Ronald W. and Buck, John R.}, + year = {1999} +} diff --git a/doc/sphinxext/gh_substitutions.py b/doc/sphinxext/gh_substitutions.py new file mode 100644 index 00000000..a1eddfbc --- /dev/null +++ b/doc/sphinxext/gh_substitutions.py @@ -0,0 +1,33 @@ +"""Provide a convenient way to link to GitHub issues and pull requests. + +Link to any issue or PR using :gh:`issue-or-pr-number`. + +Adapted from: +https://doughellmann.com/blog/2010/05/09/defining-custom-roles-in-sphinx/ + +""" +from docutils.nodes import reference +from docutils.parsers.rst.roles import set_classes + + +def gh_role(name, rawtext, text, lineno, inliner, options={}, content=[]): + """Link to a GitHub issue.""" + try: + # issue/PR mode (issues/PR-num will redirect to pull/PR-num) + int(text) + except ValueError: + # direct link mode + slug = text + else: + slug = 'issues/' + text + text = '#' + text + ref = 'https://github.com/mne-tools/mne-connectivity/' + slug + set_classes(options) + node = reference(rawtext, text, refuri=ref, **options) + return [node], [] + + +def setup(app): + """Do setup.""" + app.add_role('gh', gh_role) + return diff --git a/doc/whats_new.rst b/doc/whats_new.rst new file mode 100644 index 00000000..49a80c9a --- /dev/null +++ b/doc/whats_new.rst @@ -0,0 +1,46 @@ +:orphan: + +.. _whats_new: + + +What's new? +=========== + +Here we list a changelog of MNE-ICALabel. + +.. contents:: Contents + :local: + :depth: 3 + +.. currentmodule:: mne_icalabel + +.. _current: + +Version 0.1 (Unreleased) +------------------------ + +... + +Enhancements +~~~~~~~~~~~~ + + +Bug +~~~ + +- + +API +~~~ + +- + +Authors +~~~~~~~ + +* `Adam Li`_ +* `TODO fill in other authors name and add to authors.inc` + +:doc:`Find out what was new in previous releases ` + +.. include:: authors.inc diff --git a/doc/whats_new_previous_releases.rst b/doc/whats_new_previous_releases.rst new file mode 100644 index 00000000..a328fc16 --- /dev/null +++ b/doc/whats_new_previous_releases.rst @@ -0,0 +1,20 @@ +:orphan: + +.. _whats_new_in_previous_releases: + +.. currentmodule:: mne_connectivity + +What was new in previous releases? +================================== + +Version 0.1 (2022-03-01) +------------------------ + +Authors +~~~~~~~ + +People who contributed to this release (in alphabetical order): + +* `Adam Li`_ + +.. include:: authors.inc diff --git a/examples/automatic_artifact_correction_ica.py b/examples/automatic_artifact_correction_ica.py index d26d7a73..32f7dfc9 100644 --- a/examples/automatic_artifact_correction_ica.py +++ b/examples/automatic_artifact_correction_ica.py @@ -21,8 +21,9 @@ # %% import os + import mne -from mne.preprocessing import ICA, create_eog_epochs, create_ecg_epochs +from mne.preprocessing import ICA, create_ecg_epochs, create_eog_epochs sample_data_folder = mne.datasets.sample.data_path() sample_data_raw_file = os.path.join( @@ -204,7 +205,5 @@ ica.apply(reconst_raw) raw.plot(order=artifact_picks, n_channels=len(artifact_picks), show_scrollbars=False) -reconst_raw.plot( - order=artifact_picks, n_channels=len(artifact_picks), show_scrollbars=False -) +reconst_raw.plot(order=artifact_picks, n_channels=len(artifact_picks), show_scrollbars=False) del reconst_raw diff --git a/mne_icalabel/features.py b/mne_icalabel/features.py index c18b4f01..8330f702 100644 --- a/mne_icalabel/features.py +++ b/mne_icalabel/features.py @@ -1,13 +1,13 @@ -from typing import Union, Tuple +from typing import Tuple, Union +import numpy as np from mne import BaseEpochs from mne.io import BaseRaw from mne.preprocessing import ICA -import numpy as np from numpy.typing import NDArray from scipy.signal import resample_poly -from .utils import pol2cart, mne_to_eeglab_locs, gdatav4, _next_power_of_2 +from .utils import _next_power_of_2, gdatav4, mne_to_eeglab_locs, pol2cart def get_features(inst: Union[BaseRaw, BaseEpochs], ica: ICA): @@ -75,9 +75,7 @@ def retrieve_eeglab_icawinv( return icawinv, weights -def compute_ica_activations( - inst: Union[BaseRaw, BaseEpochs], ica: ICA -) -> NDArray[float]: +def compute_ica_activations(inst: Union[BaseRaw, BaseEpochs], ica: ICA) -> NDArray[float]: """Compute the ICA activations 'icaact' variable from an MNE ICA instance. Parameters @@ -119,9 +117,7 @@ def compute_ica_activations( # ---------------------------------------------------------------------------- -def eeg_topoplot( - inst: Union[BaseRaw, BaseEpochs], icawinv: NDArray[float] -) -> NDArray[float]: +def eeg_topoplot(inst: Union[BaseRaw, BaseEpochs], icawinv: NDArray[float]) -> NDArray[float]: """Topoplot feature.""" # TODO: Selection of channels is missing. ncomp = icawinv.shape[-1] @@ -135,9 +131,7 @@ def eeg_topoplot( return topo.astype(np.float32) -def _topoplotFast( - values: NDArray[float], rd: NDArray[float], th: NDArray[float] -) -> NDArray[float]: +def _topoplotFast(values: NDArray[float], rd: NDArray[float], th: NDArray[float]) -> NDArray[float]: """Implements topoplotFast.m from MATLAB. Each topographic map is a 32x32 images.""" # constants @@ -194,9 +188,7 @@ def _topoplotFast( # ---------------------------------------------------------------------------- -def eeg_rpsd( - inst: Union[BaseRaw, BaseEpochs], ica: ICA, icaact: NDArray[float] -) -> NDArray[float]: +def eeg_rpsd(inst: Union[BaseRaw, BaseEpochs], ica: ICA, icaact: NDArray[float]) -> NDArray[float]: """PSD feature.""" assert isinstance(inst, (BaseRaw, BaseEpochs)) # sanity-check constants = _eeg_rpsd_constants(inst, ica) @@ -271,9 +263,7 @@ def _eeg_rpsd_compute_psdmed( temp = np.hstack([icaact[it, index[:, k]] for k in range(index.shape[-1])]) temp = temp.reshape(*index.shape, order="F") elif isinstance(inst, BaseEpochs): - temp = np.hstack( - [icaact[it, index[:, k], :] for k in range(index.shape[-1])] - ) + temp = np.hstack([icaact[it, index[:, k], :] for k in range(index.shape[-1])]) temp = temp.reshape(index.shape[0], len(inst), order="F") else: raise RuntimeError # should never happen @@ -326,9 +316,7 @@ def _eeg_rpsd_format( return psd[:, :, np.newaxis, np.newaxis].transpose([2, 1, 3, 0]).astype(np.float32) -def eeg_autocorr_welch( - raw: BaseRaw, ica: ICA, icaact: NDArray[float] -) -> NDArray[float]: +def eeg_autocorr_welch(raw: BaseRaw, ica: ICA, icaact: NDArray[float]) -> NDArray[float]: """Autocorrelation feature applied on raw object with at least 5 * fs samples (5 seconds). MATLAB: 'eeg_autocorr_welch.m'.""" @@ -438,9 +426,7 @@ def eeg_autocorr(raw: BaseRaw, ica: ICA, icaact: NDArray[float]) -> NDArray[floa return resamp.astype(np.float32) -def eeg_autocorr_fftw( - epochs: BaseEpochs, ica: ICA, icaact: NDArray[float] -) -> NDArray[float]: +def eeg_autocorr_fftw(epochs: BaseEpochs, ica: ICA, icaact: NDArray[float]) -> NDArray[float]: """Autocorrelation feature applied on epoch object. MATLAB: 'eeg_autocorr_fftw.m'.""" assert isinstance(epochs, BaseEpochs) # sanity-check @@ -458,9 +444,7 @@ def eeg_autocorr_fftw( ac = np.fft.ifft(ac) if epochs.times.size < epochs.info["sfreq"]: - zeros = np.zeros( - (ac.shape[0], int(epochs.info["sfreq"]) - epochs.times.size + 1) - ) + zeros = np.zeros((ac.shape[0], int(epochs.info["sfreq"]) - epochs.times.size + 1)) ac = np.hstack([ac[:, : epochs.times.size], zeros]) else: ac = ac[:, : int(epochs.info["sfreq"]) + 1] diff --git a/mne_icalabel/network.py b/mne_icalabel/network.py index 969f01ee..b402992b 100644 --- a/mne_icalabel/network.py +++ b/mne_icalabel/network.py @@ -1,11 +1,11 @@ try: from importlib.resources import files except ImportError: - from importlib_resources import files + from importlib_resources import files # type: ignore -import torch.nn as nn -import torch import numpy as np +import torch +import torch.nn as nn from numpy.typing import ArrayLike diff --git a/mne_icalabel/tests/test_features.py b/mne_icalabel/tests/test_features.py index c538b607..3d212148 100644 --- a/mne_icalabel/tests/test_features.py +++ b/mne_icalabel/tests/test_features.py @@ -1,79 +1,60 @@ -try: - from importlib.resources import files -except ImportError: - from importlib_resources import files from pathlib import Path +import numpy as np +import pytest from mne import read_epochs_eeglab from mne.io import read_raw from mne.io.eeglab.eeglab import _check_load_mat from mne.preprocessing import read_ica_eeglab -import numpy as np from scipy.io import loadmat -import pytest from mne_icalabel.features import ( - retrieve_eeglab_icawinv, - compute_ica_activations, - get_features, - eeg_topoplot, - _topoplotFast, - _eeg_rpsd_constants, _eeg_rpsd_compute_psdmed, + _eeg_rpsd_constants, _eeg_rpsd_format, - eeg_autocorr_welch, + _topoplotFast, + compute_ica_activations, eeg_autocorr, eeg_autocorr_fftw, + eeg_autocorr_welch, + eeg_topoplot, + get_features, + retrieve_eeglab_icawinv, ) from mne_icalabel.utils import mne_to_eeglab_locs +try: + from importlib.resources import files +except ImportError: + from importlib_resources import files # type: ignore + # Raw/Epochs files with ICA decomposition -raw_eeglab_path = str( - files("mne_icalabel.tests").joinpath("data/datasets/sample-raw.set") -) +raw_eeglab_path = str(files("mne_icalabel.tests").joinpath("data/datasets/sample-raw.set")) raw_short_eeglab_path = str( files("mne_icalabel.tests").joinpath("data/datasets/sample-short-raw.set") ) raw_very_short_eeglab_path = str( files("mne_icalabel.tests").joinpath("data/datasets/sample-very-short-raw.set") ) -epo_eeglab_path = str( - files("mne_icalabel.tests").joinpath("data/datasets/sample-epo.set") -) +epo_eeglab_path = str(files("mne_icalabel.tests").joinpath("data/datasets/sample-epo.set")) # ICA activation matrix for raw/epochs -raw_icaact_eeglab_path = str( - files("mne_icalabel.tests").joinpath("data/icaact/icaact-raw.mat") -) -epo_icaact_eeglab_path = str( - files("mne_icalabel.tests").joinpath("data/icaact/icaact-epo.mat") -) +raw_icaact_eeglab_path = str(files("mne_icalabel.tests").joinpath("data/icaact/icaact-raw.mat")) +epo_icaact_eeglab_path = str(files("mne_icalabel.tests").joinpath("data/icaact/icaact-epo.mat")) # Topography raw_topo1_path = str(files("mne_icalabel.tests").joinpath("data/topo/topo1-raw.mat")) epo_topo1_path = str(files("mne_icalabel.tests").joinpath("data/topo/topo1-epo.mat")) -raw_topo_feature_path = str( - files("mne_icalabel.tests").joinpath("data/topo/topo-feature-raw.mat") -) -epo_topo_feature_path = str( - files("mne_icalabel.tests").joinpath("data/topo/topo-feature-epo.mat") -) +raw_topo_feature_path = str(files("mne_icalabel.tests").joinpath("data/topo/topo-feature-raw.mat")) +epo_topo_feature_path = str(files("mne_icalabel.tests").joinpath("data/topo/topo-feature-epo.mat")) # PSD -psd_constants_raw_path = str( - files("mne_icalabel.tests").joinpath("data/psd/constants-raw.mat") -) -psd_steps_raw_path = str( - files("mne_icalabel.tests").joinpath("data/psd/psd-step-by-step-raw.mat") -) +psd_constants_raw_path = str(files("mne_icalabel.tests").joinpath("data/psd/constants-raw.mat")) +psd_steps_raw_path = str(files("mne_icalabel.tests").joinpath("data/psd/psd-step-by-step-raw.mat")) psd_raw_path = str(files("mne_icalabel.tests").joinpath("data/psd/psd-raw.mat")) -psd_constants_epo_path = str( - files("mne_icalabel.tests").joinpath("data/psd/constants-epo.mat") -) -psd_steps_epo_path = str( - files("mne_icalabel.tests").joinpath("data/psd/psd-step-by-step-epo.mat") -) +psd_constants_epo_path = str(files("mne_icalabel.tests").joinpath("data/psd/constants-epo.mat")) +psd_steps_epo_path = str(files("mne_icalabel.tests").joinpath("data/psd/psd-step-by-step-epo.mat")) psd_epo_path = str(files("mne_icalabel.tests").joinpath("data/psd/psd-epo.mat")) # Autocorrelations @@ -86,17 +67,11 @@ autocorr_very_short_raw_path = str( files("mne_icalabel.tests").joinpath("data/autocorr/autocorr-very-short-raw.mat") ) -autocorr_epo_path = str( - files("mne_icalabel.tests").joinpath("data/autocorr/autocorr-epo.mat") -) +autocorr_epo_path = str(files("mne_icalabel.tests").joinpath("data/autocorr/autocorr-epo.mat")) # Complete features -features_raw_path = str( - files("mne_icalabel.tests").joinpath("data/features/features-raw.mat") -) -features_epo_path = str( - files("mne_icalabel.tests").joinpath("data/features/features-epo.mat") -) +features_raw_path = str(files("mne_icalabel.tests").joinpath("data/features/features-raw.mat")) +features_epo_path = str(files("mne_icalabel.tests").joinpath("data/features/features-epo.mat")) # General readers @@ -114,9 +89,7 @@ (epo_eeglab_path, psd_constants_epo_path, features_epo_path), ], ) -def test_get_features_from_precomputed_ica( - file, psd_constant_file, eeglab_feature_file -): +def test_get_features_from_precomputed_ica(file, psd_constant_file, eeglab_feature_file): """Test that we get the correct set of features from an MNE instance. Corresponds to the output from 'ICL_feature_extractor.m'.""" type_ = str(Path(file).stem)[-3:] @@ -242,9 +215,7 @@ def test_eeg_rpsd_constants(): # Raw -------------------------------------------------------------------- raw = read_raw(raw_eeglab_path, preload=True) ica = read_ica_eeglab(raw_eeglab_path) - ncomp, nfreqs, n_points, nyquist, index, window, subset = _eeg_rpsd_constants( - raw, ica - ) + ncomp, nfreqs, n_points, nyquist, index, window, subset = _eeg_rpsd_constants(raw, ica) constants_eeglab = loadmat(psd_constants_raw_path)["constants"][0, 0] ncomp_eeglab = constants_eeglab["ncomp"][0, 0] @@ -273,9 +244,7 @@ def test_eeg_rpsd_constants(): # Epochs ----------------------------------------------------------------- epochs = read_epochs_eeglab(epo_eeglab_path) ica = read_ica_eeglab(epo_eeglab_path) - ncomp, nfreqs, n_points, nyquist, index, window, subset = _eeg_rpsd_constants( - epochs, ica - ) + ncomp, nfreqs, n_points, nyquist, index, window, subset = _eeg_rpsd_constants(epochs, ica) constants_eeglab = loadmat(psd_constants_epo_path)["constants"][0, 0] ncomp_eeglab = constants_eeglab["ncomp"][0, 0] @@ -361,9 +330,7 @@ def test_eeg_rpsd(): subset_eeglab = constants_eeglab["subset"][0, :] - 1 # retrieve the rest from python - ncomp, nfreqs, n_points, nyquist, index, window, _ = _eeg_rpsd_constants( - epochs, ica - ) + ncomp, nfreqs, n_points, nyquist, index, window, _ = _eeg_rpsd_constants(epochs, ica) # compute psdmed psdmed = _eeg_rpsd_compute_psdmed( diff --git a/mne_icalabel/tests/test_network.py b/mne_icalabel/tests/test_network.py index d0f740f8..cbb7e807 100644 --- a/mne_icalabel/tests/test_network.py +++ b/mne_icalabel/tests/test_network.py @@ -1,21 +1,18 @@ try: from importlib.resources import files except ImportError: - from importlib_resources import files + from importlib_resources import files # type: ignore import numpy as np -from scipy.io import loadmat -import torch import pytest +import torch +from scipy.io import loadmat from mne_icalabel.network import ICLabelNet, format_input, run_iclabel - # Network weights torch_iclabel_path = str(files("mne_icalabel").joinpath("assets/iclabelNet.pt")) -matconvnet_iclabel_path = str( - files("mne_icalabel.tests").joinpath("data/network/netICL.mat") -) +matconvnet_iclabel_path = str(files("mne_icalabel.tests").joinpath("data/network/netICL.mat")) # Network forward pass input/output matconvnet_fw_input_path = str( @@ -26,12 +23,8 @@ ) # Features (similar to network_input) -features_raw_path = str( - files("mne_icalabel.tests").joinpath("data/features/features-raw.mat") -) -features_epo_path = str( - files("mne_icalabel.tests").joinpath("data/features/features-epo.mat") -) +features_raw_path = str(files("mne_icalabel.tests").joinpath("data/features/features-raw.mat")) +features_epo_path = str(files("mne_icalabel.tests").joinpath("data/features/features-epo.mat")) # Features formatted features_formatted_raw_path = str( @@ -42,12 +35,8 @@ ) # ICLabel output -iclabel_output_raw_path = str( - files("mne_icalabel.tests").joinpath("data/iclabel-output-raw.mat") -) -iclabel_output_epo_path = str( - files("mne_icalabel.tests").joinpath("data/iclabel-output-epo.mat") -) +iclabel_output_raw_path = str(files("mne_icalabel.tests").joinpath("data/iclabel-output-raw.mat")) +iclabel_output_epo_path = str(files("mne_icalabel.tests").joinpath("data/iclabel-output-epo.mat")) def test_weights(): @@ -64,9 +53,7 @@ def test_weights(): elif weight.ndim == 3: weights_matlab[k] = weight.transpose((2, 0, 1)) - network_python_layers = [ - layer for layer in network_python.keys() if "seq" not in layer - ] + network_python_layers = [layer for layer in network_python.keys() if "seq" not in layer] network_matlab_layers = [elt[0] for elt in network_matlab["params"]["name"][0, :]] # match layer names torch -> matconvnet @@ -181,9 +168,7 @@ def test_run_iclabel(eeglab_feature_file, eeglab_output_file): features retrieved in python in 'test_features.py:test_get_features'.""" features_eeglab = loadmat(eeglab_feature_file)["features"] # run the forward pass on pytorch - labels = run_iclabel( - features_eeglab[0, 0], features_eeglab[0, 1], features_eeglab[0, 2] - ) + labels = run_iclabel(features_eeglab[0, 0], features_eeglab[0, 1], features_eeglab[0, 2]) # load the labels from EEGLAB matlab_labels = loadmat(eeglab_output_file)["labels"] # (30, 7) diff --git a/mne_icalabel/tests/test_utils.py b/mne_icalabel/tests/test_utils.py index 2c898403..a705d749 100644 --- a/mne_icalabel/tests/test_utils.py +++ b/mne_icalabel/tests/test_utils.py @@ -1,25 +1,21 @@ try: from importlib.resources import files except ImportError: - from importlib_resources import files + from importlib_resources import files # type: ignore + from pathlib import Path +import numpy as np +import pytest from mne import read_epochs_eeglab from mne.io import read_raw -import numpy as np from scipy.io import loadmat -import pytest - -from mne_icalabel.utils import mne_to_eeglab_locs, gdatav4, _next_power_of_2 +from mne_icalabel.utils import _next_power_of_2, gdatav4, mne_to_eeglab_locs # Raw/Epochs files with ICA decomposition -raw_eeglab_path = str( - files("mne_icalabel.tests").joinpath("data/datasets/sample-raw.set") -) -epo_eeglab_path = str( - files("mne_icalabel.tests").joinpath("data/datasets/sample-epo.set") -) +raw_eeglab_path = str(files("mne_icalabel.tests").joinpath("data/datasets/sample-raw.set")) +epo_eeglab_path = str(files("mne_icalabel.tests").joinpath("data/datasets/sample-epo.set")) # Electrode locations @@ -27,12 +23,8 @@ loc_epo_path = str(files("mne_icalabel.tests").joinpath("data/utils/loc-raw.mat")) # Grid data interpolation -gdatav4_raw_path = str( - files("mne_icalabel.tests").joinpath("data/utils/gdatav4-raw.mat") -) -gdatav4_epo_path = str( - files("mne_icalabel.tests").joinpath("data/utils/gdatav4-epo.mat") -) +gdatav4_raw_path = str(files("mne_icalabel.tests").joinpath("data/utils/gdatav4-raw.mat")) +gdatav4_epo_path = str(files("mne_icalabel.tests").joinpath("data/utils/gdatav4-epo.mat")) # General readers diff --git a/mne_icalabel/utils.py b/mne_icalabel/utils.py index bc3890a8..7095ce0b 100644 --- a/mne_icalabel/utils.py +++ b/mne_icalabel/utils.py @@ -1,8 +1,8 @@ -from typing import Tuple, List +from typing import List, Tuple -from mne.io import BaseRaw -from numpy.typing import NDArray, ArrayLike import numpy as np +from mne.io import BaseRaw +from numpy.typing import ArrayLike, NDArray def mne_to_eeglab_locs(raw: BaseRaw) -> Tuple[NDArray[float], NDArray[float]]: @@ -77,9 +77,7 @@ def _cart2sph(_x, _y, _z): return rd.reshape([1, -1]), np.degrees(th).reshape([1, -1]) -def pol2cart( - theta: NDArray[float], rho: NDArray[float] -) -> Tuple[NDArray[float], NDArray[float]]: +def pol2cart(theta: NDArray[float], rho: NDArray[float]) -> Tuple[NDArray[float], NDArray[float]]: """ Converts polar coordinates to cartesian coordinates. @@ -145,9 +143,7 @@ def gdatav4( g = np.square(d) * (np.log(d) - 1) # Value of Green's function at zero g[np.where(np.isclose(d, 0))] = 0 - vq[i, j] = (np.expand_dims(g, axis=0) @ np.expand_dims(weights, axis=1))[0][ - 0 - ] + vq[i, j] = (np.expand_dims(g, axis=0) @ np.expand_dims(weights, axis=1))[0][0] return xq, yq, vq @@ -197,9 +193,7 @@ def mergepoints2D( return x, y, v -def mergesimpts( - data: ArrayLike, tols: List[ArrayLike], mode: str = "average" -) -> ArrayLike: +def mergesimpts(data: ArrayLike, tols: List[ArrayLike], mode: str = "average") -> ArrayLike: """ Args: @@ -213,15 +207,13 @@ def mergesimpts( data_ = data.copy()[np.argsort(data[:, 0])] newdata = [] tols_ = np.array(tols) - idxs_ready = [] + idxs_ready: List[int] = [] point = 0 for point in range(data_.shape[0]): if point in idxs_ready: continue else: - similar_pts = np.where( - np.prod(np.abs(data_ - data_[point]) < tols_, axis=-1) - ) + similar_pts = np.where(np.prod(np.abs(data_ - data_[point]) < tols_, axis=-1)) similar_pts = np.array(list(set(similar_pts[0].tolist()) - set(idxs_ready))) idxs_ready += similar_pts.tolist() if mode == "average": diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..e2f335cf --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,24 @@ +[tool.black] +line-length = 100 + +include = '\.pyi?$' + +exclude = ''' +( + __pycache__ + | \.git + | \.mypy_cache + | \.pytest_cache + | \.vscode + | \.venv + | \bdist\b + | \bdoc\b +) +''' +[tool.isort] +profile = "black" +multi_line_output = 3 + +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt index effab43c..0bd6558b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,4 @@ joblib mne python-picard scikit-learn -torch -sklearn \ No newline at end of file +torch \ No newline at end of file diff --git a/requirements_testing.txt b/requirements_testing.txt index 62e5d53c..4f269d73 100644 --- a/requirements_testing.txt +++ b/requirements_testing.txt @@ -16,3 +16,4 @@ mne-bids importlib_resources pymatreader black +isort \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index c8d70f18..06f990c6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -70,6 +70,15 @@ filterwarnings = # This is for Python 3.10+ and MNE <1.0 ignore:The distutils package is deprecated.*:DeprecationWarning +[mypy] +ignore_missing_imports = true +no_site_packages = true +allow_redefinition = True +exclude = _script.py + +[mypy-tests.*] +strict_optional = false + [pydocstyle] convention = pep257 match_dir = ^(?!\.|doc|examples).*$ From 29ada692a586ac3d968e0d0a7b6d5c2859ea136b Mon Sep 17 00:00:00 2001 From: Adam Li Date: Thu, 28 Apr 2022 16:13:26 -0400 Subject: [PATCH 2/5] Fix gh actions --- .github/workflows/unit_tests.yml | 2 +- requirements_doc.txt | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 76e04a52..8f953f7c 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -31,7 +31,7 @@ jobs: pip install --upgrade --upgrade-strategy eager -r requirements.txt pip install --upgrade --upgrade-strategy eager -r requirements_testing.txt - name: Run style & documentation tests - run: make pep + run: make run-checks # Run installation tests build: diff --git a/requirements_doc.txt b/requirements_doc.txt index 49330528..f1e36012 100644 --- a/requirements_doc.txt +++ b/requirements_doc.txt @@ -4,8 +4,6 @@ sphinx-gallery sphinx_rtd_theme sphinx-copybutton numpydoc -nibabel -nilearn pydata-sphinx-theme typing-extensions sphinx-autodoc-typehints From a1efd0a1bb43ccef2f8da7f4ee9b9e9205bf5f18 Mon Sep 17 00:00:00 2001 From: Adam Li Date: Thu, 28 Apr 2022 16:16:49 -0400 Subject: [PATCH 3/5] Fix sort --- doc/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 7f7a6550..2cbafd9b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,13 +1,13 @@ """Configure details for documentation with sphinx.""" -from datetime import date import os import sys import warnings +from datetime import date +import mne import sphinx_gallery # noqa: F401 from sphinx_gallery.sorting import ExampleTitleSortKey -import mne sys.path.insert(0, os.path.abspath("..")) import mne_icalabel # noqa: E402 From 9d681654995bbcdd802c8e27f71ce839a6615fbb Mon Sep 17 00:00:00 2001 From: Adam Li Date: Thu, 28 Apr 2022 16:18:54 -0400 Subject: [PATCH 4/5] Fix manfiest --- MANIFEST.in | 3 +++ Makefile | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index cd7c8478..28fe1416 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -12,6 +12,9 @@ recursive-include mne_icalabel *.pt recursive-include mne_icalabel *.py exclude .circleci/config.yml +exclude .flake8 + +recursive-exclude doc * # exclude all data files recursive-exclude mne_icalabel *.txt diff --git a/Makefile b/Makefile index 3c2de902..f6220f93 100644 --- a/Makefile +++ b/Makefile @@ -133,7 +133,7 @@ run-checks: isort --check . black --check mne_icalabel examples flake8 . - mypy . + mypy ./mne_icalabel @$(MAKE) pydocstyle check-manifest @$(MAKE) codespell-error From 7839bbb191a1700153fec7183df77622474aa002 Mon Sep 17 00:00:00 2001 From: Adam Li Date: Thu, 28 Apr 2022 16:29:04 -0400 Subject: [PATCH 5/5] Add mypy --- requirements_testing.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements_testing.txt b/requirements_testing.txt index 4f269d73..d02253bd 100644 --- a/requirements_testing.txt +++ b/requirements_testing.txt @@ -16,4 +16,5 @@ mne-bids importlib_resources pymatreader black -isort \ No newline at end of file +isort +mypy \ No newline at end of file