├── .github └── workflows │ ├── publish.yaml │ └── test.yaml ├── .gitignore ├── LICENSE ├── MOp_MERFISH_tutorial.ipynb ├── README.md ├── dist ├── scenvi-0.1.0-py3-none-any.whl ├── scenvi-0.1.0.tar.gz ├── scenvi-0.2.0-py3-none-any.whl ├── scenvi-0.2.0.tar.gz ├── scenvi-0.2.1-py3-none-any.whl ├── scenvi-0.2.1.tar.gz ├── scenvi-0.2.2-py3-none-any.whl ├── scenvi-0.2.2.tar.gz ├── scenvi-0.2.3-py3-none-any.whl ├── scenvi-0.2.3.tar.gz ├── scenvi-0.2.4-py3-none-any.whl ├── scenvi-0.2.4.tar.gz ├── scenvi-0.2.5-py3-none-any.whl ├── scenvi-0.2.5.tar.gz ├── scenvi-0.2.6-py3-none-any.whl └── scenvi-0.2.6.tar.gz ├── docs ├── Makefile ├── build │ ├── doctrees │ │ ├── ENVI.doctree │ │ ├── environment.pickle │ │ ├── index.doctree │ │ ├── nbsphinx │ │ │ ├── tutorial │ │ │ │ └── MOp_MERFISH_tutorial.ipynb │ │ │ ├── tutorial_MOp_MERFISH_tutorial_15_0.png │ │ │ ├── tutorial_MOp_MERFISH_tutorial_18_0.png │ │ │ ├── tutorial_MOp_MERFISH_tutorial_29_0.png │ │ │ ├── tutorial_MOp_MERFISH_tutorial_40_0.png │ │ │ ├── tutorial_MOp_MERFISH_tutorial_41_0.png │ │ │ ├── tutorial_MOp_MERFISH_tutorial_45_0.png │ │ │ ├── tutorial_MOp_MERFISH_tutorial_51_0.png │ │ │ └── tutorial_MOp_MERFISH_tutorial_54_0.png │ │ ├── tutorial │ │ │ └── MOp_MERFISH_tutorial.doctree │ │ └── utils.doctree │ └── html │ │ ├── .buildinfo │ │ ├── ENVI.html │ │ ├── _images │ │ ├── tutorial_MOp_MERFISH_tutorial_15_0.png │ │ ├── tutorial_MOp_MERFISH_tutorial_18_0.png │ │ ├── tutorial_MOp_MERFISH_tutorial_29_0.png │ │ ├── tutorial_MOp_MERFISH_tutorial_40_0.png │ │ ├── tutorial_MOp_MERFISH_tutorial_41_0.png │ │ ├── tutorial_MOp_MERFISH_tutorial_45_0.png │ │ ├── tutorial_MOp_MERFISH_tutorial_51_0.png │ │ └── tutorial_MOp_MERFISH_tutorial_54_0.png │ │ ├── _sources │ │ ├── ENVI.rst.txt │ │ ├── index.rst.txt │ │ ├── tutorial │ │ │ └── MOp_MERFISH_tutorial.ipynb.txt │ │ └── utils.rst.txt │ │ ├── _static │ │ ├── basic.css │ │ ├── debug.css │ │ ├── doctools.js │ │ ├── documentation_options.js │ │ ├── file.png │ │ ├── language_data.js │ │ ├── minus.png │ │ ├── nbsphinx-broken-thumbnail.svg │ │ ├── nbsphinx-code-cells.css │ │ ├── nbsphinx-gallery.css │ │ ├── nbsphinx-no-thumbnail.svg │ │ ├── plus.png │ │ ├── pygments.css │ │ ├── scripts │ │ │ ├── furo-extensions.js │ │ │ ├── furo.js │ │ │ ├── furo.js.LICENSE.txt │ │ │ └── furo.js.map │ │ ├── searchtools.js │ │ ├── skeleton.css │ │ ├── sphinx_highlight.js │ │ └── styles │ │ │ ├── furo-extensions.css │ │ │ ├── furo-extensions.css.map │ │ │ ├── furo.css │ │ │ └── furo.css.map │ │ ├── genindex.html │ │ ├── index.html │ │ ├── objects.inv │ │ ├── search.html │ │ ├── searchindex.js │ │ ├── tutorial │ │ ├── MOp_MERFISH_tutorial.html │ │ └── MOp_MERFISH_tutorial.ipynb │ │ └── utils.html ├── docs_requirements.txt ├── make.bat └── source │ ├── ENVI.rst │ ├── conf.py │ ├── index.rst │ ├── tutorial │ └── MOp_MERFISH_tutorial.ipynb │ └── utils.rst ├── pyproject.toml ├── readthedocs.yaml ├── scenvi ├── ENVI.py ├── __init__.py ├── __pycache__ │ ├── ENVI.cpython-39.pyc │ ├── __init__.cpython-38.pyc │ ├── __init__.cpython-39.pyc │ ├── dists.cpython-39.pyc │ └── utils.cpython-39.pyc ├── _dists.py └── utils.py └── tests └── test_ENVI.py /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish to PyPI 2 | on: 3 | pull_request: 4 | types: 5 | - closed 6 | branches: 7 | - main 8 | jobs: 9 | publish: 10 | if: github.event.pull_request.merged == true 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write # This is needed to push changes back to the repository 14 | steps: 15 | - uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 # Get full history for version tracking 18 | 19 | - name: Set up Python 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: '3.x' 23 | 24 | - name: Install Poetry 25 | uses: snok/install-poetry@v1 26 | with: 27 | version: '1.5.1' 28 | virtualenvs-create: true 29 | 30 | - name: Configure Git 31 | run: | 32 | git config --global user.name "github-actions[bot]" 33 | git config --global user.email "github-actions[bot]@users.noreply.github.com" 34 | 35 | - name: Update version and commit 36 | run: | 37 | # Get current version 38 | CURRENT_VERSION=$(poetry version -s) 39 | echo "Current version: $CURRENT_VERSION" 40 | 41 | # Bump patch version 42 | poetry version patch 43 | NEW_VERSION=$(poetry version -s) 44 | echo "New version: $NEW_VERSION" 45 | 46 | # Commit the version change 47 | git add pyproject.toml 48 | git commit -m "Bump version to $NEW_VERSION [skip ci]" 49 | git tag v$NEW_VERSION 50 | 51 | - name: Build and publish 52 | env: 53 | PYPI_API_TOKEN: ${{ secrets.PYPI_TOKEN }} 54 | run: | 55 | poetry config pypi-token.pypi "$PYPI_API_TOKEN" 56 | poetry build 57 | poetry publish --username __token__ --password "$PYPI_API_TOKEN" 58 | 59 | - name: Push changes to GitHub 60 | run: | 61 | git push origin HEAD:main 62 | git push origin v$(poetry version -s) -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: Test Mappers 5 | 6 | on: 7 | workflow_dispatch: 8 | pull_request: 9 | branches: [main] 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | python-version: ["3.10", "3.11", "3.12", "3.13"] 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Set up Python ${{ matrix.python-version }} 22 | uses: actions/setup-python@v3 23 | with: 24 | python-version: ${{ matrix.python-version }} 25 | - name: Install dependencies 26 | run: | 27 | python -m pip install --upgrade pip 28 | python -m pip install flake8 pytest 29 | - name: Install package 30 | run: | 31 | pip install -e . 32 | - name: Lint with flake8 33 | run: | 34 | # stop the build if there are Python syntax errors or undefined names 35 | flake8 . \ 36 | --count \ 37 | --select=E9,F63,F7,F82 \ 38 | --show-source \ 39 | --statistics \ 40 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 41 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 42 | - name: Test with pytest 43 | run: | 44 | pytest 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #https://github.com/github/gitignore/blob/main/Python.gitignore 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | .ipynb_checkpoints 12 | 13 | 14 | 15 | # Distribution / packaging 16 | .Python 17 | 18 | develop-eggs/ 19 | dist/ 20 | downloads/ 21 | eggs/ 22 | .eggs/ 23 | lib/ 24 | lib64/ 25 | parts/ 26 | sdist/ 27 | var/ 28 | wheels/ 29 | share/python-wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | MANIFEST 34 | 35 | # PyInstaller 36 | # Usually these files are written by a python script from a template 37 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .nox/ 49 | .coverage 50 | .coverage.* 51 | .cache 52 | nosetests.xml 53 | coverage.xml 54 | *.cover 55 | *.py,cover 56 | .hypothesis/ 57 | .pytest_cache/ 58 | cover/ 59 | 60 | # Translations 61 | *.mo 62 | *.pot 63 | 64 | # Django stuff: 65 | *.log 66 | local_settings.py 67 | db.sqlite3 68 | db.sqlite3-journal 69 | 70 | # Flask stuff: 71 | instance/ 72 | .webassets-cache 73 | 74 | # Scrapy stuff: 75 | .scrapy 76 | 77 | # Sphinx documentation 78 | docs/_build/ 79 | 80 | # PyBuilder 81 | .pybuilder/ 82 | target/ 83 | 84 | # Jupyter Notebook 85 | .ipynb_checkpoints 86 | 87 | # IPython 88 | profile_default/ 89 | ipython_config.py 90 | 91 | # pyenv 92 | # For a library or package, you might want to ignore these files since the code is 93 | # intended to run in multiple environments; otherwise, check them in: 94 | # .python-version 95 | 96 | # pipenv 97 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 98 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 99 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 100 | # install all needed dependencies. 101 | #Pipfile.lock 102 | 103 | # poetry 104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 105 | # This is especially recommended for binary packages to ensure reproducibility, and is more 106 | # commonly ignored for libraries. 107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 108 | #poetry.lock 109 | 110 | # pdm 111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 112 | #pdm.lock 113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 114 | # in version control. 115 | # https://pdm.fming.dev/#use-with-ide 116 | .pdm.toml 117 | 118 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 119 | __pypackages__/ 120 | 121 | # Celery stuff 122 | celerybeat-schedule 123 | celerybeat.pid 124 | 125 | # SageMath parsed files 126 | *.sage.py 127 | 128 | # Environments 129 | .env 130 | .venv 131 | env/ 132 | venv/ 133 | ENV/ 134 | env.bak/ 135 | venv.bak/ 136 | 137 | # Spyder project settings 138 | .spyderproject 139 | .spyproject 140 | 141 | # Rope project settings 142 | .ropeproject 143 | 144 | # mkdocs documentation 145 | /site 146 | 147 | # mypy 148 | .mypy_cache/ 149 | .dmypy.json 150 | dmypy.json 151 | 152 | # Pyre type checker 153 | .pyre/ 154 | 155 | # pytype static type analyzer 156 | .pytype/ 157 | 158 | # Cython debug symbols 159 | cython_debug/ 160 | 161 | # PyCharm 162 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 163 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 164 | # and can be added to the global gitignore or merged into this file. For a more nuclear 165 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 166 | #.idea 167 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 The Python Packaging Authority 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ENVI & COVET 2 | ====================== 3 | 4 | 5 | ENVI is a deep learnining based variational inference method to integrate scRNA-seq with spatial transcriptomics data. ENVI learns to reconstruct spatial onto for dissociated scRNA-seq data and impute unimagd genes onto spatial data. 6 | 7 | This implementation is written in Python3 and relies on jax, flax, sklearn, scipy and scanpy. 8 | 9 | 10 | To install JAX, simply run the command: 11 | 12 | pip install -U "jax[cuda12]" 13 | 14 | And to install ENVI along with the rest of the requirements: 15 | 16 | pip install scenvi 17 | 18 | To run ENVI: 19 | 20 | import scenvi 21 | 22 | envi_model = scenvi.ENVI(spatial_data = st_data, sc_data = sc_data) 23 | 24 | envi_model.train() 25 | envi_model.impute_genes() 26 | envi_model.infer_niche_covet() 27 | envi_model.infer_niche_celltype() 28 | 29 | st_data.obsm['envi_latent'] = envi_model.spatial_data.obsm['envi_latent'] 30 | st_data.uns['COVET_genes'] = envi_model.CovGenes 31 | st_data.obsm['COVET'] = envi_model.spatial_data.obsm['COVET'] 32 | st_data.obsm['COVET_SQRT'] = envi_model.spatial_data.obsm['COVET_SQRT'] 33 | st_data.obsm['cell_type_niche'] = envi_model.spatial_data.obsm['cell_type_niche'] 34 | st_data.obsm['imputation'] = envi_model.spatial_data.obsm['imputation'] 35 | 36 | 37 | sc_data.obsm['envi_latent'] = envi_model.sc_data.obsm['envi_latent'] 38 | sc_data.uns['COVET_genes'] = envi_model.CovGenes 39 | sc_data.obsm['COVET'] = envi_model.sc_data.obsm['COVET'] 40 | sc_data.obsm['COVET_SQRT'] = envi_model.sc_data.obsm['COVET_SQRT'] 41 | sc_data.obsm['cell_type_niche'] = envi_model.sc_data.obsm['cell_type_niche'] 42 | 43 | 44 | And to just compute COVET for spatial data: 45 | 46 | st_data.obsm['COVET'], st_data.obsm['COVET_SQRT'], st_data.uns['CovGenes'] = scenvi.compute_covet(st_data) 47 | 48 | Please read our documentation and see a full tutorial at https://scenvi.readthedocs.io/. 49 | -------------------------------------------------------------------------------- /dist/scenvi-0.1.0-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.1.0-py3-none-any.whl -------------------------------------------------------------------------------- /dist/scenvi-0.1.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.1.0.tar.gz -------------------------------------------------------------------------------- /dist/scenvi-0.2.0-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.0-py3-none-any.whl -------------------------------------------------------------------------------- /dist/scenvi-0.2.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.0.tar.gz -------------------------------------------------------------------------------- /dist/scenvi-0.2.1-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.1-py3-none-any.whl -------------------------------------------------------------------------------- /dist/scenvi-0.2.1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.1.tar.gz -------------------------------------------------------------------------------- /dist/scenvi-0.2.2-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.2-py3-none-any.whl -------------------------------------------------------------------------------- /dist/scenvi-0.2.2.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.2.tar.gz -------------------------------------------------------------------------------- /dist/scenvi-0.2.3-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.3-py3-none-any.whl -------------------------------------------------------------------------------- /dist/scenvi-0.2.3.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.3.tar.gz -------------------------------------------------------------------------------- /dist/scenvi-0.2.4-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.4-py3-none-any.whl -------------------------------------------------------------------------------- /dist/scenvi-0.2.4.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.4.tar.gz -------------------------------------------------------------------------------- /dist/scenvi-0.2.5-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.5-py3-none-any.whl -------------------------------------------------------------------------------- /dist/scenvi-0.2.5.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.5.tar.gz -------------------------------------------------------------------------------- /dist/scenvi-0.2.6-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.6-py3-none-any.whl -------------------------------------------------------------------------------- /dist/scenvi-0.2.6.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/dist/scenvi-0.2.6.tar.gz -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/build/doctrees/ENVI.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/ENVI.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_15_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_15_0.png -------------------------------------------------------------------------------- /docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_18_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_18_0.png -------------------------------------------------------------------------------- /docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_29_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_29_0.png -------------------------------------------------------------------------------- /docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_40_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_40_0.png -------------------------------------------------------------------------------- /docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_41_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_41_0.png -------------------------------------------------------------------------------- /docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_45_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_45_0.png -------------------------------------------------------------------------------- /docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_51_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_51_0.png -------------------------------------------------------------------------------- /docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_54_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/nbsphinx/tutorial_MOp_MERFISH_tutorial_54_0.png -------------------------------------------------------------------------------- /docs/build/doctrees/tutorial/MOp_MERFISH_tutorial.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/tutorial/MOp_MERFISH_tutorial.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/utils.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/doctrees/utils.doctree -------------------------------------------------------------------------------- /docs/build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: ef9216dd0783c9a330a1f77e3b1bbc54 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/build/html/ENVI.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ENVI - scenvi 0.3.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 38 | 39 | 40 | 43 | 44 | 45 | 46 | 47 | Contents 48 | 49 | 50 | 51 | 52 | 53 | Menu 54 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Expand 63 | 65 | 66 | 67 | 68 | 69 | Light mode 70 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Dark mode 85 | 87 | 88 | 89 | 90 | 91 | 92 | Auto light/dark mode 93 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 111 | 114 | 115 | 116 | 117 |
118 |
119 |
120 | 124 |
125 | 128 |
129 |
130 | 136 |
137 | 141 |
142 |
143 | 174 |
175 |
176 |
177 | 178 | 179 | 180 | 181 | Back to top 182 | 183 |
184 | 185 |
186 | 192 |
193 | 197 |
198 |
199 |
200 |

ENVI

201 |
202 | 203 |
204 |
205 | 245 |
246 | 251 |
252 |
253 | 254 | 255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_15_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_15_0.png -------------------------------------------------------------------------------- /docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_18_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_18_0.png -------------------------------------------------------------------------------- /docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_29_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_29_0.png -------------------------------------------------------------------------------- /docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_40_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_40_0.png -------------------------------------------------------------------------------- /docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_41_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_41_0.png -------------------------------------------------------------------------------- /docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_45_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_45_0.png -------------------------------------------------------------------------------- /docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_51_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_51_0.png -------------------------------------------------------------------------------- /docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_54_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_images/tutorial_MOp_MERFISH_tutorial_54_0.png -------------------------------------------------------------------------------- /docs/build/html/_sources/ENVI.rst.txt: -------------------------------------------------------------------------------- 1 | ENVI 2 | ========= 3 | 4 | .. automodule:: scenvi.ENVI 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/build/html/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. scenvi documentation master file, created by 2 | sphinx-quickstart on Wed Apr 24 12:13:12 2024. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | .. toctree:: 7 | :hidden: 8 | :caption: Tutorials: 9 | 10 | tutorial/MOp_MERFISH_tutorial 11 | 12 | .. toctree:: 13 | :hidden: 14 | :caption: Modules: 15 | 16 | ENVI 17 | Utilities 18 | 19 | 20 | .. mdinclude:: ../../README.md 21 | 22 | Index 23 | ===== 24 | 25 | * :ref:`genindex` 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/build/html/_sources/utils.rst.txt: -------------------------------------------------------------------------------- 1 | Utilities 2 | ========= 3 | 4 | .. automodule:: scenvi.utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/build/html/_static/basic.css: -------------------------------------------------------------------------------- 1 | /* 2 | * basic.css 3 | * ~~~~~~~~~ 4 | * 5 | * Sphinx stylesheet -- basic theme. 6 | * 7 | * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | /* -- main layout ----------------------------------------------------------- */ 13 | 14 | div.clearer { 15 | clear: both; 16 | } 17 | 18 | div.section::after { 19 | display: block; 20 | content: ''; 21 | clear: left; 22 | } 23 | 24 | /* -- relbar ---------------------------------------------------------------- */ 25 | 26 | div.related { 27 | width: 100%; 28 | font-size: 90%; 29 | } 30 | 31 | div.related h3 { 32 | display: none; 33 | } 34 | 35 | div.related ul { 36 | margin: 0; 37 | padding: 0 0 0 10px; 38 | list-style: none; 39 | } 40 | 41 | div.related li { 42 | display: inline; 43 | } 44 | 45 | div.related li.right { 46 | float: right; 47 | margin-right: 5px; 48 | } 49 | 50 | /* -- sidebar --------------------------------------------------------------- */ 51 | 52 | div.sphinxsidebarwrapper { 53 | padding: 10px 5px 0 10px; 54 | } 55 | 56 | div.sphinxsidebar { 57 | float: left; 58 | width: 230px; 59 | margin-left: -100%; 60 | font-size: 90%; 61 | word-wrap: break-word; 62 | overflow-wrap : break-word; 63 | } 64 | 65 | div.sphinxsidebar ul { 66 | list-style: none; 67 | } 68 | 69 | div.sphinxsidebar ul ul, 70 | div.sphinxsidebar ul.want-points { 71 | margin-left: 20px; 72 | list-style: square; 73 | } 74 | 75 | div.sphinxsidebar ul ul { 76 | margin-top: 0; 77 | margin-bottom: 0; 78 | } 79 | 80 | div.sphinxsidebar form { 81 | margin-top: 10px; 82 | } 83 | 84 | div.sphinxsidebar input { 85 | border: 1px solid #98dbcc; 86 | font-family: sans-serif; 87 | font-size: 1em; 88 | } 89 | 90 | div.sphinxsidebar #searchbox form.search { 91 | overflow: hidden; 92 | } 93 | 94 | div.sphinxsidebar #searchbox input[type="text"] { 95 | float: left; 96 | width: 80%; 97 | padding: 0.25em; 98 | box-sizing: border-box; 99 | } 100 | 101 | div.sphinxsidebar #searchbox input[type="submit"] { 102 | float: left; 103 | width: 20%; 104 | border-left: none; 105 | padding: 0.25em; 106 | box-sizing: border-box; 107 | } 108 | 109 | 110 | img { 111 | border: 0; 112 | max-width: 100%; 113 | } 114 | 115 | /* -- search page ----------------------------------------------------------- */ 116 | 117 | ul.search { 118 | margin: 10px 0 0 20px; 119 | padding: 0; 120 | } 121 | 122 | ul.search li { 123 | padding: 5px 0 5px 20px; 124 | background-image: url(file.png); 125 | background-repeat: no-repeat; 126 | background-position: 0 7px; 127 | } 128 | 129 | ul.search li a { 130 | font-weight: bold; 131 | } 132 | 133 | ul.search li p.context { 134 | color: #888; 135 | margin: 2px 0 0 30px; 136 | text-align: left; 137 | } 138 | 139 | ul.keywordmatches li.goodmatch a { 140 | font-weight: bold; 141 | } 142 | 143 | /* -- index page ------------------------------------------------------------ */ 144 | 145 | table.contentstable { 146 | width: 90%; 147 | margin-left: auto; 148 | margin-right: auto; 149 | } 150 | 151 | table.contentstable p.biglink { 152 | line-height: 150%; 153 | } 154 | 155 | a.biglink { 156 | font-size: 1.3em; 157 | } 158 | 159 | span.linkdescr { 160 | font-style: italic; 161 | padding-top: 5px; 162 | font-size: 90%; 163 | } 164 | 165 | /* -- general index --------------------------------------------------------- */ 166 | 167 | table.indextable { 168 | width: 100%; 169 | } 170 | 171 | table.indextable td { 172 | text-align: left; 173 | vertical-align: top; 174 | } 175 | 176 | table.indextable ul { 177 | margin-top: 0; 178 | margin-bottom: 0; 179 | list-style-type: none; 180 | } 181 | 182 | table.indextable > tbody > tr > td > ul { 183 | padding-left: 0em; 184 | } 185 | 186 | table.indextable tr.pcap { 187 | height: 10px; 188 | } 189 | 190 | table.indextable tr.cap { 191 | margin-top: 10px; 192 | background-color: #f2f2f2; 193 | } 194 | 195 | img.toggler { 196 | margin-right: 3px; 197 | margin-top: 3px; 198 | cursor: pointer; 199 | } 200 | 201 | div.modindex-jumpbox { 202 | border-top: 1px solid #ddd; 203 | border-bottom: 1px solid #ddd; 204 | margin: 1em 0 1em 0; 205 | padding: 0.4em; 206 | } 207 | 208 | div.genindex-jumpbox { 209 | border-top: 1px solid #ddd; 210 | border-bottom: 1px solid #ddd; 211 | margin: 1em 0 1em 0; 212 | padding: 0.4em; 213 | } 214 | 215 | /* -- domain module index --------------------------------------------------- */ 216 | 217 | table.modindextable td { 218 | padding: 2px; 219 | border-collapse: collapse; 220 | } 221 | 222 | /* -- general body styles --------------------------------------------------- */ 223 | 224 | div.body { 225 | min-width: 360px; 226 | max-width: 800px; 227 | } 228 | 229 | div.body p, div.body dd, div.body li, div.body blockquote { 230 | -moz-hyphens: auto; 231 | -ms-hyphens: auto; 232 | -webkit-hyphens: auto; 233 | hyphens: auto; 234 | } 235 | 236 | a.headerlink { 237 | visibility: hidden; 238 | } 239 | 240 | a:visited { 241 | color: #551A8B; 242 | } 243 | 244 | h1:hover > a.headerlink, 245 | h2:hover > a.headerlink, 246 | h3:hover > a.headerlink, 247 | h4:hover > a.headerlink, 248 | h5:hover > a.headerlink, 249 | h6:hover > a.headerlink, 250 | dt:hover > a.headerlink, 251 | caption:hover > a.headerlink, 252 | p.caption:hover > a.headerlink, 253 | div.code-block-caption:hover > a.headerlink { 254 | visibility: visible; 255 | } 256 | 257 | div.body p.caption { 258 | text-align: inherit; 259 | } 260 | 261 | div.body td { 262 | text-align: left; 263 | } 264 | 265 | .first { 266 | margin-top: 0 !important; 267 | } 268 | 269 | p.rubric { 270 | margin-top: 30px; 271 | font-weight: bold; 272 | } 273 | 274 | img.align-left, figure.align-left, .figure.align-left, object.align-left { 275 | clear: left; 276 | float: left; 277 | margin-right: 1em; 278 | } 279 | 280 | img.align-right, figure.align-right, .figure.align-right, object.align-right { 281 | clear: right; 282 | float: right; 283 | margin-left: 1em; 284 | } 285 | 286 | img.align-center, figure.align-center, .figure.align-center, object.align-center { 287 | display: block; 288 | margin-left: auto; 289 | margin-right: auto; 290 | } 291 | 292 | img.align-default, figure.align-default, .figure.align-default { 293 | display: block; 294 | margin-left: auto; 295 | margin-right: auto; 296 | } 297 | 298 | .align-left { 299 | text-align: left; 300 | } 301 | 302 | .align-center { 303 | text-align: center; 304 | } 305 | 306 | .align-default { 307 | text-align: center; 308 | } 309 | 310 | .align-right { 311 | text-align: right; 312 | } 313 | 314 | /* -- sidebars -------------------------------------------------------------- */ 315 | 316 | div.sidebar, 317 | aside.sidebar { 318 | margin: 0 0 0.5em 1em; 319 | border: 1px solid #ddb; 320 | padding: 7px; 321 | background-color: #ffe; 322 | width: 40%; 323 | float: right; 324 | clear: right; 325 | overflow-x: auto; 326 | } 327 | 328 | p.sidebar-title { 329 | font-weight: bold; 330 | } 331 | 332 | nav.contents, 333 | aside.topic, 334 | div.admonition, div.topic, blockquote { 335 | clear: left; 336 | } 337 | 338 | /* -- topics ---------------------------------------------------------------- */ 339 | 340 | nav.contents, 341 | aside.topic, 342 | div.topic { 343 | border: 1px solid #ccc; 344 | padding: 7px; 345 | margin: 10px 0 10px 0; 346 | } 347 | 348 | p.topic-title { 349 | font-size: 1.1em; 350 | font-weight: bold; 351 | margin-top: 10px; 352 | } 353 | 354 | /* -- admonitions ----------------------------------------------------------- */ 355 | 356 | div.admonition { 357 | margin-top: 10px; 358 | margin-bottom: 10px; 359 | padding: 7px; 360 | } 361 | 362 | div.admonition dt { 363 | font-weight: bold; 364 | } 365 | 366 | p.admonition-title { 367 | margin: 0px 10px 5px 0px; 368 | font-weight: bold; 369 | } 370 | 371 | div.body p.centered { 372 | text-align: center; 373 | margin-top: 25px; 374 | } 375 | 376 | /* -- content of sidebars/topics/admonitions -------------------------------- */ 377 | 378 | div.sidebar > :last-child, 379 | aside.sidebar > :last-child, 380 | nav.contents > :last-child, 381 | aside.topic > :last-child, 382 | div.topic > :last-child, 383 | div.admonition > :last-child { 384 | margin-bottom: 0; 385 | } 386 | 387 | div.sidebar::after, 388 | aside.sidebar::after, 389 | nav.contents::after, 390 | aside.topic::after, 391 | div.topic::after, 392 | div.admonition::after, 393 | blockquote::after { 394 | display: block; 395 | content: ''; 396 | clear: both; 397 | } 398 | 399 | /* -- tables ---------------------------------------------------------------- */ 400 | 401 | table.docutils { 402 | margin-top: 10px; 403 | margin-bottom: 10px; 404 | border: 0; 405 | border-collapse: collapse; 406 | } 407 | 408 | table.align-center { 409 | margin-left: auto; 410 | margin-right: auto; 411 | } 412 | 413 | table.align-default { 414 | margin-left: auto; 415 | margin-right: auto; 416 | } 417 | 418 | table caption span.caption-number { 419 | font-style: italic; 420 | } 421 | 422 | table caption span.caption-text { 423 | } 424 | 425 | table.docutils td, table.docutils th { 426 | padding: 1px 8px 1px 5px; 427 | border-top: 0; 428 | border-left: 0; 429 | border-right: 0; 430 | border-bottom: 1px solid #aaa; 431 | } 432 | 433 | th { 434 | text-align: left; 435 | padding-right: 5px; 436 | } 437 | 438 | table.citation { 439 | border-left: solid 1px gray; 440 | margin-left: 1px; 441 | } 442 | 443 | table.citation td { 444 | border-bottom: none; 445 | } 446 | 447 | th > :first-child, 448 | td > :first-child { 449 | margin-top: 0px; 450 | } 451 | 452 | th > :last-child, 453 | td > :last-child { 454 | margin-bottom: 0px; 455 | } 456 | 457 | /* -- figures --------------------------------------------------------------- */ 458 | 459 | div.figure, figure { 460 | margin: 0.5em; 461 | padding: 0.5em; 462 | } 463 | 464 | div.figure p.caption, figcaption { 465 | padding: 0.3em; 466 | } 467 | 468 | div.figure p.caption span.caption-number, 469 | figcaption span.caption-number { 470 | font-style: italic; 471 | } 472 | 473 | div.figure p.caption span.caption-text, 474 | figcaption span.caption-text { 475 | } 476 | 477 | /* -- field list styles ----------------------------------------------------- */ 478 | 479 | table.field-list td, table.field-list th { 480 | border: 0 !important; 481 | } 482 | 483 | .field-list ul { 484 | margin: 0; 485 | padding-left: 1em; 486 | } 487 | 488 | .field-list p { 489 | margin: 0; 490 | } 491 | 492 | .field-name { 493 | -moz-hyphens: manual; 494 | -ms-hyphens: manual; 495 | -webkit-hyphens: manual; 496 | hyphens: manual; 497 | } 498 | 499 | /* -- hlist styles ---------------------------------------------------------- */ 500 | 501 | table.hlist { 502 | margin: 1em 0; 503 | } 504 | 505 | table.hlist td { 506 | vertical-align: top; 507 | } 508 | 509 | /* -- object description styles --------------------------------------------- */ 510 | 511 | .sig { 512 | font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 513 | } 514 | 515 | .sig-name, code.descname { 516 | background-color: transparent; 517 | font-weight: bold; 518 | } 519 | 520 | .sig-name { 521 | font-size: 1.1em; 522 | } 523 | 524 | code.descname { 525 | font-size: 1.2em; 526 | } 527 | 528 | .sig-prename, code.descclassname { 529 | background-color: transparent; 530 | } 531 | 532 | .optional { 533 | font-size: 1.3em; 534 | } 535 | 536 | .sig-paren { 537 | font-size: larger; 538 | } 539 | 540 | .sig-param.n { 541 | font-style: italic; 542 | } 543 | 544 | /* C++ specific styling */ 545 | 546 | .sig-inline.c-texpr, 547 | .sig-inline.cpp-texpr { 548 | font-family: unset; 549 | } 550 | 551 | .sig.c .k, .sig.c .kt, 552 | .sig.cpp .k, .sig.cpp .kt { 553 | color: #0033B3; 554 | } 555 | 556 | .sig.c .m, 557 | .sig.cpp .m { 558 | color: #1750EB; 559 | } 560 | 561 | .sig.c .s, .sig.c .sc, 562 | .sig.cpp .s, .sig.cpp .sc { 563 | color: #067D17; 564 | } 565 | 566 | 567 | /* -- other body styles ----------------------------------------------------- */ 568 | 569 | ol.arabic { 570 | list-style: decimal; 571 | } 572 | 573 | ol.loweralpha { 574 | list-style: lower-alpha; 575 | } 576 | 577 | ol.upperalpha { 578 | list-style: upper-alpha; 579 | } 580 | 581 | ol.lowerroman { 582 | list-style: lower-roman; 583 | } 584 | 585 | ol.upperroman { 586 | list-style: upper-roman; 587 | } 588 | 589 | :not(li) > ol > li:first-child > :first-child, 590 | :not(li) > ul > li:first-child > :first-child { 591 | margin-top: 0px; 592 | } 593 | 594 | :not(li) > ol > li:last-child > :last-child, 595 | :not(li) > ul > li:last-child > :last-child { 596 | margin-bottom: 0px; 597 | } 598 | 599 | ol.simple ol p, 600 | ol.simple ul p, 601 | ul.simple ol p, 602 | ul.simple ul p { 603 | margin-top: 0; 604 | } 605 | 606 | ol.simple > li:not(:first-child) > p, 607 | ul.simple > li:not(:first-child) > p { 608 | margin-top: 0; 609 | } 610 | 611 | ol.simple p, 612 | ul.simple p { 613 | margin-bottom: 0; 614 | } 615 | 616 | aside.footnote > span, 617 | div.citation > span { 618 | float: left; 619 | } 620 | aside.footnote > span:last-of-type, 621 | div.citation > span:last-of-type { 622 | padding-right: 0.5em; 623 | } 624 | aside.footnote > p { 625 | margin-left: 2em; 626 | } 627 | div.citation > p { 628 | margin-left: 4em; 629 | } 630 | aside.footnote > p:last-of-type, 631 | div.citation > p:last-of-type { 632 | margin-bottom: 0em; 633 | } 634 | aside.footnote > p:last-of-type:after, 635 | div.citation > p:last-of-type:after { 636 | content: ""; 637 | clear: both; 638 | } 639 | 640 | dl.field-list { 641 | display: grid; 642 | grid-template-columns: fit-content(30%) auto; 643 | } 644 | 645 | dl.field-list > dt { 646 | font-weight: bold; 647 | word-break: break-word; 648 | padding-left: 0.5em; 649 | padding-right: 5px; 650 | } 651 | 652 | dl.field-list > dd { 653 | padding-left: 0.5em; 654 | margin-top: 0em; 655 | margin-left: 0em; 656 | margin-bottom: 0em; 657 | } 658 | 659 | dl { 660 | margin-bottom: 15px; 661 | } 662 | 663 | dd > :first-child { 664 | margin-top: 0px; 665 | } 666 | 667 | dd ul, dd table { 668 | margin-bottom: 10px; 669 | } 670 | 671 | dd { 672 | margin-top: 3px; 673 | margin-bottom: 10px; 674 | margin-left: 30px; 675 | } 676 | 677 | .sig dd { 678 | margin-top: 0px; 679 | margin-bottom: 0px; 680 | } 681 | 682 | .sig dl { 683 | margin-top: 0px; 684 | margin-bottom: 0px; 685 | } 686 | 687 | dl > dd:last-child, 688 | dl > dd:last-child > :last-child { 689 | margin-bottom: 0; 690 | } 691 | 692 | dt:target, span.highlighted { 693 | background-color: #fbe54e; 694 | } 695 | 696 | rect.highlighted { 697 | fill: #fbe54e; 698 | } 699 | 700 | dl.glossary dt { 701 | font-weight: bold; 702 | font-size: 1.1em; 703 | } 704 | 705 | .versionmodified { 706 | font-style: italic; 707 | } 708 | 709 | .system-message { 710 | background-color: #fda; 711 | padding: 5px; 712 | border: 3px solid red; 713 | } 714 | 715 | .footnote:target { 716 | background-color: #ffa; 717 | } 718 | 719 | .line-block { 720 | display: block; 721 | margin-top: 1em; 722 | margin-bottom: 1em; 723 | } 724 | 725 | .line-block .line-block { 726 | margin-top: 0; 727 | margin-bottom: 0; 728 | margin-left: 1.5em; 729 | } 730 | 731 | .guilabel, .menuselection { 732 | font-family: sans-serif; 733 | } 734 | 735 | .accelerator { 736 | text-decoration: underline; 737 | } 738 | 739 | .classifier { 740 | font-style: oblique; 741 | } 742 | 743 | .classifier:before { 744 | font-style: normal; 745 | margin: 0 0.5em; 746 | content: ":"; 747 | display: inline-block; 748 | } 749 | 750 | abbr, acronym { 751 | border-bottom: dotted 1px; 752 | cursor: help; 753 | } 754 | 755 | .translated { 756 | background-color: rgba(207, 255, 207, 0.2) 757 | } 758 | 759 | .untranslated { 760 | background-color: rgba(255, 207, 207, 0.2) 761 | } 762 | 763 | /* -- code displays --------------------------------------------------------- */ 764 | 765 | pre { 766 | overflow: auto; 767 | overflow-y: hidden; /* fixes display issues on Chrome browsers */ 768 | } 769 | 770 | pre, div[class*="highlight-"] { 771 | clear: both; 772 | } 773 | 774 | span.pre { 775 | -moz-hyphens: none; 776 | -ms-hyphens: none; 777 | -webkit-hyphens: none; 778 | hyphens: none; 779 | white-space: nowrap; 780 | } 781 | 782 | div[class*="highlight-"] { 783 | margin: 1em 0; 784 | } 785 | 786 | td.linenos pre { 787 | border: 0; 788 | background-color: transparent; 789 | color: #aaa; 790 | } 791 | 792 | table.highlighttable { 793 | display: block; 794 | } 795 | 796 | table.highlighttable tbody { 797 | display: block; 798 | } 799 | 800 | table.highlighttable tr { 801 | display: flex; 802 | } 803 | 804 | table.highlighttable td { 805 | margin: 0; 806 | padding: 0; 807 | } 808 | 809 | table.highlighttable td.linenos { 810 | padding-right: 0.5em; 811 | } 812 | 813 | table.highlighttable td.code { 814 | flex: 1; 815 | overflow: hidden; 816 | } 817 | 818 | .highlight .hll { 819 | display: block; 820 | } 821 | 822 | div.highlight pre, 823 | table.highlighttable pre { 824 | margin: 0; 825 | } 826 | 827 | div.code-block-caption + div { 828 | margin-top: 0; 829 | } 830 | 831 | div.code-block-caption { 832 | margin-top: 1em; 833 | padding: 2px 5px; 834 | font-size: small; 835 | } 836 | 837 | div.code-block-caption code { 838 | background-color: transparent; 839 | } 840 | 841 | table.highlighttable td.linenos, 842 | span.linenos, 843 | div.highlight span.gp { /* gp: Generic.Prompt */ 844 | user-select: none; 845 | -webkit-user-select: text; /* Safari fallback only */ 846 | -webkit-user-select: none; /* Chrome/Safari */ 847 | -moz-user-select: none; /* Firefox */ 848 | -ms-user-select: none; /* IE10+ */ 849 | } 850 | 851 | div.code-block-caption span.caption-number { 852 | padding: 0.1em 0.3em; 853 | font-style: italic; 854 | } 855 | 856 | div.code-block-caption span.caption-text { 857 | } 858 | 859 | div.literal-block-wrapper { 860 | margin: 1em 0; 861 | } 862 | 863 | code.xref, a code { 864 | background-color: transparent; 865 | font-weight: bold; 866 | } 867 | 868 | h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { 869 | background-color: transparent; 870 | } 871 | 872 | .viewcode-link { 873 | float: right; 874 | } 875 | 876 | .viewcode-back { 877 | float: right; 878 | font-family: sans-serif; 879 | } 880 | 881 | div.viewcode-block:target { 882 | margin: -1px -10px; 883 | padding: 0 10px; 884 | } 885 | 886 | /* -- math display ---------------------------------------------------------- */ 887 | 888 | img.math { 889 | vertical-align: middle; 890 | } 891 | 892 | div.body div.math p { 893 | text-align: center; 894 | } 895 | 896 | span.eqno { 897 | float: right; 898 | } 899 | 900 | span.eqno a.headerlink { 901 | position: absolute; 902 | z-index: 1; 903 | } 904 | 905 | div.math:hover a.headerlink { 906 | visibility: visible; 907 | } 908 | 909 | /* -- printout stylesheet --------------------------------------------------- */ 910 | 911 | @media print { 912 | div.document, 913 | div.documentwrapper, 914 | div.bodywrapper { 915 | margin: 0 !important; 916 | width: 100%; 917 | } 918 | 919 | div.sphinxsidebar, 920 | div.related, 921 | div.footer, 922 | #top-link { 923 | display: none; 924 | } 925 | } -------------------------------------------------------------------------------- /docs/build/html/_static/debug.css: -------------------------------------------------------------------------------- 1 | /* 2 | This CSS file should be overridden by the theme authors. It's 3 | meant for debugging and developing the skeleton that this theme provides. 4 | */ 5 | body { 6 | font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, 7 | "Apple Color Emoji", "Segoe UI Emoji"; 8 | background: lavender; 9 | } 10 | .sb-announcement { 11 | background: rgb(131, 131, 131); 12 | } 13 | .sb-announcement__inner { 14 | background: black; 15 | color: white; 16 | } 17 | .sb-header { 18 | background: lightskyblue; 19 | } 20 | .sb-header__inner { 21 | background: royalblue; 22 | color: white; 23 | } 24 | .sb-header-secondary { 25 | background: lightcyan; 26 | } 27 | .sb-header-secondary__inner { 28 | background: cornflowerblue; 29 | color: white; 30 | } 31 | .sb-sidebar-primary { 32 | background: lightgreen; 33 | } 34 | .sb-main { 35 | background: blanchedalmond; 36 | } 37 | .sb-main__inner { 38 | background: antiquewhite; 39 | } 40 | .sb-header-article { 41 | background: lightsteelblue; 42 | } 43 | .sb-article-container { 44 | background: snow; 45 | } 46 | .sb-article-main { 47 | background: white; 48 | } 49 | .sb-footer-article { 50 | background: lightpink; 51 | } 52 | .sb-sidebar-secondary { 53 | background: lightgoldenrodyellow; 54 | } 55 | .sb-footer-content { 56 | background: plum; 57 | } 58 | .sb-footer-content__inner { 59 | background: palevioletred; 60 | } 61 | .sb-footer { 62 | background: pink; 63 | } 64 | .sb-footer__inner { 65 | background: salmon; 66 | } 67 | .sb-article { 68 | background: white; 69 | } 70 | -------------------------------------------------------------------------------- /docs/build/html/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * doctools.js 3 | * ~~~~~~~~~~~ 4 | * 5 | * Base JavaScript utilities for all Sphinx HTML documentation. 6 | * 7 | * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | "use strict"; 12 | 13 | const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ 14 | "TEXTAREA", 15 | "INPUT", 16 | "SELECT", 17 | "BUTTON", 18 | ]); 19 | 20 | const _ready = (callback) => { 21 | if (document.readyState !== "loading") { 22 | callback(); 23 | } else { 24 | document.addEventListener("DOMContentLoaded", callback); 25 | } 26 | }; 27 | 28 | /** 29 | * Small JavaScript module for the documentation. 30 | */ 31 | const Documentation = { 32 | init: () => { 33 | Documentation.initDomainIndexTable(); 34 | Documentation.initOnKeyListeners(); 35 | }, 36 | 37 | /** 38 | * i18n support 39 | */ 40 | TRANSLATIONS: {}, 41 | PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), 42 | LOCALE: "unknown", 43 | 44 | // gettext and ngettext don't access this so that the functions 45 | // can safely bound to a different name (_ = Documentation.gettext) 46 | gettext: (string) => { 47 | const translated = Documentation.TRANSLATIONS[string]; 48 | switch (typeof translated) { 49 | case "undefined": 50 | return string; // no translation 51 | case "string": 52 | return translated; // translation exists 53 | default: 54 | return translated[0]; // (singular, plural) translation tuple exists 55 | } 56 | }, 57 | 58 | ngettext: (singular, plural, n) => { 59 | const translated = Documentation.TRANSLATIONS[singular]; 60 | if (typeof translated !== "undefined") 61 | return translated[Documentation.PLURAL_EXPR(n)]; 62 | return n === 1 ? singular : plural; 63 | }, 64 | 65 | addTranslations: (catalog) => { 66 | Object.assign(Documentation.TRANSLATIONS, catalog.messages); 67 | Documentation.PLURAL_EXPR = new Function( 68 | "n", 69 | `return (${catalog.plural_expr})` 70 | ); 71 | Documentation.LOCALE = catalog.locale; 72 | }, 73 | 74 | /** 75 | * helper function to focus on search bar 76 | */ 77 | focusSearchBar: () => { 78 | document.querySelectorAll("input[name=q]")[0]?.focus(); 79 | }, 80 | 81 | /** 82 | * Initialise the domain index toggle buttons 83 | */ 84 | initDomainIndexTable: () => { 85 | const toggler = (el) => { 86 | const idNumber = el.id.substr(7); 87 | const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); 88 | if (el.src.substr(-9) === "minus.png") { 89 | el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; 90 | toggledRows.forEach((el) => (el.style.display = "none")); 91 | } else { 92 | el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; 93 | toggledRows.forEach((el) => (el.style.display = "")); 94 | } 95 | }; 96 | 97 | const togglerElements = document.querySelectorAll("img.toggler"); 98 | togglerElements.forEach((el) => 99 | el.addEventListener("click", (event) => toggler(event.currentTarget)) 100 | ); 101 | togglerElements.forEach((el) => (el.style.display = "")); 102 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); 103 | }, 104 | 105 | initOnKeyListeners: () => { 106 | // only install a listener if it is really needed 107 | if ( 108 | !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && 109 | !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS 110 | ) 111 | return; 112 | 113 | document.addEventListener("keydown", (event) => { 114 | // bail for input elements 115 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 116 | // bail with special keys 117 | if (event.altKey || event.ctrlKey || event.metaKey) return; 118 | 119 | if (!event.shiftKey) { 120 | switch (event.key) { 121 | case "ArrowLeft": 122 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 123 | 124 | const prevLink = document.querySelector('link[rel="prev"]'); 125 | if (prevLink && prevLink.href) { 126 | window.location.href = prevLink.href; 127 | event.preventDefault(); 128 | } 129 | break; 130 | case "ArrowRight": 131 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 132 | 133 | const nextLink = document.querySelector('link[rel="next"]'); 134 | if (nextLink && nextLink.href) { 135 | window.location.href = nextLink.href; 136 | event.preventDefault(); 137 | } 138 | break; 139 | } 140 | } 141 | 142 | // some keyboard layouts may need Shift to get / 143 | switch (event.key) { 144 | case "/": 145 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; 146 | Documentation.focusSearchBar(); 147 | event.preventDefault(); 148 | } 149 | }); 150 | }, 151 | }; 152 | 153 | // quick alias for translations 154 | const _ = Documentation.gettext; 155 | 156 | _ready(Documentation.init); 157 | -------------------------------------------------------------------------------- /docs/build/html/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | const DOCUMENTATION_OPTIONS = { 2 | VERSION: '0.3.2', 3 | LANGUAGE: 'en', 4 | COLLAPSE_INDEX: false, 5 | BUILDER: 'html', 6 | FILE_SUFFIX: '.html', 7 | LINK_SUFFIX: '.html', 8 | HAS_SOURCE: true, 9 | SOURCELINK_SUFFIX: '.txt', 10 | NAVIGATION_WITH_KEYS: false, 11 | SHOW_SEARCH_SUMMARY: true, 12 | ENABLE_SEARCH_SHORTCUTS: true, 13 | }; -------------------------------------------------------------------------------- /docs/build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_static/file.png -------------------------------------------------------------------------------- /docs/build/html/_static/language_data.js: -------------------------------------------------------------------------------- 1 | /* 2 | * language_data.js 3 | * ~~~~~~~~~~~~~~~~ 4 | * 5 | * This script contains the language-specific data used by searchtools.js, 6 | * namely the list of stopwords, stemmer, scorer and splitter. 7 | * 8 | * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. 9 | * :license: BSD, see LICENSE for details. 10 | * 11 | */ 12 | 13 | var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; 14 | 15 | 16 | /* Non-minified version is copied as a separate JS file, if available */ 17 | 18 | /** 19 | * Porter Stemmer 20 | */ 21 | var Stemmer = function() { 22 | 23 | var step2list = { 24 | ational: 'ate', 25 | tional: 'tion', 26 | enci: 'ence', 27 | anci: 'ance', 28 | izer: 'ize', 29 | bli: 'ble', 30 | alli: 'al', 31 | entli: 'ent', 32 | eli: 'e', 33 | ousli: 'ous', 34 | ization: 'ize', 35 | ation: 'ate', 36 | ator: 'ate', 37 | alism: 'al', 38 | iveness: 'ive', 39 | fulness: 'ful', 40 | ousness: 'ous', 41 | aliti: 'al', 42 | iviti: 'ive', 43 | biliti: 'ble', 44 | logi: 'log' 45 | }; 46 | 47 | var step3list = { 48 | icate: 'ic', 49 | ative: '', 50 | alize: 'al', 51 | iciti: 'ic', 52 | ical: 'ic', 53 | ful: '', 54 | ness: '' 55 | }; 56 | 57 | var c = "[^aeiou]"; // consonant 58 | var v = "[aeiouy]"; // vowel 59 | var C = c + "[^aeiouy]*"; // consonant sequence 60 | var V = v + "[aeiou]*"; // vowel sequence 61 | 62 | var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 63 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 64 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 65 | var s_v = "^(" + C + ")?" + v; // vowel in stem 66 | 67 | this.stemWord = function (w) { 68 | var stem; 69 | var suffix; 70 | var firstch; 71 | var origword = w; 72 | 73 | if (w.length < 3) 74 | return w; 75 | 76 | var re; 77 | var re2; 78 | var re3; 79 | var re4; 80 | 81 | firstch = w.substr(0,1); 82 | if (firstch == "y") 83 | w = firstch.toUpperCase() + w.substr(1); 84 | 85 | // Step 1a 86 | re = /^(.+?)(ss|i)es$/; 87 | re2 = /^(.+?)([^s])s$/; 88 | 89 | if (re.test(w)) 90 | w = w.replace(re,"$1$2"); 91 | else if (re2.test(w)) 92 | w = w.replace(re2,"$1$2"); 93 | 94 | // Step 1b 95 | re = /^(.+?)eed$/; 96 | re2 = /^(.+?)(ed|ing)$/; 97 | if (re.test(w)) { 98 | var fp = re.exec(w); 99 | re = new RegExp(mgr0); 100 | if (re.test(fp[1])) { 101 | re = /.$/; 102 | w = w.replace(re,""); 103 | } 104 | } 105 | else if (re2.test(w)) { 106 | var fp = re2.exec(w); 107 | stem = fp[1]; 108 | re2 = new RegExp(s_v); 109 | if (re2.test(stem)) { 110 | w = stem; 111 | re2 = /(at|bl|iz)$/; 112 | re3 = new RegExp("([^aeiouylsz])\\1$"); 113 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 114 | if (re2.test(w)) 115 | w = w + "e"; 116 | else if (re3.test(w)) { 117 | re = /.$/; 118 | w = w.replace(re,""); 119 | } 120 | else if (re4.test(w)) 121 | w = w + "e"; 122 | } 123 | } 124 | 125 | // Step 1c 126 | re = /^(.+?)y$/; 127 | if (re.test(w)) { 128 | var fp = re.exec(w); 129 | stem = fp[1]; 130 | re = new RegExp(s_v); 131 | if (re.test(stem)) 132 | w = stem + "i"; 133 | } 134 | 135 | // Step 2 136 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; 137 | if (re.test(w)) { 138 | var fp = re.exec(w); 139 | stem = fp[1]; 140 | suffix = fp[2]; 141 | re = new RegExp(mgr0); 142 | if (re.test(stem)) 143 | w = stem + step2list[suffix]; 144 | } 145 | 146 | // Step 3 147 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; 148 | if (re.test(w)) { 149 | var fp = re.exec(w); 150 | stem = fp[1]; 151 | suffix = fp[2]; 152 | re = new RegExp(mgr0); 153 | if (re.test(stem)) 154 | w = stem + step3list[suffix]; 155 | } 156 | 157 | // Step 4 158 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; 159 | re2 = /^(.+?)(s|t)(ion)$/; 160 | if (re.test(w)) { 161 | var fp = re.exec(w); 162 | stem = fp[1]; 163 | re = new RegExp(mgr1); 164 | if (re.test(stem)) 165 | w = stem; 166 | } 167 | else if (re2.test(w)) { 168 | var fp = re2.exec(w); 169 | stem = fp[1] + fp[2]; 170 | re2 = new RegExp(mgr1); 171 | if (re2.test(stem)) 172 | w = stem; 173 | } 174 | 175 | // Step 5 176 | re = /^(.+?)e$/; 177 | if (re.test(w)) { 178 | var fp = re.exec(w); 179 | stem = fp[1]; 180 | re = new RegExp(mgr1); 181 | re2 = new RegExp(meq1); 182 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 183 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) 184 | w = stem; 185 | } 186 | re = /ll$/; 187 | re2 = new RegExp(mgr1); 188 | if (re.test(w) && re2.test(w)) { 189 | re = /.$/; 190 | w = w.replace(re,""); 191 | } 192 | 193 | // and turn initial Y back to y 194 | if (firstch == "y") 195 | w = firstch.toLowerCase() + w.substr(1); 196 | return w; 197 | } 198 | } 199 | 200 | -------------------------------------------------------------------------------- /docs/build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_static/minus.png -------------------------------------------------------------------------------- /docs/build/html/_static/nbsphinx-broken-thumbnail.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/build/html/_static/nbsphinx-code-cells.css: -------------------------------------------------------------------------------- 1 | /* remove conflicting styling from Sphinx themes */ 2 | div.nbinput.container div.prompt *, 3 | div.nboutput.container div.prompt *, 4 | div.nbinput.container div.input_area pre, 5 | div.nboutput.container div.output_area pre, 6 | div.nbinput.container div.input_area .highlight, 7 | div.nboutput.container div.output_area .highlight { 8 | border: none; 9 | padding: 0; 10 | margin: 0; 11 | box-shadow: none; 12 | } 13 | 14 | div.nbinput.container > div[class*=highlight], 15 | div.nboutput.container > div[class*=highlight] { 16 | margin: 0; 17 | } 18 | 19 | div.nbinput.container div.prompt *, 20 | div.nboutput.container div.prompt * { 21 | background: none; 22 | } 23 | 24 | div.nboutput.container div.output_area .highlight, 25 | div.nboutput.container div.output_area pre { 26 | background: unset; 27 | } 28 | 29 | div.nboutput.container div.output_area div.highlight { 30 | color: unset; /* override Pygments text color */ 31 | } 32 | 33 | /* avoid gaps between output lines */ 34 | div.nboutput.container div[class*=highlight] pre { 35 | line-height: normal; 36 | } 37 | 38 | /* input/output containers */ 39 | div.nbinput.container, 40 | div.nboutput.container { 41 | display: -webkit-flex; 42 | display: flex; 43 | align-items: flex-start; 44 | margin: 0; 45 | width: 100%; 46 | } 47 | @media (max-width: 540px) { 48 | div.nbinput.container, 49 | div.nboutput.container { 50 | flex-direction: column; 51 | } 52 | } 53 | 54 | /* input container */ 55 | div.nbinput.container { 56 | padding-top: 5px; 57 | } 58 | 59 | /* last container */ 60 | div.nblast.container { 61 | padding-bottom: 5px; 62 | } 63 | 64 | /* input prompt */ 65 | div.nbinput.container div.prompt pre, 66 | /* for sphinx_immaterial theme: */ 67 | div.nbinput.container div.prompt pre > code { 68 | color: #307FC1; 69 | } 70 | 71 | /* output prompt */ 72 | div.nboutput.container div.prompt pre, 73 | /* for sphinx_immaterial theme: */ 74 | div.nboutput.container div.prompt pre > code { 75 | color: #BF5B3D; 76 | } 77 | 78 | /* all prompts */ 79 | div.nbinput.container div.prompt, 80 | div.nboutput.container div.prompt { 81 | width: 4.5ex; 82 | padding-top: 5px; 83 | position: relative; 84 | user-select: none; 85 | } 86 | 87 | div.nbinput.container div.prompt > div, 88 | div.nboutput.container div.prompt > div { 89 | position: absolute; 90 | right: 0; 91 | margin-right: 0.3ex; 92 | } 93 | 94 | @media (max-width: 540px) { 95 | div.nbinput.container div.prompt, 96 | div.nboutput.container div.prompt { 97 | width: unset; 98 | text-align: left; 99 | padding: 0.4em; 100 | } 101 | div.nboutput.container div.prompt.empty { 102 | padding: 0; 103 | } 104 | 105 | div.nbinput.container div.prompt > div, 106 | div.nboutput.container div.prompt > div { 107 | position: unset; 108 | } 109 | } 110 | 111 | /* disable scrollbars and line breaks on prompts */ 112 | div.nbinput.container div.prompt pre, 113 | div.nboutput.container div.prompt pre { 114 | overflow: hidden; 115 | white-space: pre; 116 | } 117 | 118 | /* input/output area */ 119 | div.nbinput.container div.input_area, 120 | div.nboutput.container div.output_area { 121 | -webkit-flex: 1; 122 | flex: 1; 123 | overflow: auto; 124 | } 125 | @media (max-width: 540px) { 126 | div.nbinput.container div.input_area, 127 | div.nboutput.container div.output_area { 128 | width: 100%; 129 | } 130 | } 131 | 132 | /* input area */ 133 | div.nbinput.container div.input_area { 134 | border: 1px solid #e0e0e0; 135 | border-radius: 2px; 136 | /*background: #f5f5f5;*/ 137 | } 138 | 139 | /* override MathJax center alignment in output cells */ 140 | div.nboutput.container div[class*=MathJax] { 141 | text-align: left !important; 142 | } 143 | 144 | /* override sphinx.ext.imgmath center alignment in output cells */ 145 | div.nboutput.container div.math p { 146 | text-align: left; 147 | } 148 | 149 | /* standard error */ 150 | div.nboutput.container div.output_area.stderr { 151 | background: #fdd; 152 | } 153 | 154 | /* ANSI colors */ 155 | .ansi-black-fg { color: #3E424D; } 156 | .ansi-black-bg { background-color: #3E424D; } 157 | .ansi-black-intense-fg { color: #282C36; } 158 | .ansi-black-intense-bg { background-color: #282C36; } 159 | .ansi-red-fg { color: #E75C58; } 160 | .ansi-red-bg { background-color: #E75C58; } 161 | .ansi-red-intense-fg { color: #B22B31; } 162 | .ansi-red-intense-bg { background-color: #B22B31; } 163 | .ansi-green-fg { color: #00A250; } 164 | .ansi-green-bg { background-color: #00A250; } 165 | .ansi-green-intense-fg { color: #007427; } 166 | .ansi-green-intense-bg { background-color: #007427; } 167 | .ansi-yellow-fg { color: #DDB62B; } 168 | .ansi-yellow-bg { background-color: #DDB62B; } 169 | .ansi-yellow-intense-fg { color: #B27D12; } 170 | .ansi-yellow-intense-bg { background-color: #B27D12; } 171 | .ansi-blue-fg { color: #208FFB; } 172 | .ansi-blue-bg { background-color: #208FFB; } 173 | .ansi-blue-intense-fg { color: #0065CA; } 174 | .ansi-blue-intense-bg { background-color: #0065CA; } 175 | .ansi-magenta-fg { color: #D160C4; } 176 | .ansi-magenta-bg { background-color: #D160C4; } 177 | .ansi-magenta-intense-fg { color: #A03196; } 178 | .ansi-magenta-intense-bg { background-color: #A03196; } 179 | .ansi-cyan-fg { color: #60C6C8; } 180 | .ansi-cyan-bg { background-color: #60C6C8; } 181 | .ansi-cyan-intense-fg { color: #258F8F; } 182 | .ansi-cyan-intense-bg { background-color: #258F8F; } 183 | .ansi-white-fg { color: #C5C1B4; } 184 | .ansi-white-bg { background-color: #C5C1B4; } 185 | .ansi-white-intense-fg { color: #A1A6B2; } 186 | .ansi-white-intense-bg { background-color: #A1A6B2; } 187 | 188 | .ansi-default-inverse-fg { color: #FFFFFF; } 189 | .ansi-default-inverse-bg { background-color: #000000; } 190 | 191 | .ansi-bold { font-weight: bold; } 192 | .ansi-underline { text-decoration: underline; } 193 | 194 | 195 | div.nbinput.container div.input_area div[class*=highlight] > pre, 196 | div.nboutput.container div.output_area div[class*=highlight] > pre, 197 | div.nboutput.container div.output_area div[class*=highlight].math, 198 | div.nboutput.container div.output_area.rendered_html, 199 | div.nboutput.container div.output_area > div.output_javascript, 200 | div.nboutput.container div.output_area:not(.rendered_html) > img{ 201 | padding: 5px; 202 | margin: 0; 203 | } 204 | 205 | /* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */ 206 | div.nbinput.container div.input_area > div[class^='highlight'], 207 | div.nboutput.container div.output_area > div[class^='highlight']{ 208 | overflow-y: hidden; 209 | } 210 | 211 | /* hide copy button on prompts for 'sphinx_copybutton' extension ... */ 212 | .prompt .copybtn, 213 | /* ... and 'sphinx_immaterial' theme */ 214 | .prompt .md-clipboard.md-icon { 215 | display: none; 216 | } 217 | 218 | /* Some additional styling taken form the Jupyter notebook CSS */ 219 | .jp-RenderedHTMLCommon table, 220 | div.rendered_html table { 221 | border: none; 222 | border-collapse: collapse; 223 | border-spacing: 0; 224 | color: black; 225 | font-size: 12px; 226 | table-layout: fixed; 227 | } 228 | .jp-RenderedHTMLCommon thead, 229 | div.rendered_html thead { 230 | border-bottom: 1px solid black; 231 | vertical-align: bottom; 232 | } 233 | .jp-RenderedHTMLCommon tr, 234 | .jp-RenderedHTMLCommon th, 235 | .jp-RenderedHTMLCommon td, 236 | div.rendered_html tr, 237 | div.rendered_html th, 238 | div.rendered_html td { 239 | text-align: right; 240 | vertical-align: middle; 241 | padding: 0.5em 0.5em; 242 | line-height: normal; 243 | white-space: normal; 244 | max-width: none; 245 | border: none; 246 | } 247 | .jp-RenderedHTMLCommon th, 248 | div.rendered_html th { 249 | font-weight: bold; 250 | } 251 | .jp-RenderedHTMLCommon tbody tr:nth-child(odd), 252 | div.rendered_html tbody tr:nth-child(odd) { 253 | background: #f5f5f5; 254 | } 255 | .jp-RenderedHTMLCommon tbody tr:hover, 256 | div.rendered_html tbody tr:hover { 257 | background: rgba(66, 165, 245, 0.2); 258 | } 259 | 260 | -------------------------------------------------------------------------------- /docs/build/html/_static/nbsphinx-gallery.css: -------------------------------------------------------------------------------- 1 | .nbsphinx-gallery { 2 | display: grid; 3 | grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); 4 | gap: 5px; 5 | margin-top: 1em; 6 | margin-bottom: 1em; 7 | } 8 | 9 | .nbsphinx-gallery > a { 10 | padding: 5px; 11 | border: 1px dotted currentColor; 12 | border-radius: 2px; 13 | text-align: center; 14 | } 15 | 16 | .nbsphinx-gallery > a:hover { 17 | border-style: solid; 18 | } 19 | 20 | .nbsphinx-gallery img { 21 | max-width: 100%; 22 | max-height: 100%; 23 | } 24 | 25 | .nbsphinx-gallery > a > div:first-child { 26 | display: flex; 27 | align-items: start; 28 | justify-content: center; 29 | height: 120px; 30 | margin-bottom: 5px; 31 | } 32 | -------------------------------------------------------------------------------- /docs/build/html/_static/nbsphinx-no-thumbnail.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_static/plus.png -------------------------------------------------------------------------------- /docs/build/html/_static/scripts/furo-extensions.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/_static/scripts/furo-extensions.js -------------------------------------------------------------------------------- /docs/build/html/_static/scripts/furo.js: -------------------------------------------------------------------------------- 1 | /*! For license information please see furo.js.LICENSE.txt */ 2 | (()=>{var t={212:function(t,e,n){var o,r;r=void 0!==n.g?n.g:"undefined"!=typeof window?window:this,o=function(){return function(t){"use strict";var e={navClass:"active",contentClass:"active",nested:!1,nestedClass:"active",offset:0,reflow:!1,events:!0},n=function(t,e,n){if(n.settings.events){var o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n});e.dispatchEvent(o)}},o=function(t){var e=0;if(t.offsetParent)for(;t;)e+=t.offsetTop,t=t.offsetParent;return e>=0?e:0},r=function(t){t&&t.sort((function(t,e){return o(t.content)=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight,document.body.offsetHeight,document.documentElement.offsetHeight,document.body.clientHeight,document.documentElement.clientHeight)},l=function(t,e){var n=t[t.length-1];if(function(t,e){return!(!s()||!c(t.content,e,!0))}(n,e))return n;for(var o=t.length-1;o>=0;o--)if(c(t[o].content,e))return t[o]},a=function(t,e){if(e.nested&&t.parentNode){var n=t.parentNode.closest("li");n&&(n.classList.remove(e.nestedClass),a(n,e))}},i=function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.remove(e.navClass),t.content.classList.remove(e.contentClass),a(o,e),n("gumshoeDeactivate",o,{link:t.nav,content:t.content,settings:e}))}},u=function(t,e){if(e.nested){var n=t.parentNode.closest("li");n&&(n.classList.add(e.nestedClass),u(n,e))}};return function(o,c){var s,a,d,f,m,v={setup:function(){s=document.querySelectorAll(o),a=[],Array.prototype.forEach.call(s,(function(t){var e=document.getElementById(decodeURIComponent(t.hash.substr(1)));e&&a.push({nav:t,content:e})})),r(a)},detect:function(){var t=l(a,m);t?d&&t.content===d.content||(i(d,m),function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.add(e.navClass),t.content.classList.add(e.contentClass),u(o,e),n("gumshoeActivate",o,{link:t.nav,content:t.content,settings:e}))}}(t,m),d=t):d&&(i(d,m),d=null)}},h=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame(v.detect)},g=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame((function(){r(a),v.detect()}))};return v.destroy=function(){d&&i(d,m),t.removeEventListener("scroll",h,!1),m.reflow&&t.removeEventListener("resize",g,!1),a=null,s=null,d=null,f=null,m=null},m=function(){var t={};return Array.prototype.forEach.call(arguments,(function(e){for(var n in e){if(!e.hasOwnProperty(n))return;t[n]=e[n]}})),t}(e,c||{}),v.setup(),v.detect(),t.addEventListener("scroll",h,!1),m.reflow&&t.addEventListener("resize",g,!1),v}}(r)}.apply(e,[]),void 0===o||(t.exports=o)}},e={};function n(o){var r=e[o];if(void 0!==r)return r.exports;var c=e[o]={exports:{}};return t[o].call(c.exports,c,c.exports,n),c.exports}n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";var t=n(212),e=n.n(t),o=null,r=null,c=window.pageYOffset||document.documentElement.scrollTop;const s=64;function l(){const t=localStorage.getItem("theme")||"auto";var e;"light"!==(e=window.matchMedia("(prefers-color-scheme: dark)").matches?"auto"===t?"light":"light"==t?"dark":"auto":"auto"===t?"dark":"dark"==t?"light":"auto")&&"dark"!==e&&"auto"!==e&&(console.error(`Got invalid theme mode: ${e}. Resetting to auto.`),e="auto"),document.body.dataset.theme=e,localStorage.setItem("theme",e),console.log(`Changed to ${e} mode.`)}function a(){!function(){const t=document.getElementsByClassName("theme-toggle");Array.from(t).forEach((t=>{t.addEventListener("click",l)}))}(),function(){let t=0,e=!1;window.addEventListener("scroll",(function(n){t=window.scrollY,e||(window.requestAnimationFrame((function(){var n;n=t,0==Math.floor(r.getBoundingClientRect().top)?r.classList.add("scrolled"):r.classList.remove("scrolled"),function(t){tc&&document.documentElement.classList.remove("show-back-to-top"),c=t}(n),function(t){null!==o&&(0==t?o.scrollTo(0,0):Math.ceil(t)>=Math.floor(document.documentElement.scrollHeight-window.innerHeight)?o.scrollTo(0,o.scrollHeight):document.querySelector(".scroll-current"))}(n),e=!1})),e=!0)})),window.scroll()}(),null!==o&&new(e())(".toc-tree a",{reflow:!0,recursive:!0,navClass:"scroll-current",offset:()=>{let t=parseFloat(getComputedStyle(document.documentElement).fontSize);return r.getBoundingClientRect().height+.5*t+1}})}document.addEventListener("DOMContentLoaded",(function(){document.body.parentNode.classList.remove("no-js"),r=document.querySelector("header"),o=document.querySelector(".toc-scroll"),a()}))})()})(); 3 | //# sourceMappingURL=furo.js.map -------------------------------------------------------------------------------- /docs/build/html/_static/scripts/furo.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * gumshoejs v5.1.2 (patched by @pradyunsg) 3 | * A simple, framework-agnostic scrollspy script. 4 | * (c) 2019 Chris Ferdinandi 5 | * MIT License 6 | * http://github.com/cferdinandi/gumshoe 7 | */ 8 | -------------------------------------------------------------------------------- /docs/build/html/_static/skeleton.css: -------------------------------------------------------------------------------- 1 | /* Some sane resets. */ 2 | html { 3 | height: 100%; 4 | } 5 | 6 | body { 7 | margin: 0; 8 | min-height: 100%; 9 | } 10 | 11 | /* All the flexbox magic! */ 12 | body, 13 | .sb-announcement, 14 | .sb-content, 15 | .sb-main, 16 | .sb-container, 17 | .sb-container__inner, 18 | .sb-article-container, 19 | .sb-footer-content, 20 | .sb-header, 21 | .sb-header-secondary, 22 | .sb-footer { 23 | display: flex; 24 | } 25 | 26 | /* These order things vertically */ 27 | body, 28 | .sb-main, 29 | .sb-article-container { 30 | flex-direction: column; 31 | } 32 | 33 | /* Put elements in the center */ 34 | .sb-header, 35 | .sb-header-secondary, 36 | .sb-container, 37 | .sb-content, 38 | .sb-footer, 39 | .sb-footer-content { 40 | justify-content: center; 41 | } 42 | /* Put elements at the ends */ 43 | .sb-article-container { 44 | justify-content: space-between; 45 | } 46 | 47 | /* These elements grow. */ 48 | .sb-main, 49 | .sb-content, 50 | .sb-container, 51 | article { 52 | flex-grow: 1; 53 | } 54 | 55 | /* Because padding making this wider is not fun */ 56 | article { 57 | box-sizing: border-box; 58 | } 59 | 60 | /* The announcements element should never be wider than the page. */ 61 | .sb-announcement { 62 | max-width: 100%; 63 | } 64 | 65 | .sb-sidebar-primary, 66 | .sb-sidebar-secondary { 67 | flex-shrink: 0; 68 | width: 17rem; 69 | } 70 | 71 | .sb-announcement__inner { 72 | justify-content: center; 73 | 74 | box-sizing: border-box; 75 | height: 3rem; 76 | 77 | overflow-x: auto; 78 | white-space: nowrap; 79 | } 80 | 81 | /* Sidebars, with checkbox-based toggle */ 82 | .sb-sidebar-primary, 83 | .sb-sidebar-secondary { 84 | position: fixed; 85 | height: 100%; 86 | top: 0; 87 | } 88 | 89 | .sb-sidebar-primary { 90 | left: -17rem; 91 | transition: left 250ms ease-in-out; 92 | } 93 | .sb-sidebar-secondary { 94 | right: -17rem; 95 | transition: right 250ms ease-in-out; 96 | } 97 | 98 | .sb-sidebar-toggle { 99 | display: none; 100 | } 101 | .sb-sidebar-overlay { 102 | position: fixed; 103 | top: 0; 104 | width: 0; 105 | height: 0; 106 | 107 | transition: width 0ms ease 250ms, height 0ms ease 250ms, opacity 250ms ease; 108 | 109 | opacity: 0; 110 | background-color: rgba(0, 0, 0, 0.54); 111 | } 112 | 113 | #sb-sidebar-toggle--primary:checked 114 | ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--primary"], 115 | #sb-sidebar-toggle--secondary:checked 116 | ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--secondary"] { 117 | width: 100%; 118 | height: 100%; 119 | opacity: 1; 120 | transition: width 0ms ease, height 0ms ease, opacity 250ms ease; 121 | } 122 | 123 | #sb-sidebar-toggle--primary:checked ~ .sb-container .sb-sidebar-primary { 124 | left: 0; 125 | } 126 | #sb-sidebar-toggle--secondary:checked ~ .sb-container .sb-sidebar-secondary { 127 | right: 0; 128 | } 129 | 130 | /* Full-width mode */ 131 | .drop-secondary-sidebar-for-full-width-content 132 | .hide-when-secondary-sidebar-shown { 133 | display: none !important; 134 | } 135 | .drop-secondary-sidebar-for-full-width-content .sb-sidebar-secondary { 136 | display: none !important; 137 | } 138 | 139 | /* Mobile views */ 140 | .sb-page-width { 141 | width: 100%; 142 | } 143 | 144 | .sb-article-container, 145 | .sb-footer-content__inner, 146 | .drop-secondary-sidebar-for-full-width-content .sb-article, 147 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 148 | width: 100vw; 149 | } 150 | 151 | .sb-article, 152 | .match-content-width { 153 | padding: 0 1rem; 154 | box-sizing: border-box; 155 | } 156 | 157 | @media (min-width: 32rem) { 158 | .sb-article, 159 | .match-content-width { 160 | padding: 0 2rem; 161 | } 162 | } 163 | 164 | /* Tablet views */ 165 | @media (min-width: 42rem) { 166 | .sb-article-container { 167 | width: auto; 168 | } 169 | .sb-footer-content__inner, 170 | .drop-secondary-sidebar-for-full-width-content .sb-article, 171 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 172 | width: 42rem; 173 | } 174 | .sb-article, 175 | .match-content-width { 176 | width: 42rem; 177 | } 178 | } 179 | @media (min-width: 46rem) { 180 | .sb-footer-content__inner, 181 | .drop-secondary-sidebar-for-full-width-content .sb-article, 182 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 183 | width: 46rem; 184 | } 185 | .sb-article, 186 | .match-content-width { 187 | width: 46rem; 188 | } 189 | } 190 | @media (min-width: 50rem) { 191 | .sb-footer-content__inner, 192 | .drop-secondary-sidebar-for-full-width-content .sb-article, 193 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 194 | width: 50rem; 195 | } 196 | .sb-article, 197 | .match-content-width { 198 | width: 50rem; 199 | } 200 | } 201 | 202 | /* Tablet views */ 203 | @media (min-width: 59rem) { 204 | .sb-sidebar-secondary { 205 | position: static; 206 | } 207 | .hide-when-secondary-sidebar-shown { 208 | display: none !important; 209 | } 210 | .sb-footer-content__inner, 211 | .drop-secondary-sidebar-for-full-width-content .sb-article, 212 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 213 | width: 59rem; 214 | } 215 | .sb-article, 216 | .match-content-width { 217 | width: 42rem; 218 | } 219 | } 220 | @media (min-width: 63rem) { 221 | .sb-footer-content__inner, 222 | .drop-secondary-sidebar-for-full-width-content .sb-article, 223 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 224 | width: 63rem; 225 | } 226 | .sb-article, 227 | .match-content-width { 228 | width: 46rem; 229 | } 230 | } 231 | @media (min-width: 67rem) { 232 | .sb-footer-content__inner, 233 | .drop-secondary-sidebar-for-full-width-content .sb-article, 234 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 235 | width: 67rem; 236 | } 237 | .sb-article, 238 | .match-content-width { 239 | width: 50rem; 240 | } 241 | } 242 | 243 | /* Desktop views */ 244 | @media (min-width: 76rem) { 245 | .sb-sidebar-primary { 246 | position: static; 247 | } 248 | .hide-when-primary-sidebar-shown { 249 | display: none !important; 250 | } 251 | .sb-footer-content__inner, 252 | .drop-secondary-sidebar-for-full-width-content .sb-article, 253 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 254 | width: 59rem; 255 | } 256 | .sb-article, 257 | .match-content-width { 258 | width: 42rem; 259 | } 260 | } 261 | 262 | /* Full desktop views */ 263 | @media (min-width: 80rem) { 264 | .sb-article, 265 | .match-content-width { 266 | width: 46rem; 267 | } 268 | .sb-footer-content__inner, 269 | .drop-secondary-sidebar-for-full-width-content .sb-article, 270 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 271 | width: 63rem; 272 | } 273 | } 274 | 275 | @media (min-width: 84rem) { 276 | .sb-article, 277 | .match-content-width { 278 | width: 50rem; 279 | } 280 | .sb-footer-content__inner, 281 | .drop-secondary-sidebar-for-full-width-content .sb-article, 282 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 283 | width: 67rem; 284 | } 285 | } 286 | 287 | @media (min-width: 88rem) { 288 | .sb-footer-content__inner, 289 | .drop-secondary-sidebar-for-full-width-content .sb-article, 290 | .drop-secondary-sidebar-for-full-width-content .match-content-width { 291 | width: 67rem; 292 | } 293 | .sb-page-width { 294 | width: 88rem; 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /docs/build/html/_static/sphinx_highlight.js: -------------------------------------------------------------------------------- 1 | /* Highlighting utilities for Sphinx HTML documentation. */ 2 | "use strict"; 3 | 4 | const SPHINX_HIGHLIGHT_ENABLED = true 5 | 6 | /** 7 | * highlight a given string on a node by wrapping it in 8 | * span elements with the given class name. 9 | */ 10 | const _highlight = (node, addItems, text, className) => { 11 | if (node.nodeType === Node.TEXT_NODE) { 12 | const val = node.nodeValue; 13 | const parent = node.parentNode; 14 | const pos = val.toLowerCase().indexOf(text); 15 | if ( 16 | pos >= 0 && 17 | !parent.classList.contains(className) && 18 | !parent.classList.contains("nohighlight") 19 | ) { 20 | let span; 21 | 22 | const closestNode = parent.closest("body, svg, foreignObject"); 23 | const isInSVG = closestNode && closestNode.matches("svg"); 24 | if (isInSVG) { 25 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); 26 | } else { 27 | span = document.createElement("span"); 28 | span.classList.add(className); 29 | } 30 | 31 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 32 | const rest = document.createTextNode(val.substr(pos + text.length)); 33 | parent.insertBefore( 34 | span, 35 | parent.insertBefore( 36 | rest, 37 | node.nextSibling 38 | ) 39 | ); 40 | node.nodeValue = val.substr(0, pos); 41 | /* There may be more occurrences of search term in this node. So call this 42 | * function recursively on the remaining fragment. 43 | */ 44 | _highlight(rest, addItems, text, className); 45 | 46 | if (isInSVG) { 47 | const rect = document.createElementNS( 48 | "http://www.w3.org/2000/svg", 49 | "rect" 50 | ); 51 | const bbox = parent.getBBox(); 52 | rect.x.baseVal.value = bbox.x; 53 | rect.y.baseVal.value = bbox.y; 54 | rect.width.baseVal.value = bbox.width; 55 | rect.height.baseVal.value = bbox.height; 56 | rect.setAttribute("class", className); 57 | addItems.push({ parent: parent, target: rect }); 58 | } 59 | } 60 | } else if (node.matches && !node.matches("button, select, textarea")) { 61 | node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); 62 | } 63 | }; 64 | const _highlightText = (thisNode, text, className) => { 65 | let addItems = []; 66 | _highlight(thisNode, addItems, text, className); 67 | addItems.forEach((obj) => 68 | obj.parent.insertAdjacentElement("beforebegin", obj.target) 69 | ); 70 | }; 71 | 72 | /** 73 | * Small JavaScript module for the documentation. 74 | */ 75 | const SphinxHighlight = { 76 | 77 | /** 78 | * highlight the search words provided in localstorage in the text 79 | */ 80 | highlightSearchWords: () => { 81 | if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight 82 | 83 | // get and clear terms from localstorage 84 | const url = new URL(window.location); 85 | const highlight = 86 | localStorage.getItem("sphinx_highlight_terms") 87 | || url.searchParams.get("highlight") 88 | || ""; 89 | localStorage.removeItem("sphinx_highlight_terms") 90 | url.searchParams.delete("highlight"); 91 | window.history.replaceState({}, "", url); 92 | 93 | // get individual terms from highlight string 94 | const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); 95 | if (terms.length === 0) return; // nothing to do 96 | 97 | // There should never be more than one element matching "div.body" 98 | const divBody = document.querySelectorAll("div.body"); 99 | const body = divBody.length ? divBody[0] : document.querySelector("body"); 100 | window.setTimeout(() => { 101 | terms.forEach((term) => _highlightText(body, term, "highlighted")); 102 | }, 10); 103 | 104 | const searchBox = document.getElementById("searchbox"); 105 | if (searchBox === null) return; 106 | searchBox.appendChild( 107 | document 108 | .createRange() 109 | .createContextualFragment( 110 | '" 114 | ) 115 | ); 116 | }, 117 | 118 | /** 119 | * helper function to hide the search marks again 120 | */ 121 | hideSearchWords: () => { 122 | document 123 | .querySelectorAll("#searchbox .highlight-link") 124 | .forEach((el) => el.remove()); 125 | document 126 | .querySelectorAll("span.highlighted") 127 | .forEach((el) => el.classList.remove("highlighted")); 128 | localStorage.removeItem("sphinx_highlight_terms") 129 | }, 130 | 131 | initEscapeListener: () => { 132 | // only install a listener if it is really needed 133 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; 134 | 135 | document.addEventListener("keydown", (event) => { 136 | // bail for input elements 137 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 138 | // bail with special keys 139 | if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; 140 | if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { 141 | SphinxHighlight.hideSearchWords(); 142 | event.preventDefault(); 143 | } 144 | }); 145 | }, 146 | }; 147 | 148 | _ready(() => { 149 | /* Do not call highlightSearchWords() when we are on the search page. 150 | * It will highlight words from the *previous* search query. 151 | */ 152 | if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); 153 | SphinxHighlight.initEscapeListener(); 154 | }); 155 | -------------------------------------------------------------------------------- /docs/build/html/_static/styles/furo-extensions.css: -------------------------------------------------------------------------------- 1 | #furo-sidebar-ad-placement{padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)}#furo-sidebar-ad-placement .ethical-sidebar{background:var(--color-background-secondary);border:none;box-shadow:none}#furo-sidebar-ad-placement .ethical-sidebar:hover{background:var(--color-background-hover)}#furo-sidebar-ad-placement .ethical-sidebar a{color:var(--color-foreground-primary)}#furo-sidebar-ad-placement .ethical-callout a{color:var(--color-foreground-secondary)!important}#furo-readthedocs-versions{background:transparent;display:block;position:static;width:100%}#furo-readthedocs-versions .rst-versions{background:#1a1c1e}#furo-readthedocs-versions .rst-current-version{background:var(--color-sidebar-item-background);cursor:unset}#furo-readthedocs-versions .rst-current-version:hover{background:var(--color-sidebar-item-background)}#furo-readthedocs-versions .rst-current-version .fa-book{color:var(--color-foreground-primary)}#furo-readthedocs-versions>.rst-other-versions{padding:0}#furo-readthedocs-versions>.rst-other-versions small{opacity:1}#furo-readthedocs-versions .injected .rst-versions{position:unset}#furo-readthedocs-versions:focus-within,#furo-readthedocs-versions:hover{box-shadow:0 0 0 1px var(--color-sidebar-background-border)}#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:hover .rst-current-version{background:#1a1c1e;font-size:inherit;height:auto;line-height:inherit;padding:12px;text-align:right}#furo-readthedocs-versions:focus-within .rst-current-version .fa-book,#furo-readthedocs-versions:hover .rst-current-version .fa-book{color:#fff;float:left}#furo-readthedocs-versions:focus-within .fa-caret-down,#furo-readthedocs-versions:hover .fa-caret-down{display:none}#furo-readthedocs-versions:focus-within .injected,#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:focus-within .rst-other-versions,#furo-readthedocs-versions:hover .injected,#furo-readthedocs-versions:hover .rst-current-version,#furo-readthedocs-versions:hover .rst-other-versions{display:block}#furo-readthedocs-versions:focus-within>.rst-current-version,#furo-readthedocs-versions:hover>.rst-current-version{display:none}.highlight:hover button.copybtn{color:var(--color-code-foreground)}.highlight button.copybtn{align-items:center;background-color:var(--color-code-background);border:none;color:var(--color-background-item);cursor:pointer;height:1.25em;opacity:1;right:.5rem;top:.625rem;transition:color .3s,opacity .3s;width:1.25em}.highlight button.copybtn:hover{background-color:var(--color-code-background);color:var(--color-brand-content)}.highlight button.copybtn:after{background-color:transparent;color:var(--color-code-foreground);display:none}.highlight button.copybtn.success{color:#22863a;transition:color 0ms}.highlight button.copybtn.success:after{display:block}.highlight button.copybtn svg{padding:0}body{--sd-color-primary:var(--color-brand-primary);--sd-color-primary-highlight:var(--color-brand-content);--sd-color-primary-text:var(--color-background-primary);--sd-color-shadow:rgba(0,0,0,.05);--sd-color-card-border:var(--color-card-border);--sd-color-card-border-hover:var(--color-brand-content);--sd-color-card-background:var(--color-card-background);--sd-color-card-text:var(--color-foreground-primary);--sd-color-card-header:var(--color-card-marginals-background);--sd-color-card-footer:var(--color-card-marginals-background);--sd-color-tabs-label-active:var(--color-brand-content);--sd-color-tabs-label-hover:var(--color-foreground-muted);--sd-color-tabs-label-inactive:var(--color-foreground-muted);--sd-color-tabs-underline-active:var(--color-brand-content);--sd-color-tabs-underline-hover:var(--color-foreground-border);--sd-color-tabs-underline-inactive:var(--color-background-border);--sd-color-tabs-overline:var(--color-background-border);--sd-color-tabs-underline:var(--color-background-border)}.sd-tab-content{box-shadow:0 -2px var(--sd-color-tabs-overline),0 1px var(--sd-color-tabs-underline)}.sd-card{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)}.sd-shadow-sm{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-md{box-shadow:0 .3rem .75rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-lg{box-shadow:0 .6rem 1.5rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-card-hover:hover{transform:none}.sd-cards-carousel{gap:.25rem;padding:.25rem}body{--tabs--label-text:var(--color-foreground-muted);--tabs--label-text--hover:var(--color-foreground-muted);--tabs--label-text--active:var(--color-brand-content);--tabs--label-text--active--hover:var(--color-brand-content);--tabs--label-background:transparent;--tabs--label-background--hover:transparent;--tabs--label-background--active:transparent;--tabs--label-background--active--hover:transparent;--tabs--padding-x:0.25em;--tabs--margin-x:1em;--tabs--border:var(--color-background-border);--tabs--label-border:transparent;--tabs--label-border--hover:var(--color-foreground-muted);--tabs--label-border--active:var(--color-brand-content);--tabs--label-border--active--hover:var(--color-brand-content)}[role=main] .container{max-width:none;padding-left:0;padding-right:0}.shadow.docutils{border:none;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)!important}.sphinx-bs .card{background-color:var(--color-background-secondary);color:var(--color-foreground)} 2 | /*# sourceMappingURL=furo-extensions.css.map*/ -------------------------------------------------------------------------------- /docs/build/html/_static/styles/furo-extensions.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"styles/furo-extensions.css","mappings":"AAGA,2BACE,oFACA,4CAKE,6CAHA,YACA,eAEA,CACA,kDACE,yCAEF,8CACE,sCAEJ,8CACE,kDAEJ,2BAGE,uBACA,cAHA,gBACA,UAEA,CAGA,yCACE,mBAEF,gDAEE,gDADA,YACA,CACA,sDACE,gDACF,yDACE,sCAEJ,+CACE,UACA,qDACE,UAGF,mDACE,eAEJ,yEAEE,4DAEA,mHASE,mBAPA,kBAEA,YADA,oBAGA,aADA,gBAIA,CAEA,qIAEE,WADA,UACA,CAEJ,uGACE,aAEF,iUAGE,cAEF,mHACE,aC1EJ,gCACE,mCAEF,0BAKE,mBAUA,8CACA,YAFA,mCAKA,eAZA,cALA,UASA,YADA,YAYA,iCAdA,YAcA,CAEA,gCAEE,8CADA,gCACA,CAEF,gCAGE,6BADA,mCADA,YAEA,CAEF,kCAEE,cADA,oBACA,CACA,wCACE,cAEJ,8BACE,UC5CN,KAEE,6CAA8C,CAC9C,uDAAwD,CACxD,uDAAwD,CAGxD,iCAAsC,CAGtC,+CAAgD,CAChD,uDAAwD,CACxD,uDAAwD,CACxD,oDAAqD,CACrD,6DAA8D,CAC9D,6DAA8D,CAG9D,uDAAwD,CACxD,yDAA0D,CAC1D,4DAA6D,CAC7D,2DAA4D,CAC5D,8DAA+D,CAC/D,iEAAkE,CAClE,uDAAwD,CACxD,wDAAyD,CAG3D,gBACE,qFAGF,SACE,6EAEF,cACE,uFAEF,cACE,uFAEF,cACE,uFAGF,qBACE,eAEF,mBACE,WACA,eChDF,KACE,gDAAiD,CACjD,uDAAwD,CACxD,qDAAsD,CACtD,4DAA6D,CAC7D,oCAAqC,CACrC,2CAA4C,CAC5C,4CAA6C,CAC7C,mDAAoD,CACpD,wBAAyB,CACzB,oBAAqB,CACrB,6CAA8C,CAC9C,gCAAiC,CACjC,yDAA0D,CAC1D,uDAAwD,CACxD,8DAA+D,CCbjE,uBACE,eACA,eACA,gBAGF,iBACE,YACA,+EAGF,iBACE,mDACA","sources":["webpack:///./src/furo/assets/styles/extensions/_readthedocs.sass","webpack:///./src/furo/assets/styles/extensions/_copybutton.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-design.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-inline-tabs.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-panels.sass"],"sourcesContent":["// This file contains the styles used for tweaking how ReadTheDoc's embedded\n// contents would show up inside the theme.\n\n#furo-sidebar-ad-placement\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n .ethical-sidebar\n // Remove the border and box-shadow.\n border: none\n box-shadow: none\n // Manage the background colors.\n background: var(--color-background-secondary)\n &:hover\n background: var(--color-background-hover)\n // Ensure the text is legible.\n a\n color: var(--color-foreground-primary)\n\n .ethical-callout a\n color: var(--color-foreground-secondary) !important\n\n#furo-readthedocs-versions\n position: static\n width: 100%\n background: transparent\n display: block\n\n // Make the background color fit with the theme's aesthetic.\n .rst-versions\n background: rgb(26, 28, 30)\n\n .rst-current-version\n cursor: unset\n background: var(--color-sidebar-item-background)\n &:hover\n background: var(--color-sidebar-item-background)\n .fa-book\n color: var(--color-foreground-primary)\n\n > .rst-other-versions\n padding: 0\n small\n opacity: 1\n\n .injected\n .rst-versions\n position: unset\n\n &:hover,\n &:focus-within\n box-shadow: 0 0 0 1px var(--color-sidebar-background-border)\n\n .rst-current-version\n // Undo the tweaks done in RTD's CSS\n font-size: inherit\n line-height: inherit\n height: auto\n text-align: right\n padding: 12px\n\n // Match the rest of the body\n background: #1a1c1e\n\n .fa-book\n float: left\n color: white\n\n .fa-caret-down\n display: none\n\n .rst-current-version,\n .rst-other-versions,\n .injected\n display: block\n\n > .rst-current-version\n display: none\n",".highlight\n &:hover button.copybtn\n color: var(--color-code-foreground)\n\n button.copybtn\n // Make it visible\n opacity: 1\n\n // Align things correctly\n align-items: center\n\n height: 1.25em\n width: 1.25em\n\n top: 0.625rem // $code-spacing-vertical\n right: 0.5rem\n\n // Make it look better\n color: var(--color-background-item)\n background-color: var(--color-code-background)\n border: none\n\n // Change to cursor to make it obvious that you can click on it\n cursor: pointer\n\n // Transition smoothly, for aesthetics\n transition: color 300ms, opacity 300ms\n\n &:hover\n color: var(--color-brand-content)\n background-color: var(--color-code-background)\n\n &::after\n display: none\n color: var(--color-code-foreground)\n background-color: transparent\n\n &.success\n transition: color 0ms\n color: #22863a\n &::after\n display: block\n\n svg\n padding: 0\n","body\n // Colors\n --sd-color-primary: var(--color-brand-primary)\n --sd-color-primary-highlight: var(--color-brand-content)\n --sd-color-primary-text: var(--color-background-primary)\n\n // Shadows\n --sd-color-shadow: rgba(0, 0, 0, 0.05)\n\n // Cards\n --sd-color-card-border: var(--color-card-border)\n --sd-color-card-border-hover: var(--color-brand-content)\n --sd-color-card-background: var(--color-card-background)\n --sd-color-card-text: var(--color-foreground-primary)\n --sd-color-card-header: var(--color-card-marginals-background)\n --sd-color-card-footer: var(--color-card-marginals-background)\n\n // Tabs\n --sd-color-tabs-label-active: var(--color-brand-content)\n --sd-color-tabs-label-hover: var(--color-foreground-muted)\n --sd-color-tabs-label-inactive: var(--color-foreground-muted)\n --sd-color-tabs-underline-active: var(--color-brand-content)\n --sd-color-tabs-underline-hover: var(--color-foreground-border)\n --sd-color-tabs-underline-inactive: var(--color-background-border)\n --sd-color-tabs-overline: var(--color-background-border)\n --sd-color-tabs-underline: var(--color-background-border)\n\n// Tabs\n.sd-tab-content\n box-shadow: 0 -2px var(--sd-color-tabs-overline), 0 1px var(--sd-color-tabs-underline)\n\n// Shadows\n.sd-card // Have a shadow by default\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n.sd-shadow-sm\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-md\n box-shadow: 0 0.3rem 0.75rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-lg\n box-shadow: 0 0.6rem 1.5rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Cards\n.sd-card-hover:hover // Don't change scale on hover\n transform: none\n\n.sd-cards-carousel // Have a bit of gap in the carousel by default\n gap: 0.25rem\n padding: 0.25rem\n","// This file contains styles to tweak sphinx-inline-tabs to work well with Furo.\n\nbody\n --tabs--label-text: var(--color-foreground-muted)\n --tabs--label-text--hover: var(--color-foreground-muted)\n --tabs--label-text--active: var(--color-brand-content)\n --tabs--label-text--active--hover: var(--color-brand-content)\n --tabs--label-background: transparent\n --tabs--label-background--hover: transparent\n --tabs--label-background--active: transparent\n --tabs--label-background--active--hover: transparent\n --tabs--padding-x: 0.25em\n --tabs--margin-x: 1em\n --tabs--border: var(--color-background-border)\n --tabs--label-border: transparent\n --tabs--label-border--hover: var(--color-foreground-muted)\n --tabs--label-border--active: var(--color-brand-content)\n --tabs--label-border--active--hover: var(--color-brand-content)\n","// This file contains styles to tweak sphinx-panels to work well with Furo.\n\n// sphinx-panels includes Bootstrap 4, which uses .container which can conflict\n// with docutils' `.. container::` directive.\n[role=\"main\"] .container\n max-width: initial\n padding-left: initial\n padding-right: initial\n\n// Make the panels look nicer!\n.shadow.docutils\n border: none\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Make panel colors respond to dark mode\n.sphinx-bs .card\n background-color: var(--color-background-secondary)\n color: var(--color-foreground)\n"],"names":[],"sourceRoot":""} -------------------------------------------------------------------------------- /docs/build/html/genindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Index - scenvi 0.3.2 documentation 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 36 | 37 | 38 | 41 | 42 | 43 | 44 | 45 | Contents 46 | 47 | 48 | 49 | 50 | 51 | Menu 52 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | Expand 61 | 63 | 64 | 65 | 66 | 67 | Light mode 68 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | Dark mode 83 | 85 | 86 | 87 | 88 | 89 | 90 | Auto light/dark mode 91 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 109 | 112 | 113 | 114 | 115 |
116 |
117 |
118 | 122 |
123 | 126 |
127 |
128 | 134 |
135 | 139 |
140 |
141 | 172 |
173 |
174 |
175 | 176 | 177 | 178 | 179 | Back to top 180 | 181 |
182 |
183 | 189 |
190 | 194 |
195 |
196 | 197 |
198 |

Index

199 |
200 |
201 | 202 |
203 |
204 |
205 | 206 | 210 |
211 |
212 | 215 | Made with Sphinx and @pradyunsg's 216 | 217 | Furo 218 | 219 |
220 |
221 | 222 |
223 |
224 | 225 |
226 |
227 | 232 |
233 |
234 | 235 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /docs/build/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | scenvi 0.3.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 38 | 39 | 40 | 43 | 44 | 45 | 46 | 47 | Contents 48 | 49 | 50 | 51 | 52 | 53 | Menu 54 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Expand 63 | 65 | 66 | 67 | 68 | 69 | Light mode 70 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Dark mode 85 | 87 | 88 | 89 | 90 | 91 | 92 | Auto light/dark mode 93 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 111 | 114 | 115 | 116 | 117 |
118 |
119 |
120 | 124 |
125 | 128 |
129 |
130 | 136 |
137 | 141 |
142 |
143 | 174 |
175 |
176 |
177 | 178 | 179 | 180 | 181 | Back to top 182 | 183 |
184 | 185 |
186 | 192 |
193 | 197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |

ENVI & COVET

205 |

ENVI is a deep learnining based variational inference method to integrate scRNA-seq with spatial transcriptomics data. ENVI learns to reconstruct spatial onto for dissociated scRNA-seq data and impute unimagd genes onto spatial data.

206 |

This implementation is written in Python3 and relies on jax, flax, sklearn, scipy and scanpy.

207 |

To install JAX, simply run the command:

208 |
pip install -U "jax[cuda12_pip]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html
209 | 
210 |
211 |

And to install ENVI along with the rest of the requirements:

212 |
pip install scenvi
213 | 
214 |
215 |

To run ENVI:

216 |
import scenvi
217 | 
218 | envi_model = scenvi.ENVI(spatial_data = st_data, sc_data = sc_data)
219 | 
220 | envi_model.train()
221 | envi_model.impute_genes()
222 | envi_model.infer_niche_covet()
223 | envi_model.infer_niche_celltype()
224 | 
225 | st_data.obsm['envi_latent'] = envi_model.spatial_data.obsm['envi_latent']
226 | st_data.uns['COVET_genes'] =  envi_model.CovGenes
227 | st_data.obsm['COVET'] = envi_model.spatial_data.obsm['COVET']
228 | st_data.obsm['COVET_SQRT'] = envi_model.spatial_data.obsm['COVET_SQRT']
229 | st_data.obsm['cell_type_niche'] = envi_model.spatial_data.obsm['cell_type_niche']
230 | st_data.obsm['imputation'] = envi_model.spatial_data.obsm['imputation']
231 | 
232 | 
233 | sc_data.obsm['envi_latent'] = envi_model.sc_data.obsm['envi_latent']
234 | sc_data.uns['COVET_genes'] =  envi_model.CovGenes
235 | sc_data.obsm['COVET'] = envi_model.sc_data.obsm['COVET']
236 | sc_data.obsm['COVET_SQRT'] = envi_model.sc_data.obsm['COVET_SQRT']
237 | sc_data.obsm['cell_type_niche'] = envi_model.sc_data.obsm['cell_type_niche']
238 | 
239 |
240 |

And to just compute COVET for spatial data:

241 |
st_data.obsm['COVET'], st_data.obsm['COVET_SQRT'], st_data.uns['CovGenes'] = scenvi.compute_covet(st_data)
242 | 
243 |
244 |

Please read our documentation and see a full tutorial at https://scenvi.readthedocs.io/.

245 |
246 |
247 |

Index

248 | 251 |
252 | 253 |
254 |
255 | 285 |
286 | 291 |
292 |
293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | -------------------------------------------------------------------------------- /docs/build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/docs/build/html/objects.inv -------------------------------------------------------------------------------- /docs/build/html/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Search - scenvi 0.3.2 documentation 8 | 9 | 10 | 11 | 12 | 13 | 14 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | 44 | Contents 45 | 46 | 47 | 48 | 49 | 50 | Menu 51 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Expand 60 | 62 | 63 | 64 | 65 | 66 | Light mode 67 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Dark mode 82 | 84 | 85 | 86 | 87 | 88 | 89 | Auto light/dark mode 90 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 108 | 111 | 112 | 113 | 114 |
115 |
116 |
117 | 121 |
122 | 125 |
126 |
127 | 133 |
134 | 138 |
139 |
140 | 171 |
172 |
173 |
174 | 175 | 176 | 177 | 178 | Back to top 179 | 180 |
181 |
182 | 188 |
189 | 193 |
194 |
195 | 196 | 204 | 205 |
206 | 207 |
208 |
209 |
210 | 211 | 215 |
216 |
217 | 220 | Made with Sphinx and @pradyunsg's 221 | 222 | Furo 223 | 224 |
225 |
226 | 227 |
228 |
229 | 230 |
231 |
232 | 237 |
238 |
239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | -------------------------------------------------------------------------------- /docs/build/html/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({"alltitles": {"Calculating FDL and DC on COVET": [[2, "Calculating-FDL-and-DC-on-COVET"]], "Data": [[2, "Data"]], "ENVI": [[0, "envi"]], "ENVI & COVET": [[1, "envi-covet"]], "ENVI COVET analysis": [[2, "ENVI-COVET-analysis"]], "ENVI Tutorial": [[2, "ENVI-Tutorial"]], "ENVI imputation on Spatial Data": [[2, "ENVI-imputation-on-Spatial-Data"]], "Importing": [[2, "Importing"]], "Index": [[1, "index"]], "Install ENVI": [[2, "Install-ENVI"]], "Niche Cell Type Composition": [[2, "Niche-Cell-Type-Composition"]], "Plot DC and Depth": [[2, "Plot-DC-and-Depth"]], "Plot UMAPs of ENVI latent": [[2, "Plot-UMAPs-of-ENVI-latent"]], "Plot as Stacked Bar Plots": [[2, "Plot-as-Stacked-Bar-Plots"]], "Plotting the Motor Cortex MERFISH": [[2, "Plotting-the-Motor-Cortex-MERFISH"]], "Plotting the Motor Cortex scRNAseq": [[2, "Plotting-the-Motor-Cortex-scRNAseq"]], "Reverse DC if needed": [[2, "Reverse-DC-if-needed"]], "Running ENVI": [[2, "Running-ENVI"]], "Subtype Depth": [[2, "Subtype-Depth"]], "Utilities": [[3, "utilities"]], "Utility Functions:": [[2, "Utility-Functions:"]], "What is COVET?": [[2, "What-is-COVET?"]], "What is ENVI?": [[2, "What-is-ENVI?"]]}, "docnames": ["ENVI", "index", "tutorial/MOp_MERFISH_tutorial", "utils"], "envversion": {"nbsphinx": 4, "sphinx": 61, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2}, "filenames": ["ENVI.rst", "index.rst", "tutorial/MOp_MERFISH_tutorial.ipynb", "utils.rst"], "indexentries": {}, "objects": {}, "objnames": {}, "objtypes": {}, "terms": {"": 2, "0": 2, "00": 2, "007843": 2, "01": 2, "015686": 2, "02": 2, "027451": 2, "03": 2, "03it": 2, "04": 2, "1": 2, "10": 2, "100": 2, "1000": 2, "106": 2, "108": 2, "10it": 2, "11": 2, "12": 2, "121": 2, "122": 2, "13": 2, "131": 2, "14": 2, "147": 2, "148": 2, "15": 2, "151": 2, "153": 2, "16": 2, "16000": 2, "17": 2, "18": 2, "185": 2, "188235": 2, "19": 2, "1e": 2, "2": 2, "2024": 2, "2048": 2, "207": 2, "21": 2, "22": 2, "23": 2, "231373": 2, "235294": 2, "24": 2, "25": 2, "255": 2, "256": 2, "26": 2, "27": 2, "28": 2, "29": 2, "294118": 2, "3": 2, "30": 2, "309804": 2, "31": 2, "329412": 2, "33": 2, "339e": 2, "341176": 2, "345098": 2, "34902": 2, "352941": 2, "368627": 2, "39": 2, "392157": 2, "4": 2, "415686": 2, "423529": 2, "431e": 2, "447059": 2, "454902": 2, "458824": 2, "466667": 2, "470588": 2, "473e": 2, "47451": 2, "478431": 2, "482353": 2, "494118": 2, "498039": 2, "5": 2, "500": 2, "533333": 2, "54902": 2, "556441": 2, "560784": 2, "564706": 2, "584314": 2, "59": 2, "596078": 2, "6": 2, "607843": 2, "631373": 2, "643137": 2, "647059": 2, "65098": 2, "67451": 2, "693e": 2, "7": 2, "709804": 2, "717647": 2, "718": 2, "72549": 2, "737255": 2, "752941": 2, "780392": 2, "8": 2, "80": 2, "811765": 2, "819608": 2, "843137": 2, "847059": 2, "866667": 2, "894118": 2, "9": 2, "92549": 2, "933333": 2, "94": 2, "95": 2, "960784": 2, "992157": 2, "996078": 2, "And": 1, "For": 2, "The": 2, "To": 1, "__module__": 2, "__name__": 2, "abund": 2, "adamts18": 2, "adapt": 2, "adaptive_k": 2, "adaptive_std": 2, "adjac": 2, "adjusts": 2, "adjustspeedandapplyforc": 2, "affin": 2, "affinity_matrix": 2, "all": 2, "along": 1, "alpha": 2, "altern": 2, "amazonaw": 2, "analy": 2, "anisotrop": 2, "anndata": 2, "approxim": 2, "ar": 2, "arang": 2, "arbitrari": 2, "argsort": 2, "arr": 2, "arrai": 2, "asarrai": 2, "ascend": 2, "astro": 2, "attract": 2, "auxiliari": 2, "aw": 2, "ax": 2, "axi": 2, "backward": 2, "barneshut": 2, "barneshutoptim": 2, "barneshuttheta": 2, "base": [1, 2], "batch": 2, "bbox_to_anchor": 2, "becaus": 2, "behavior": 2, "between": 2, "blue": 2, "box": 2, "boxenplot": 2, "bw": 2, "c": 2, "calb2": 2, "can": 2, "canon": 2, "cc": 2, "cell_label_palett": 2, "cell_nam": 2, "cell_typ": 2, "cell_type_nich": [1, 2], "cell_type_palett": 2, "cellular": 2, "cet_cet_d13": 2, "chang": 2, "check": 2, "chodl": 2, "cluster_label": 2, "cmap": 2, "co": 2, "col": 2, "color": 2, "colorcet": 2, "column": 2, "com": [1, 2], "command": [1, 2], "compat": 2, "compil": 2, "compon": 2, "comput": [1, 2], "compute_covet": 1, "concaten": 2, "construct": 2, "context": 2, "correspond": 2, "cortic": 2, "cov": 2, "covari": 2, "covet_gen": [1, 2], "covet_sqrt": [1, 2], "covgen": [1, 2], "cpu": 2, "creat": 2, "crh": 2, "crhr2": 2, "csr_matrix": 2, "cuda": 2, "cuda12_pip": 1, "cuda_device_ord": 2, "cuda_visible_devic": 2, "cvae": 2, "cvec": 2, "d": 2, "data": 1, "data_df": 2, "datafram": 2, "dataset": 2, "dc_covet": 2, "dcomposit": 2, "deep": [1, 2], "def": 2, "defin": 2, "delta": 2, "depth_df": 2, "determ": 2, "determin": 2, "devic": 2, "dictionari": 2, "diffus": 2, "direct": 2, "directli": 2, "disabl": 2, "dissoci": [1, 2], "dist": 2, "distanc": 2, "div": 2, "dkkl1": 2, "document": 1, "dot": 2, "doubl": 2, "down": 2, "download": 2, "dp": 2, "driver": 2, "drop": 2, "each": 2, "edgecolor": 2, "edgeweightinflu": 2, "eig": 2, "eigen": 2, "eigenvalu": 2, "eigenvector": 2, "els": 2, "emb": 2, "embed": 2, "endo": 2, "enumer": 2, "envi_lat": [1, 2], "envi_model": [1, 2], "environ": 2, "equal": 2, "er": 2, "etc": 2, "etv1": 2, "euclidean": 2, "everi": 2, "exp": 2, "extern": 2, "f": 1, "fa2": 2, "fals": 2, "fdl_covet": 2, "feel": 2, "fig": 2, "figsiz": 2, "figur": 2, "filterwarn": 2, "find": 2, "finish": 2, "first": 2, "fit": 2, "fit_transform": 2, "flatten": 2, "flax": 1, "flip": 2, "floor": 2, "follow": 2, "font_scal": 2, "fontsiz": 2, "forc": 2, "force_directed_layout": 2, "forceatla": 2, "forceatlas2": 2, "forward": 2, "frame": 2, "free": 2, "from": 2, "full": 1, "gabaerg": 2, "gene": [1, 2], "get_titl": 2, "glutamaterg": 2, "go": 2, "googleapi": 1, "gpu": 2, "gran_sst_palett": 2, "graph": 2, "gravit": 2, "graviti": 2, "green": 2, "groupbi": 2, "h5ad": 2, "highly_vari": 2, "highly_variable_gen": 2, "hpse": 2, "hs6st2": 2, "hspe": 2, "html": 1, "http": [1, 2], "hue": 2, "i": 1, "ighm": 2, "ignor": 2, "implement": 1, "import": 1, "imput": 1, "impute_gen": [1, 2], "ind": 2, "index": 2, "indptr": 2, "infer": 1, "infer_niche_celltyp": [1, 2], "infer_niche_covet": [1, 2], "init_coord": 2, "initi": 2, "inlin": 2, "inplac": 2, "input": 2, "instal": 1, "int": 2, "integr": [1, 2], "intial": 2, "io": 1, "isspars": 2, "iter": 2, "jax": 1, "jax_cuda_releas": 1, "jittertoler": 2, "just": 1, "k": 2, "kernel": 2, "kind": 2, "kl": 2, "kneighbors_graph": 2, "knn": 2, "l2": 2, "l23_it": 2, "l45_it": 2, "l56_np": 2, "l5_et": 2, "l5_it": 2, "l5_pt": 2, "l6_ct": 2, "l6_it": 2, "l6_it_car3": 2, "l6b": 2, "l_alpha": 2, "lab": 2, "label": 2, "lamp5": 2, "latent_umap": 2, "layer": 2, "layout": 2, "learn": 1, "learnin": 1, "left": 2, "legend": 2, "len": 2, "lim_arr": 2, "linalg": 2, "linlogmod": 2, "load": 2, "loc": 2, "log": 2, "lower": 2, "lt": 2, "mai": 2, "map": 2, "marker": 2, "markerscal": 2, "markov": 2, "mat": 2, "matplotlib": 2, "matric": 2, "matrix": 2, "max": 2, "maxit": 2, "mean": 2, "method": [1, 2], "metric": 2, "microglia": 2, "min_dist": 2, "miss": 2, "mode": 2, "model": 2, "mouse1_slice10": 2, "mouse1_slice162": 2, "mouse1_slice212": 2, "mouse1_slice40": 2, "mouse1_slice71": 2, "mouse2_slice270": 2, "multithread": 2, "myh8": 2, "n": 2, "n_compon": 2, "n_job": 2, "n_neighbor": 2, "n_pc": 2, "n_top_gen": 2, "name": 2, "nbr": 2, "ncol": 2, "nearest": 2, "nearestneighbor": 2, "neighbor": 2, "neuron": 2, "non": 2, "none": 2, "norm": 2, "normal": 2, "note": 2, "np": 2, "number": 2, "numpi": 2, "nvidia": 2, "nvptx_compil": 2, "o": 2, "ob": 2, "object": 2, "obsm": [1, 2], "obsp": 2, "off": 2, "older": 2, "oligo": 2, "onto": 1, "opc": 2, "oper": 2, "order": 2, "our": 1, "outboundattractiondistribut": 2, "own": 2, "packag": 2, "pair": 2, "palett": 2, "pamr1": 2, "panda": 2, "parallel": 2, "param": 2, "paramet": 2, "pca": 2, "pci_bus_id": 2, "pd": 2, "pe": 2, "percentil": 2, "perform": 2, "pericyt": 2, "phenograph": 2, "pip": [1, 2], "pleas": 1, "plt": 2, "po": 2, "posit": 2, "pp": 2, "pre": 2, "predict": 2, "prefer": 2, "print": 2, "produc": 2, "project": 2, "prop": 2, "proport": 2, "provid": 2, "pseudo": 2, "ptxa": 2, "public": 2, "pvalb": 2, "pyplot": 2, "python3": 1, "quantifi": 2, "random": 2, "rang": 2, "ravel": 2, "re": 2, "read": [1, 2], "read_h5ad": 2, "readthedoc": 1, "real": 2, "reconstruct": 1, "red": 2, "releas": 1, "reli": [1, 2], "repres": 2, "represent": 2, "repuls": 2, "requir": 1, "reshap": 2, "rest": 1, "result": 2, "return": 2, "run": 1, "run_diffusion_map": 2, "s3": 2, "sc": 2, "sc_data": [1, 2], "sc_data_sst": 2, "scalingratio": 2, "scanpi": [1, 2], "scatterplot": 2, "scenvi": [1, 2], "scipi": [1, 2], "scrna": [1, 2], "scrna_seq": 2, "seaborn": 2, "second": 2, "see": [1, 2], "seq": [1, 2], "seri": 2, "servic": 2, "set": 2, "set_styl": 2, "setp": 2, "shallow": 2, "shape": 2, "should": 2, "show": 2, "simpli": [1, 2], "size": 2, "sklearn": [1, 2], "slit1": 2, "slow": 2, "small": 2, "smc": 2, "sn": 2, "sncg": 2, "so": 2, "some": 2, "sort": 2, "sort_valu": 2, "spars": 2, "spatial": 1, "spatial_data": [1, 2], "specif": 2, "sqrt": 2, "sst": 2, "st_data": [1, 2], "st_data_sst": 2, "st_databatch": 2, "st_dataplotbatch": 2, "std": 2, "step": 2, "storag": 1, "stronggravitymod": 2, "subplot": 2, "subtype_canon": 2, "subtype_depth_ord": 2, "sum": 2, "switch": 2, "t": 2, "take": 2, "temp": 2, "th": 2, "than": 2, "thi": [1, 2], "tick_gen": 2, "tight_layout": 2, "titl": 2, "todens": 2, "tol": 2, "took": 2, "train": [1, 2], "transcriptom": 1, "true": 2, "tune": 2, "tutori": 1, "u": 1, "umap_": 2, "umap_exp": 2, "un": [1, 2], "unimagd": 1, "updat": 2, "us": 2, "v": 2, "vae": 2, "valu": 2, "var": 2, "variat": 1, "verbos": 2, "version": 2, "vip": 2, "vlmc": 2, "vmax": 2, "vmin": 2, "w": 2, "want": 2, "warn": 2, "we": 2, "wget": 2, "which": 2, "whitegrid": 2, "width": 2, "written": 1, "x": 2, "xla": 2, "xlabel": 2, "xlim": 2, "xmax": 2, "xmin": 2, "y": 2, "ylabel": 2, "ylim": 2, "ymax": 2, "ymin": 2, "you": 2, "your": 2, "zero": 2, "zoom": 2}, "titles": ["ENVI", "ENVI & COVET", "ENVI Tutorial", "Utilities"], "titleterms": {"analysi": 2, "bar": 2, "calcul": 2, "cell": 2, "composit": 2, "cortex": 2, "covet": [1, 2], "data": 2, "dc": 2, "depth": 2, "envi": [0, 1, 2], "fdl": 2, "function": 2, "i": 2, "import": 2, "imput": 2, "index": 1, "instal": 2, "latent": 2, "merfish": 2, "motor": 2, "need": 2, "nich": 2, "plot": 2, "revers": 2, "run": 2, "scrnaseq": 2, "spatial": 2, "stack": 2, "subtyp": 2, "tutori": 2, "type": 2, "umap": 2, "util": [2, 3], "what": 2}}) -------------------------------------------------------------------------------- /docs/build/html/utils.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Utilities - scenvi 0.3.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 38 | 39 | 40 | 43 | 44 | 45 | 46 | 47 | Contents 48 | 49 | 50 | 51 | 52 | 53 | Menu 54 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Expand 63 | 65 | 66 | 67 | 68 | 69 | Light mode 70 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Dark mode 85 | 87 | 88 | 89 | 90 | 91 | 92 | Auto light/dark mode 93 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 111 | 114 | 115 | 116 | 117 |
118 |
119 |
120 | 124 |
125 | 128 |
129 |
130 | 136 |
137 | 141 |
142 |
143 | 174 |
175 |
176 |
177 | 178 | 179 | 180 | 181 | Back to top 182 | 183 |
184 | 185 |
186 | 192 |
193 | 197 |
198 |
199 |
200 |

Utilities

201 |
202 | 203 |
204 |
205 | 237 |
238 | 243 |
244 |
245 | 246 | 247 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /docs/docs_requirements.txt: -------------------------------------------------------------------------------- 1 | sphinxcontrib-autoprogram 2 | sphinxcontrib-napoleon 3 | sphinx-autodocgen 4 | sphinx-github-style 5 | sphinx-mdinclude 6 | m2r2 7 | nbsphinx 8 | furo 9 | typing-extensions 10 | IPython 11 | pandoc 12 | tomli -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/ENVI.rst: -------------------------------------------------------------------------------- 1 | ENVI 2 | ========= 3 | 4 | .. automodule:: scenvi.ENVI 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | # -- Project information ----------------------------------------------------- 7 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 8 | 9 | # Configuration file for the Sphinx documentation builder. 10 | # 11 | # This file only contains a selection of the most common options. For a full 12 | # list see the documentation: 13 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 14 | 15 | # -- Path setup -------------------------------------------------------------- 16 | 17 | # If extensions (or modules to document with autodoc) are in another directory, 18 | # add these directories to sys.path here. If the directory is relative to the 19 | # documentation root, use os.path.abspath to make it absolute, like shown here. 20 | # 21 | import os 22 | import sys 23 | from pathlib import Path 24 | import datetime 25 | import tomli 26 | 27 | sys.path.insert(0, os.path.abspath("../../src")) 28 | 29 | this_directory = Path(__file__).parent 30 | 31 | # Get current year for copyright 32 | current_year = datetime.datetime.now().year 33 | 34 | # Get package version from pyproject.toml 35 | try: 36 | pyproject_path = Path(__file__).parents[2] / "pyproject.toml" 37 | if pyproject_path.exists(): 38 | with open(pyproject_path, "rb") as f: 39 | pyproject_data = tomli.load(f) 40 | package_version = pyproject_data.get("tool", {}).get("poetry", {}).get("version", "0.1.0") 41 | else: 42 | package_version = "0.1.0" 43 | except Exception as e: 44 | print(f"Warning: Could not read version from pyproject.toml: {e}") 45 | package_version = "0.1.0" 46 | 47 | # -- Project information ----------------------------------------------------- 48 | 49 | project = "scenvi" 50 | copyright = f"{current_year}, Doron Haviv" 51 | author = 'Doron Haviv' 52 | 53 | # The full version, including alpha/beta/rc tags 54 | release = package_version 55 | 56 | 57 | # -- General configuration --------------------------------------------------- 58 | 59 | # Add any Sphinx extension module names here, as strings. They can be 60 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 61 | # ones. 62 | extensions = [ 63 | "sphinx.ext.autodoc", 64 | "nbsphinx", 65 | "sphinx.ext.napoleon", 66 | "sphinx_mdinclude", 67 | ] 68 | if os.environ.get('READTHEDOCS') == 'True': 69 | extensions.append("sphinx_github_style") 70 | 71 | source_suffix = [".rst", ".md"] 72 | 73 | # Add any paths that contain templates here, relative to this directory. 74 | templates_path = ["_templates"] 75 | 76 | # List of patterns, relative to source directory, that match files and 77 | # directories to ignore when looking for source files. 78 | # This pattern also affects html_static_path and html_extra_path. 79 | exclude_patterns = ["_build", "**.ipynb_checkpoints"] 80 | 81 | # GitHub repository info 82 | github_user = "dpeerlabs" # Replace with your actual GitHub username 83 | github_repo = "scenvi" # Replace with your actual repository name 84 | github_version = "main" # Or your default branch 85 | 86 | # For sphinx-github-style extension when on ReadTheDocs 87 | if os.environ.get('READTHEDOCS') == 'True': 88 | linkcode_url = f"https://github.com/{github_user}/{github_repo}/blob/{github_version}" 89 | 90 | # -- Options for HTML output ------------------------------------------------- 91 | 92 | # The theme to use for HTML and HTML Help pages. See the documentation for 93 | # a list of builtin themes. 94 | # 95 | html_theme = "furo" 96 | pygments_style = "tango" 97 | 98 | highlight_language = "none" 99 | 100 | # Add any paths that contain custom static files (such as style sheets) here, 101 | # relative to this directory. They are copied after the builtin static files, 102 | # so a file named "default.css" will overwrite the builtin "default.css". 103 | html_static_path = [] -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. scenvi documentation master file, created by 2 | sphinx-quickstart on Wed Apr 24 12:13:12 2024. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | .. toctree:: 7 | :hidden: 8 | :caption: Tutorials: 9 | 10 | tutorial/MOp_MERFISH_tutorial 11 | 12 | .. toctree:: 13 | :hidden: 14 | :caption: Modules: 15 | 16 | ENVI 17 | Utilities 18 | 19 | 20 | .. mdinclude:: ../../README.md 21 | 22 | Index 23 | ===== 24 | 25 | * :ref:`genindex` 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/source/utils.rst: -------------------------------------------------------------------------------- 1 | Utilities 2 | ========= 3 | 4 | .. automodule:: scenvi.utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "scenvi" 3 | version = "0.4.5" 4 | description = "Integration of scRNA-seq and spatial transcpriptomics data" 5 | authors = ["Doron Haviv"] 6 | license = "MIT" 7 | readme = "README.md" 8 | 9 | [tool.poetry.dependencies] 10 | scanpy = "^1.11.0" 11 | python = "^3.9" 12 | flax = "^0.10.4" 13 | optax = "^0.2.4" 14 | tensorflow_probability = "^0.22.0" 15 | clu = "^0.0.11" 16 | tqdm = "^4.66.1" 17 | 18 | [build-system] 19 | requires = ["poetry-core"] 20 | build-backend = "poetry.core.masonry.api" 21 | -------------------------------------------------------------------------------- /readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-20.04 5 | tools: 6 | python: "3.11" 7 | 8 | sphinx: 9 | configuration: docs/source/conf.py 10 | 11 | python: 12 | install: 13 | - requirements: docs/docs_requirements.txt 14 | - method: pip 15 | path: . -------------------------------------------------------------------------------- /scenvi/__init__.py: -------------------------------------------------------------------------------- 1 | from scenvi.ENVI import ENVI # noqa: F401 2 | from scenvi.utils import compute_covet # noqa: F401 3 | -------------------------------------------------------------------------------- /scenvi/__pycache__/ENVI.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/scenvi/__pycache__/ENVI.cpython-39.pyc -------------------------------------------------------------------------------- /scenvi/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/scenvi/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /scenvi/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/scenvi/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /scenvi/__pycache__/dists.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/scenvi/__pycache__/dists.cpython-39.pyc -------------------------------------------------------------------------------- /scenvi/__pycache__/utils.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpeerlab/ENVI/b433de227c7d90bb5ef355bd9cb961f4b1a422dc/scenvi/__pycache__/utils.cpython-39.pyc -------------------------------------------------------------------------------- /scenvi/_dists.py: -------------------------------------------------------------------------------- 1 | import jax.numpy as jnp 2 | import tensorflow_probability.substrates.jax.distributions as jnd 3 | 4 | 5 | def KL(mean, log_std): 6 | """ 7 | :meta private: 8 | """ 9 | KL = 0.5 * (jnp.square(mean) + jnp.square(jnp.exp(log_std)) - 2 * log_std) 10 | return jnp.mean(KL, axis=-1) 11 | 12 | 13 | def log_pos_pdf(sample, l): # noqa: E741 14 | """ 15 | :meta private: 16 | """ 17 | 18 | log_prob = jnd.Poisson(rate=l).log_prob(sample) 19 | return jnp.mean(log_prob, axis=-1) 20 | 21 | 22 | def log_nb_pdf(sample, r, p): 23 | """ 24 | :meta private: 25 | """ 26 | 27 | log_prob = jnd.NegativeBinomial(total_count=r, logits=p).log_prob(sample) 28 | return jnp.mean(log_prob, axis=-1) 29 | 30 | 31 | def log_zinb_pdf(sample, r, p, d): 32 | """ 33 | :meta private: 34 | """ 35 | 36 | log_prob = jnd.Inflated( 37 | jnd.NegativeBinomial(total_count=r, logits=p), inflated_loc_logits=d 38 | ).log_prob(sample) 39 | return jnp.mean(log_prob, axis=-1) 40 | 41 | 42 | def log_normal_pdf(sample, mean): 43 | """ 44 | :meta private: 45 | """ 46 | 47 | log_prob = jnd.Normal(loc=mean, scale=1).log_prob(sample) 48 | return jnp.mean(log_prob, axis=-1) 49 | 50 | 51 | def AOT_Distance(sample, mean): 52 | """ 53 | :meta private: 54 | """ 55 | 56 | sample = jnp.reshape(sample, [sample.shape[0], -1]) 57 | mean = jnp.reshape(mean, [mean.shape[0], -1]) 58 | log_prob = -jnp.square(sample - mean) 59 | return jnp.mean(log_prob, axis=-1) 60 | -------------------------------------------------------------------------------- /scenvi/utils.py: -------------------------------------------------------------------------------- 1 | import jax 2 | import jax.numpy as jnp 3 | import numpy as np 4 | import pandas as pd 5 | import scanpy as sc 6 | import sklearn.neighbors 7 | from clu import metrics 8 | from flax import linen as nn 9 | from flax import struct 10 | from flax.training import train_state 11 | from jax import random 12 | 13 | from sklearn.preprocessing import OneHotEncoder 14 | from tqdm import tqdm 15 | import scipy.sparse 16 | 17 | class FeedForward(nn.Module): 18 | """ 19 | :meta private: 20 | """ 21 | 22 | n_layers: int 23 | n_neurons: int 24 | n_output: int 25 | 26 | @nn.compact 27 | def __call__(self, x): 28 | """ 29 | :meta private: 30 | """ 31 | 32 | n_layers = self.n_layers 33 | n_neurons = self.n_neurons 34 | n_output = self.n_output 35 | 36 | x = nn.Dense( 37 | features=n_neurons, 38 | dtype=jnp.float32, 39 | kernel_init=nn.initializers.glorot_uniform(), 40 | bias_init=nn.initializers.zeros_init(), 41 | )(x) 42 | x = nn.leaky_relu(x) 43 | x = nn.LayerNorm(dtype=jnp.float32)(x) 44 | 45 | for _ in range(n_layers - 1): 46 | 47 | x = nn.Dense( 48 | features=n_neurons, 49 | dtype=jnp.float32, 50 | kernel_init=nn.initializers.glorot_uniform(), 51 | bias_init=nn.initializers.zeros_init(), 52 | )(x) 53 | x = nn.leaky_relu(x) + x 54 | x = nn.LayerNorm(dtype=jnp.float32)(x) 55 | 56 | output = nn.Dense( 57 | features=n_output, 58 | dtype=jnp.float32, 59 | kernel_init=nn.initializers.glorot_uniform(), 60 | bias_init=nn.initializers.zeros_init(), 61 | )(x) 62 | 63 | return output 64 | 65 | 66 | class CVAE(nn.Module): 67 | """ 68 | :meta private: 69 | """ 70 | 71 | n_layers: int 72 | n_neurons: int 73 | n_latent: int 74 | n_output_exp: int 75 | n_output_cov: int 76 | 77 | def setup(self): 78 | """ 79 | :meta private: 80 | """ 81 | 82 | n_layers = self.n_layers 83 | n_neurons = self.n_neurons 84 | n_latent = self.n_latent 85 | n_output_exp = self.n_output_exp 86 | n_output_cov = self.n_output_cov 87 | 88 | self.encoder = FeedForward( 89 | n_layers=n_layers, n_neurons=n_neurons, n_output=n_latent * 2 90 | ) 91 | 92 | self.decoder_exp = FeedForward( 93 | n_layers=n_layers, n_neurons=n_neurons, n_output=n_output_exp 94 | ) 95 | 96 | self.decoder_cov = FeedForward( 97 | n_layers=n_layers, n_neurons=n_neurons, n_output=n_output_cov 98 | ) 99 | 100 | def __call__(self, x, mode="spatial", key=random.key(0)): 101 | """ 102 | :meta private: 103 | """ 104 | 105 | conf_const = 0 if mode == "spatial" else 1 106 | conf_neurons = jax.nn.one_hot( 107 | conf_const * jnp.ones(x.shape[0], dtype=jnp.int8), 2, dtype=jnp.float32 108 | ) 109 | 110 | x_conf = jnp.concatenate([x, conf_neurons], axis=-1) 111 | enc_mu, enc_logstd = jnp.split(self.encoder(x_conf), 2, axis=-1) 112 | 113 | key, subkey = random.split(key) 114 | z = enc_mu + random.normal(key=subkey, shape=enc_logstd.shape) * jnp.exp( 115 | enc_logstd 116 | ) 117 | z_conf = jnp.concatenate([z, conf_neurons], axis=-1) 118 | 119 | dec_exp = self.decoder_exp(z_conf) 120 | 121 | if mode == "spatial": 122 | dec_cov = self.decoder_cov(z) 123 | return (enc_mu, enc_logstd, dec_exp, dec_cov) 124 | return (enc_mu, enc_logstd, dec_exp) 125 | 126 | 127 | @struct.dataclass 128 | class Metrics(metrics.Collection): 129 | """ 130 | :meta private: 131 | """ 132 | 133 | enc_loss: metrics.Average 134 | dec_loss: metrics.Average 135 | enc_corr: metrics.Average 136 | 137 | 138 | class TrainState(train_state.TrainState): 139 | """ 140 | :meta private: 141 | """ 142 | 143 | metrics: Metrics 144 | 145 | def batch_matrix_sqrt(Mats): 146 | """ 147 | :meta private: 148 | """ 149 | 150 | e, v = np.linalg.eigh(Mats) 151 | e = np.where(e < 0, 0, e) 152 | e = np.sqrt(e) 153 | 154 | m, n = e.shape 155 | diag_e = np.zeros((m, n, n), dtype=e.dtype) 156 | diag_e.reshape(-1, n**2)[..., :: n + 1] = e 157 | return np.matmul(np.matmul(v, diag_e), v.transpose([0, 2, 1])) 158 | 159 | 160 | def batch_knn(data, batch, k): 161 | """ 162 | :meta private: 163 | """ 164 | 165 | kNNGraphIndex = np.zeros(shape=(data.shape[0], k)) 166 | 167 | for val in np.unique(batch): 168 | val_ind = np.where(batch == val)[0] 169 | 170 | batch_knn = sklearn.neighbors.kneighbors_graph( 171 | data[val_ind], n_neighbors=k, mode="connectivity", n_jobs=-1 172 | ).tocoo() 173 | batch_knn_ind = np.reshape( 174 | np.asarray(batch_knn.col), [data[val_ind].shape[0], k] 175 | ) 176 | kNNGraphIndex[val_ind] = val_ind[batch_knn_ind] 177 | 178 | return kNNGraphIndex.astype("int") 179 | 180 | 181 | def calculate_covariance_matrices(spatial_data, kNN, exp_data, spatial_key="spatial", batch_key=-1, batch_size=None): 182 | """ 183 | Calculate covariance matrices for each cell/spot in spatial data using provided expression data 184 | 185 | :param spatial_data: AnnData object with spatial coordinates 186 | :param kNN: Number of nearest neighbors 187 | :param exp_data: Pre-processed expression data to use for covariance calculation 188 | :param spatial_key: Key for spatial coordinates in obsm 189 | :param batch_key: Key for batch information in obs, or -1 for no batch 190 | :param batch_size: Number of cells to process at once (for memory efficiency) 191 | 192 | :return: 3D array of covariance matrices 193 | """ 194 | 195 | # Get the KNN graph 196 | if batch_key == -1: 197 | kNNGraph = sklearn.neighbors.kneighbors_graph( 198 | spatial_data.obsm[spatial_key], 199 | n_neighbors=kNN, 200 | mode="connectivity", 201 | n_jobs=-1, 202 | ).tocoo() 203 | kNNGraphIndex = np.reshape( 204 | np.asarray(kNNGraph.col), [spatial_data.obsm[spatial_key].shape[0], kNN] 205 | ) 206 | else: 207 | kNNGraphIndex = batch_knn( 208 | spatial_data.obsm[spatial_key], spatial_data.obs[batch_key], kNN 209 | ) 210 | 211 | # Get the global mean for each feature 212 | global_mean = exp_data.mean(axis=0) 213 | 214 | # Initialize the output covariance matrices 215 | n_cells = exp_data.shape[0] 216 | n_features = exp_data.shape[1] 217 | CovMats = np.zeros((n_cells, n_features, n_features), dtype=np.float32) 218 | 219 | # Process in batches if requested 220 | if batch_size is None or batch_size >= n_cells: 221 | # Process all cells at once 222 | print("Calculating covariance matrices for all cells/spots") 223 | DistanceMatWeighted = ( 224 | global_mean[None, None, :] 225 | - exp_data[kNNGraphIndex[np.arange(n_cells)]] 226 | ) 227 | 228 | CovMats = np.matmul( 229 | DistanceMatWeighted.transpose([0, 2, 1]), DistanceMatWeighted 230 | ) / (kNN - 1) 231 | else: 232 | # Process in batches to save memory 233 | batch_indices = np.array_split(np.arange(n_cells), np.ceil(n_cells / batch_size)) 234 | 235 | for batch_idx in tqdm(batch_indices, desc="Calculating covariance matrices"): 236 | # Get neighbor indices for this batch 237 | batch_neighbors = kNNGraphIndex[batch_idx] 238 | 239 | # Calculate the distance matrices for this batch 240 | batch_distances = ( 241 | global_mean[None, None, :] 242 | - exp_data[batch_neighbors] 243 | ) 244 | 245 | # Calculate the covariance matrices for this batch 246 | batch_covs = np.matmul( 247 | batch_distances.transpose([0, 2, 1]), batch_distances 248 | ) / (kNN - 1) 249 | 250 | # Store the results 251 | CovMats[batch_idx] = batch_covs 252 | 253 | # Add a small regularization term to ensure positive definiteness 254 | reg_term = CovMats.mean() * 0.00001 255 | identity = np.eye(n_features)[None, :, :] 256 | CovMats = CovMats + reg_term * identity 257 | 258 | return CovMats 259 | 260 | def niche_cell_type( 261 | spatial_data, kNN, spatial_key="spatial", cell_type_key="cell_type", batch_key=-1 262 | ): 263 | """ 264 | :meta private: 265 | """ 266 | 267 | 268 | 269 | if batch_key == -1: 270 | kNNGraph = sklearn.neighbors.kneighbors_graph( 271 | spatial_data.obsm[spatial_key], 272 | n_neighbors=kNN, 273 | mode="connectivity", 274 | n_jobs=-1, 275 | ).tocoo() 276 | knn_index = np.reshape( 277 | np.asarray(kNNGraph.col), [spatial_data.obsm[spatial_key].shape[0], kNN] 278 | ) 279 | else: 280 | knn_index = batch_knn( 281 | spatial_data.obsm[spatial_key], spatial_data.obs[batch_key], kNN 282 | ) 283 | 284 | one_hot_enc = OneHotEncoder().fit( 285 | np.asarray(list(set(spatial_data.obs[cell_type_key]))).reshape([-1, 1]) 286 | ) 287 | cell_type_one_hot = ( 288 | one_hot_enc.transform( 289 | np.asarray(spatial_data.obs[cell_type_key]).reshape([-1, 1]) 290 | ) 291 | .reshape([spatial_data.obs["cell_type"].shape[0], -1]) 292 | .todense() 293 | ) 294 | 295 | cell_type_niche = pd.DataFrame( 296 | cell_type_one_hot[knn_index].sum(axis=1), 297 | index=spatial_data.obs_names, 298 | columns=list(one_hot_enc.categories_[0]), 299 | ) 300 | return cell_type_niche 301 | 302 | def compute_covet( 303 | spatial_data, k=8, g=64, genes=None, spatial_key="spatial", batch_key="batch", 304 | batch_size=None, use_obsm=None, use_layer=None 305 | ): 306 | """ 307 | Compute niche covariance matrices for spatial data, run with scenvi.compute_covet 308 | 309 | :param spatial_data: (anndata) spatial data, with an obsm indicating spatial location of spot/segmented cell 310 | :param k: (int) number of nearest neighbours to define niche (default 8) 311 | :param g: (int) number of HVG to compute COVET representation on (default 64) 312 | :param genes: (list of str) list of genes to keep for niche covariance (default []) 313 | :param spatial_key: (str) obsm key name with physical location of spots/cells (default 'spatial') 314 | :param batch_key: (str) obs key name of batch/sample of spatial data (default 'batch' if in spatial_data.obs, else -1) 315 | :param batch_size: (int) Number of cells/spots to process at once for large datasets (default None) 316 | :param use_obsm: (str) obsm key to use for COVET calculation instead of gene expression (e.g. 'X_pca', 'X_dc') (default None) 317 | :param use_layer: (str) layer to use for COVET calculation instead of log-transformed X (e.g. 'log', 'log1p') (default None) 318 | 319 | :return COVET: niche covariance matrices 320 | :return COVET_SQRT: matrix square-root of niche covariance matrices for approximate OT 321 | :return CovGenes: list of genes selected for COVET representation (or feature names if using obsm) 322 | """ 323 | 324 | genes = [] if genes is None else genes 325 | 326 | # Handle batch key 327 | if batch_key not in spatial_data.obs.columns: 328 | batch_key = -1 329 | 330 | # Determine data source: obsm, layer, or X 331 | if use_obsm is not None: 332 | if use_obsm not in spatial_data.obsm: 333 | raise ValueError(f"obsm key '{use_obsm}' not found in spatial_data.obsm") 334 | 335 | # Use the specified obsm embedding 336 | print(f"Computing COVET using obsm '{use_obsm}' with {spatial_data.obsm[use_obsm].shape[1]} dimensions") 337 | CovGenes = [f"{use_obsm}_{i}" for i in range(spatial_data.obsm[use_obsm].shape[1])] 338 | exp_data = spatial_data.obsm[use_obsm] 339 | 340 | else: 341 | # Select genes for covariance calculation 342 | if g == -1 or g >= spatial_data.shape[1]: 343 | # Use all genes 344 | CovGenes = spatial_data.var_names 345 | print(f"Computing COVET using all {len(CovGenes)} genes") 346 | else: 347 | # Check if highly variable genes need to be calculated 348 | if "highly_variable" not in spatial_data.var.columns: 349 | print(f"Identifying top {g} highly variable genes for COVET calculation") 350 | # Create a copy to avoid modifying the input 351 | spatial_data_copy = spatial_data.copy() 352 | 353 | # Determine appropriate layer for HVG calculation 354 | if use_layer is None: 355 | if 'log' in spatial_data_copy.layers: 356 | layer = "log" 357 | elif 'log1p' in spatial_data_copy.layers: 358 | layer = "log1p" 359 | elif spatial_data_copy.X.min() < 0: 360 | # Data is already log-transformed 361 | layer = None 362 | else: 363 | # Create log layer 364 | spatial_data_copy.layers["log"] = np.log(spatial_data_copy.X + 1) 365 | layer = "log" 366 | else: 367 | layer = use_layer 368 | 369 | # Calculate HVGs 370 | sc.pp.highly_variable_genes( 371 | spatial_data_copy, 372 | n_top_genes=g, 373 | layer=layer if layer else None 374 | ) 375 | # Get HVG names 376 | hvg_genes = spatial_data_copy.var_names[spatial_data_copy.var.highly_variable] 377 | if(len(hvg_genes) > g): 378 | print(f"Found {len(hvg_genes)} HVGs") 379 | else: 380 | # HVGs already calculated 381 | hvg_genes = spatial_data.var_names[spatial_data.var.highly_variable] 382 | print(f"Using {len(hvg_genes)} pre-calculated highly variable genes for COVET") 383 | 384 | # Combine HVGs with manually specified genes 385 | CovGenes = np.asarray(hvg_genes) 386 | if len(genes) > 0: 387 | CovGenes = np.union1d(CovGenes, genes) 388 | print(f"Added {len(genes)} user-specified genes to COVET calculation") 389 | 390 | print(f"Computing COVET using {len(CovGenes)} genes") 391 | 392 | # Get expression data based on selected genes and specified layer 393 | if use_layer is not None: 394 | if use_layer not in spatial_data.layers: 395 | raise ValueError(f"Layer '{use_layer}' not found in spatial_data.layers") 396 | print(f"Using expression data from layer '{use_layer}'") 397 | exp_data = spatial_data[:, CovGenes].layers[use_layer].toarray() if scipy.sparse.issparse(spatial_data.layers[use_layer]) else spatial_data[:, CovGenes].layers[use_layer] 398 | else: 399 | # Default: log-transform X if needed 400 | if spatial_data.X.min() < 0: 401 | # Data is already log-transformed 402 | print("Using expression data from X (appears to be log-transformed)") 403 | exp_data = spatial_data[:, CovGenes].X.toarray() if scipy.sparse.issparse(spatial_data.X) else spatial_data[:, CovGenes].X 404 | else: 405 | print("Log-transforming expression data from X") 406 | exp_data = np.log(spatial_data[:, CovGenes].X.toarray() + 1) if scipy.sparse.issparse(spatial_data.X) else np.log(spatial_data[:, CovGenes].X + 1) 407 | 408 | # Calculate covariance matrices with batch processing 409 | COVET = calculate_covariance_matrices( 410 | spatial_data, k, exp_data, spatial_key=spatial_key, 411 | batch_key=batch_key, batch_size=batch_size 412 | ) 413 | 414 | # Calculate matrix square root 415 | if batch_size is None or batch_size >= COVET.shape[0]: 416 | print("Computing matrix square root...") 417 | COVET_SQRT = batch_matrix_sqrt(COVET) 418 | else: 419 | # Process matrix square root in batches too 420 | n_cells = COVET.shape[0] 421 | COVET_SQRT = np.zeros_like(COVET) 422 | 423 | # Split into batches 424 | batch_indices = np.array_split(np.arange(n_cells), np.ceil(n_cells / batch_size)) 425 | 426 | for batch_idx in tqdm(batch_indices, desc="Computing matrix square roots"): 427 | # Process this batch of matrices 428 | batch_sqrt = batch_matrix_sqrt(COVET[batch_idx]) 429 | COVET_SQRT[batch_idx] = batch_sqrt 430 | 431 | # Return results with proper types 432 | return ( 433 | COVET.astype("float32"), 434 | COVET_SQRT.astype("float32"), 435 | np.asarray(CovGenes, dtype=str), 436 | ) -------------------------------------------------------------------------------- /tests/test_ENVI.py: -------------------------------------------------------------------------------- 1 | import pytest # type: ignore 2 | 3 | import anndata 4 | import numpy as np 5 | 6 | import scenvi 7 | 8 | @pytest.fixture 9 | def example_model(): 10 | st_data = anndata.AnnData(X=np.random.uniform(low=0, high=100, size=(16, 4)), 11 | obsm={'spatial': np.random.normal(size=[16, 2])}) 12 | sc_data = anndata.AnnData(X=np.random.uniform(low=0, high=100, size=(16, 8))) 13 | 14 | envi_model = scenvi.ENVI(spatial_data=st_data, sc_data=sc_data, batch_key=-1) 15 | return envi_model 16 | 17 | @pytest.fixture 18 | def example_model_with_hvg(): 19 | # Create data with pre-computed HVGs 20 | st_data = anndata.AnnData(X=np.random.uniform(low=0, high=100, size=(16, 4)), 21 | obsm={'spatial': np.random.normal(size=[16, 2])}) 22 | sc_data = anndata.AnnData(X=np.random.uniform(low=0, high=100, size=(16, 8))) 23 | 24 | # Add highly_variable column 25 | sc_data.var['highly_variable'] = [True, False, True, False, True, False, True, False] 26 | 27 | envi_model = scenvi.ENVI(spatial_data=st_data, sc_data=sc_data, batch_key=-1) 28 | return envi_model 29 | 30 | @pytest.fixture 31 | def example_model_with_user_genes(): 32 | st_data = anndata.AnnData(X=np.random.uniform(low=0, high=100, size=(16, 4)), 33 | obsm={'spatial': np.random.normal(size=[16, 2])}) 34 | st_data.var_names = [f"gene{i}" for i in range(4)] 35 | 36 | sc_data = anndata.AnnData(X=np.random.uniform(low=0, high=100, size=(16, 8))) 37 | sc_data.var_names = [f"gene{i}" for i in range(8)] 38 | 39 | # Specify user genes to include 40 | user_genes = ["gene1", "gene3", "gene5"] 41 | 42 | envi_model = scenvi.ENVI(spatial_data=st_data, sc_data=sc_data, batch_key=-1, sc_genes=user_genes) 43 | return envi_model 44 | 45 | @pytest.fixture 46 | def large_example_model(): 47 | # Create larger dataset to test batch processing 48 | st_data = anndata.AnnData(X=np.random.uniform(low=0, high=100, size=(100, 32)), 49 | obsm={'spatial': np.random.normal(size=[100, 2])}) 50 | sc_data = anndata.AnnData(X=np.random.uniform(low=0, high=100, size=(100, 64))) 51 | 52 | envi_model = scenvi.ENVI(spatial_data=st_data, sc_data=sc_data, batch_key=-1, num_cov_genes = 16) 53 | return envi_model 54 | 55 | def test_train(example_model): 56 | example_model.train(training_steps=1) 57 | 58 | assert 'COVET' in example_model.spatial_data.obsm 59 | assert 'COVET_SQRT' in example_model.spatial_data.obsm 60 | 61 | assert 'envi_latent' in example_model.spatial_data.obsm 62 | assert example_model.spatial_data.obsm['envi_latent'].shape == (example_model.spatial_data.shape[0], example_model.latent_dim) 63 | 64 | assert 'envi_latent' in example_model.sc_data.obsm 65 | assert example_model.sc_data.obsm['envi_latent'].shape == (example_model.sc_data.shape[0], example_model.latent_dim) 66 | 67 | def test_impute(example_model): 68 | example_model.train(training_steps=1) 69 | example_model.impute_genes() 70 | 71 | assert 'imputation' in example_model.spatial_data.obsm 72 | 73 | def test_infer_niche(example_model): 74 | example_model.train(training_steps=1) 75 | example_model.infer_niche_covet() 76 | 77 | assert 'COVET_SQRT' in example_model.sc_data.obsm 78 | assert 'COVET' in example_model.sc_data.obsm 79 | 80 | def test_precomputed_hvg(example_model_with_hvg): 81 | """Test that pre-computed highly variable genes are correctly used""" 82 | # Check that the HVGs from input were maintained 83 | hvg_count = sum(example_model_with_hvg.sc_data.var['highly_variable']) 84 | assert hvg_count > 0 85 | 86 | # Train and verify 87 | example_model_with_hvg.train(training_steps=1) 88 | assert 'envi_latent' in example_model_with_hvg.spatial_data.obsm 89 | assert 'envi_latent' in example_model_with_hvg.sc_data.obsm 90 | 91 | def test_user_specified_genes(example_model_with_user_genes): 92 | """Test that user-specified genes are correctly included""" 93 | # Check that user-specified genes are included 94 | for gene in ["gene1", "gene3", "gene5"]: 95 | if gene in example_model_with_user_genes.sc_data.var_names: 96 | assert gene in example_model_with_user_genes.sc_data.var_names 97 | 98 | # Train and verify 99 | example_model_with_user_genes.train(training_steps=1) 100 | example_model_with_user_genes.impute_genes() 101 | 102 | # Check that imputation includes these genes 103 | assert 'imputation' in example_model_with_user_genes.spatial_data.obsm 104 | imputed_genes = example_model_with_user_genes.spatial_data.obsm['imputation'].columns 105 | 106 | for gene in ["gene1", "gene3", "gene5"]: 107 | if gene in example_model_with_user_genes.sc_data.var_names: 108 | assert gene in imputed_genes 109 | 110 | def test_all_genes_covet(): 111 | """Test using all genes for COVET calculation""" 112 | # Create a new model using all genes for COVET 113 | st_data = anndata.AnnData(X=np.random.uniform(low=0, high=100, size=(16, 4)), 114 | obsm={'spatial': np.random.normal(size=[16, 2])}) 115 | sc_data = anndata.AnnData(X=np.random.uniform(low=0, high=100, size=(16, 8))) 116 | 117 | # Set num_cov_genes=-1 to use all genes 118 | envi_model = scenvi.ENVI(spatial_data=st_data, sc_data=sc_data, batch_key=-1, num_cov_genes=-1) 119 | 120 | # Verify all genes are used 121 | assert len(envi_model.CovGenes) == st_data.shape[1] 122 | 123 | # Train and verify 124 | envi_model.train(training_steps=1) 125 | assert 'COVET' in envi_model.spatial_data.obsm 126 | 127 | def test_covet_with_batches(large_example_model): 128 | """Test COVET calculation with batch processing""" 129 | # Calculate COVET matrices using batch processing 130 | 131 | 132 | 133 | (covet, covet_sqrt, cov_genes) = scenvi.compute_covet( 134 | large_example_model.spatial_data, 135 | k=5, 136 | g=6, 137 | batch_size=20 # Process in batches of 20 138 | ) 139 | # Verify the results 140 | assert covet.shape[0] == large_example_model.spatial_data.shape[0] 141 | assert covet_sqrt.shape[0] == large_example_model.spatial_data.shape[0] 142 | assert len(cov_genes) >= 6 143 | 144 | # Verify shapes match expected dimensions 145 | assert covet.shape[1] == covet.shape[2] # Square matrices 146 | assert covet_sqrt.shape[1] == covet_sqrt.shape[2] # Square matrices 147 | assert covet.shape[1] == len(cov_genes) # Matrix size matches gene count 148 | 149 | def test_niche_cell_type(example_model): 150 | """Test niche cell type inference""" 151 | # Add cell type information 152 | example_model.spatial_data.obs['cell_type'] = np.random.choice( 153 | ['Type1', 'Type2', 'Type3'], size=example_model.spatial_data.shape[0] 154 | ) 155 | 156 | # Train model 157 | example_model.train(training_steps=1) 158 | example_model.infer_niche_covet() 159 | # Infer niche cell types 160 | 161 | example_model.infer_niche_celltype(cell_type_key='cell_type') 162 | 163 | # Verify results 164 | assert 'cell_type_niche' in example_model.spatial_data.obsm 165 | assert 'cell_type_niche' in example_model.sc_data.obsm 166 | 167 | # Check the columns of the cell_type_niche match the unique cell types 168 | unique_cell_types = sorted(example_model.spatial_data.obs['cell_type'].unique()) 169 | niche_columns = sorted(example_model.sc_data.obsm['cell_type_niche'].columns) 170 | assert unique_cell_types == niche_columns --------------------------------------------------------------------------------