├── .github └── workflows │ └── python-package.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs ├── Makefile ├── _build │ ├── .doctrees │ │ ├── api.doctree │ │ ├── autoapi │ │ │ ├── index.doctree │ │ │ └── milopy │ │ │ │ ├── core │ │ │ │ └── index.doctree │ │ │ │ ├── index.doctree │ │ │ │ ├── plot │ │ │ │ └── index.doctree │ │ │ │ ├── tests │ │ │ │ ├── index.doctree │ │ │ │ ├── test_DA_nhoods │ │ │ │ │ └── index.doctree │ │ │ │ ├── test_annotate_nhoods │ │ │ │ │ └── index.doctree │ │ │ │ ├── test_count_nhoods │ │ │ │ │ └── index.doctree │ │ │ │ ├── test_io │ │ │ │ │ └── index.doctree │ │ │ │ ├── test_make_nhoods │ │ │ │ │ └── index.doctree │ │ │ │ └── test_plot │ │ │ │ │ └── index.doctree │ │ │ │ ├── utils │ │ │ │ └── index.doctree │ │ │ │ └── version │ │ │ │ └── index.doctree │ │ ├── index.doctree │ │ ├── milopy_example.doctree │ │ └── readme.doctree │ ├── _sources │ │ ├── api.rst.txt │ │ ├── autoapi │ │ │ ├── index.rst.txt │ │ │ └── milopy │ │ │ │ ├── core │ │ │ │ └── index.rst.txt │ │ │ │ ├── index.rst.txt │ │ │ │ ├── plot │ │ │ │ └── index.rst.txt │ │ │ │ ├── tests │ │ │ │ ├── index.rst.txt │ │ │ │ ├── test_DA_nhoods │ │ │ │ │ └── index.rst.txt │ │ │ │ ├── test_annotate_nhoods │ │ │ │ │ └── index.rst.txt │ │ │ │ ├── test_count_nhoods │ │ │ │ │ └── index.rst.txt │ │ │ │ ├── test_io │ │ │ │ │ └── index.rst.txt │ │ │ │ ├── test_make_nhoods │ │ │ │ │ └── index.rst.txt │ │ │ │ └── test_plot │ │ │ │ │ └── index.rst.txt │ │ │ │ ├── utils │ │ │ │ └── index.rst.txt │ │ │ │ └── version │ │ │ │ └── index.rst.txt │ │ └── index.rst.txt │ ├── api.html │ ├── autoapi │ │ ├── index.html │ │ └── milopy │ │ │ ├── core │ │ │ └── index.html │ │ │ ├── index.html │ │ │ ├── plot │ │ │ └── index.html │ │ │ ├── tests │ │ │ ├── index.html │ │ │ ├── test_DA_nhoods │ │ │ │ └── index.html │ │ │ ├── test_annotate_nhoods │ │ │ │ └── index.html │ │ │ ├── test_count_nhoods │ │ │ │ └── index.html │ │ │ ├── test_io │ │ │ │ └── index.html │ │ │ ├── test_make_nhoods │ │ │ │ └── index.html │ │ │ └── test_plot │ │ │ │ └── index.html │ │ │ ├── utils │ │ │ └── index.html │ │ │ └── version │ │ │ └── index.html │ ├── doctrees │ │ ├── environment.pickle │ │ └── index.doctree │ ├── html │ │ ├── .buildinfo │ │ ├── _sources │ │ │ └── index.rst.txt │ │ ├── _static │ │ │ ├── _sphinx_javascript_frameworks_compat.js │ │ │ ├── alabaster.css │ │ │ ├── basic.css │ │ │ ├── custom.css │ │ │ ├── doctools.js │ │ │ ├── documentation_options.js │ │ │ ├── file.png │ │ │ ├── jquery-3.6.0.js │ │ │ ├── jquery.js │ │ │ ├── language_data.js │ │ │ ├── minus.png │ │ │ ├── plus.png │ │ │ ├── pygments.css │ │ │ ├── searchtools.js │ │ │ ├── underscore-1.13.1.js │ │ │ └── underscore.js │ │ ├── genindex.html │ │ ├── index.html │ │ ├── milopy.rst │ │ ├── milopy.tests.rst │ │ ├── modules.rst │ │ ├── objects.inv │ │ ├── search.html │ │ └── searchindex.js │ ├── index.html │ └── reports │ │ └── milopy_example.err.log ├── api.rst ├── conf.py ├── index.md ├── index.rst ├── jupyter_execute │ ├── 19cffa128bdd43873065fb687f6783d072fd13d6a46e9571e9df4e86ef7f8e01.png │ ├── 60fe2e0e3f3b249ef5c44df2c62e4947bfa5fe5376652a22d18cd443c25bf3f2.png │ ├── 882e4262f5b1f970a56379ef517f24e1c50c08880d6cfd46d6d1184318fdc5f5.png │ ├── 8ab561250afc6b0c8550159dd96f6ac996a77a173eac1f617b88016d594433f3.png │ ├── 8e315beb2b1c3159b4475845d7131f21850c0afadd685ce52119278f60d61e53.png │ ├── 9fdf0fa20b948b519daf9016a4ef15fac541369cec8ac9c2a0f9bccf45231e71.png │ ├── fc2ef72cf4b4a63a47d0cde09b2e76b5d70c70e17e2e30e5d9149f8a766a2675.png │ └── milopy_example.ipynb ├── make.bat ├── milopy_example.ipynb ├── readme.rst └── requirements.txt ├── milopy ├── __init__.py ├── core.py ├── plot.py ├── tests │ ├── __init__.py │ ├── test_DA_nhoods.py │ ├── test_annotate_nhoods.py │ ├── test_count_nhoods.py │ ├── test_io.py │ ├── test_make_nhoods.py │ └── test_plot.py ├── utils.py └── version.py ├── notebooks └── milopy_example.ipynb ├── requirements.txt └── setup.py /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ['3.7', '3.8', '3.9', '3.10'] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: r-lib/actions/setup-r@v2 24 | - name: Set up Python ${{ matrix.python-version }} 25 | uses: actions/setup-python@v2 26 | with: 27 | python-version: ${{ matrix.python-version }} 28 | - name: Install dependencies 29 | run: | 30 | python -m pip install --upgrade pip 31 | python -m pip install flake8 pytest 32 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 33 | - name: Install R package dependencies 34 | run: | 35 | Rscript --vanilla -e "install.packages(c('BiocManager', 'statmod'), repos='http://cran.us.r-project.org'); library('BiocManager'); BiocManager::install('edgeR')" 36 | - name: Lint with flake8 37 | run: | 38 | # stop the build if there are Python syntax errors or undefined names 39 | flake8 . --count --select=E9,F63,F7,F82 --show-source --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 | # Compiled python modules. 2 | *.pyc 3 | 4 | # Setuptools distribution folder. 5 | /dist/ 6 | 7 | # Python egg metadata, regenerated from source files by setuptools. 8 | /*.egg-info 9 | 10 | .ipynb_checkpoints 11 | */.ipynb_checkpoints/* 12 | 13 | .vscode/ 14 | build/ 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.1.1 (23/09/2022) 4 | 5 | - Fixing bug in SpatialFDR assignment for compatibility with `pandas>=1.5` 6 | 7 | ## v0.1.0 (16/08/2022) 8 | 9 | - First stable release of `milopy` 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # milopy 2 | 📢📢 **NEWS: an improved and actively maintained python implementation of Milo can be now found in [scverse/pertpy](https://github.com/scverse/pertpy) ([tutorial](https://pertpy.readthedocs.io/en/latest/tutorials/notebooks/milo.html)). This package will soon be archived.** 3 | 4 | Basic python implementation of Milo for differential abundance testing on KNN graphs, to ease interoperability with [`scanpy`](https://scanpy.readthedocs.io/en/stable/index.html) pipelines for single-cell analysis. See our [preprint](https://www.biorxiv.org/content/10.1101/2020.11.23.393769v1) for details on the statistical framework. 5 | 6 | ## Installation 7 | 8 | To run the differential abundance testing, the R package `edgeR` needs to be installed. In R: 9 | ```r 10 | if (!requireNamespace("BiocManager", quietly = TRUE)) 11 | install.packages("BiocManager") 12 | BiocManager::install("edgeR") 13 | install.packages('statmod') 14 | ``` 15 | 16 | Then the package can be installed from source 17 | ``` 18 | git clone https://github.com/emdann/milopy.git 19 | cd milopy 20 | pip install . 21 | ``` 22 | 23 | ## Tutorial 24 | 25 | * [Guided example on mouse gastrulation data](https://nbviewer.jupyter.org/github/emdann/milopy/blob/master/notebooks/milopy_example.ipynb) 26 | 27 | 28 | 29 | ## Quick start 30 | ```python 31 | import scanpy as sc 32 | import numpy as np 33 | 34 | import milopy 35 | import milopy.core as milo 36 | ``` 37 | 38 | Load example dataset 39 | ```python 40 | adata = sc.datasets.pbmc3k_processed() 41 | ``` 42 | 43 | Simulate experimental condition and replicates 44 | ```python 45 | ## Simulate experimental condition ## 46 | adata.obs["condition"] = np.random.choice(["ConditionA", "ConditionB"], size=adata.n_obs, p=[0.5,0.5]) 47 | # we simulate differential abundance in NK cells 48 | DA_cells = adata.obs["louvain"] == "NK cells" 49 | adata.obs.loc[DA_cells, "condition"] = np.random.choice(["ConditionA", "ConditionB"], size=sum(DA_cells), p=[0.2,0.8]) 50 | 51 | ## Simulate replicates ## 52 | adata.obs["replicate"] = np.random.choice(["R1", "R2", "R3"], size=adata.n_obs) 53 | adata.obs["sample"] = adata.obs["replicate"] + adata.obs["condition"] 54 | 55 | sc.pl.umap(adata, color=["louvain","condition", "sample"]) 56 | ``` 57 | 58 | Test for differential abundance with Milo 59 | ```python 60 | ## Build KNN graph 61 | sc.pp.neighbors(adata, n_neighbors=10) 62 | 63 | ## Assign cells to neighbourhoods 64 | milo.make_nhoods(adata) 65 | 66 | ## Count cells from each sample in each nhood 67 | milo.count_nhoods(adata, sample_col="sample") 68 | 69 | ## Test for differential abundance between conditions 70 | milo.DA_nhoods(adata, design="~ condition") 71 | 72 | ## Check results 73 | milo_results = adata.uns["nhood_adata"].obs 74 | milo_results 75 | ``` 76 | 77 | Visualize results on UMAP embedding 78 | ```python 79 | milopy.utils.build_nhood_graph(adata) 80 | milopy.plot.plot_nhood_graph(adata, alpha=0.2, min_size=5) 81 | ``` 82 | -------------------------------------------------------------------------------- /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 = . 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/api.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/api.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/core/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/core/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/plot/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/plot/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/tests/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/tests/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/tests/test_DA_nhoods/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/tests/test_DA_nhoods/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/tests/test_annotate_nhoods/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/tests/test_annotate_nhoods/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/tests/test_count_nhoods/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/tests/test_count_nhoods/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/tests/test_io/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/tests/test_io/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/tests/test_make_nhoods/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/tests/test_make_nhoods/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/tests/test_plot/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/tests/test_plot/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/utils/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/utils/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/milopy/version/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/autoapi/milopy/version/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/milopy_example.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/milopy_example.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/readme.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/.doctrees/readme.doctree -------------------------------------------------------------------------------- /docs/_build/_sources/api.rst.txt: -------------------------------------------------------------------------------- 1 | ============ 2 | API 3 | ============ 4 | 5 | Import milopy as:: 6 | 7 | import milopy 8 | 9 | 10 | Core functions: `core` 11 | -------------------------------- 12 | 13 | Core functions for differential abundance testing 14 | 15 | .. toctree:: 16 | :maxdepth: 3 17 | :caption: core: 18 | 19 | autoapi/milopy/core/index 20 | 21 | 22 | Plotting functions: `plot` 23 | -------------------------------- 24 | .. toctree:: 25 | :maxdepth: 3 26 | :caption: plot: 27 | 28 | autoapi/milopy/plot/index 29 | 30 | 31 | 32 | Utility functions: `utils` 33 | -------------------------------- 34 | .. toctree:: 35 | :maxdepth: 3 36 | :caption: utils: 37 | 38 | autoapi/milopy/utils/index 39 | 40 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/index.rst.txt: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | This page contains auto-generated API reference documentation [#f1]_. 5 | 6 | .. toctree:: 7 | :titlesonly: 8 | 9 | /autoapi/milopy/index 10 | 11 | .. [#f1] Created with `sphinx-autoapi `_ -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/core/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.core` 2 | ===================== 3 | 4 | .. py:module:: milopy.core 5 | 6 | 7 | Module Contents 8 | --------------- 9 | 10 | 11 | Functions 12 | ~~~~~~~~~ 13 | 14 | .. autoapisummary:: 15 | 16 | milopy.core.make_nhoods 17 | milopy.core.count_nhoods 18 | milopy.core.DA_nhoods 19 | milopy.core._graph_spatialFDR 20 | milopy.core._try_import_bioc_library 21 | 22 | 23 | 24 | .. py:function:: make_nhoods(adata: anndata.AnnData, neighbors_key: str = None, prop=0.1, seed: int = 42) 25 | 26 | This function randomly samples vertcies on a graph to define neighbourhoods. 27 | These are then refined by computing the median profile for the neighbourhood 28 | in reduced dimensional space and selecting the nearest vertex to this 29 | position. Thus, multiple neighbourhoods may be collapsed down together to 30 | prevent over-sampling the graph space. 31 | 32 | - adata: AnnData object. Should contain a knn graph in `adata.obsp` 33 | - neighbors_key: string indicating the key in `adata.obsp` to use as KNN graph. If not specified, 34 | `make_nhoods` looks .obsp[‘connectivities’] for connectivities (default storage places for 35 | `scanpy.pp.neighbors`). If specified, it looks .obsp[.uns[neighbors_key][‘connectivities_key’]] for 36 | connectivities. 37 | - prop: fraction of cells to sample for neighbourhood index search (default: 0.1) 38 | - seed: random seed for cell sampling (default: 42) 39 | 40 | 41 | .. py:function:: count_nhoods(adata: anndata.AnnData, sample_col: str) 42 | 43 | - adata 44 | - sample_col: string, column in adata.obs that contains sample information 45 | (what should be in the columns of the nhoodCount matrix) 46 | 47 | Returns: None 48 | Updated adata.uns slot to contain adata.uns["nhood_adata"], where: 49 | - adata.uns["nhood_adata"].obs_names are neighbourhoods 50 | - adata.uns["nhood_adata"].var_names are samples 51 | - adata.uns["nhood_adata"].X is the matrix counting the number of cells from each 52 | sample in each neighbourhood 53 | 54 | 55 | .. py:function:: DA_nhoods(adata, design, model_contrasts=None, subset_samples=None, add_intercept=True) 56 | 57 | This will perform differential neighbourhood abundance testing (using edgeR under the hood) 58 | - adata 59 | - design: formula (terms should be columns in adata.uns["nhood_adata"].var) 60 | - model_contrasts: A string vector that defines the contrasts used to perform DA testing 61 | - subset_samples: subset of samples (columns in `adata.uns["nhood_adata"].X`) to use for the test 62 | - add_intercept: whether to include an intercept in the model. If False, this is equivalent to adding + 0 in the design formula. 63 | When model_contrasts is specified, this is set to False by default. 64 | 65 | 66 | .. py:function:: _graph_spatialFDR(adata, neighbors_key=None) 67 | 68 | FDR correction weighted on inverse of connectivity of neighbourhoods. 69 | The distance to the k-th nearest neighbor is used as a measure of connectivity. 70 | 71 | 72 | .. py:function:: _try_import_bioc_library(name) 73 | 74 | 75 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy` 2 | ================ 3 | 4 | .. py:module:: milopy 5 | 6 | 7 | Subpackages 8 | ----------- 9 | .. toctree:: 10 | :titlesonly: 11 | :maxdepth: 3 12 | 13 | tests/index.rst 14 | 15 | 16 | Submodules 17 | ---------- 18 | .. toctree:: 19 | :titlesonly: 20 | :maxdepth: 1 21 | 22 | core/index.rst 23 | plot/index.rst 24 | utils/index.rst 25 | version/index.rst 26 | 27 | 28 | Package Contents 29 | ---------------- 30 | 31 | .. py:data:: __version__ 32 | :annotation: = 0.0.999 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/plot/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.plot` 2 | ===================== 3 | 4 | .. py:module:: milopy.plot 5 | 6 | 7 | Module Contents 8 | --------------- 9 | 10 | 11 | Functions 12 | ~~~~~~~~~ 13 | 14 | .. autoapisummary:: 15 | 16 | milopy.plot.plot_nhood_graph 17 | milopy.plot.plot_nhood 18 | milopy.plot.plot_DA_beeswarm 19 | milopy.plot._get_palette_adata 20 | milopy.plot.plot_nhood_counts_by_cond 21 | 22 | 23 | 24 | .. py:function:: plot_nhood_graph(adata: anndata.AnnData, alpha: float = 0.1, min_logFC: float = 0, min_size: int = 10, plot_edges: bool = False, title: str = 'DA log-Fold Change', **kwargs) 25 | 26 | Visualize DA results on abstracted graph (wrapper around sc.pl.embedding) 27 | 28 | Params: 29 | ------- 30 | - adata: AnnData object 31 | - alpha: significance threshold 32 | - min_logFC: minimum absolute log-Fold Change to show results (default: 0, show all significant neighbourhoods) 33 | - min_size: minimum size of nodes in visualization (default: 10) 34 | - plot_edges: boolean indicating if edges for neighbourhood overlaps whould be plotted (default: False) 35 | - title: plot title (default: 'DA log-Fold Change') 36 | - **kwargs: other arguments to pass to scanpy.pl.embedding 37 | 38 | 39 | .. py:function:: plot_nhood(adata, ix, basis='X_umap') 40 | 41 | Visualize cells in a neighbourhood 42 | 43 | 44 | .. py:function:: plot_DA_beeswarm(adata: anndata.AnnData, anno_col: str = 'nhood_annotation', alpha: float = 0.1, subset_nhoods: List = None) 45 | 46 | Plot beeswarm plot of logFC against nhood labels 47 | 48 | Params: 49 | ------- 50 | - adata: AnnData object 51 | - anno_col: column in adata.uns['nhood_adata'].obs to use as annotation 52 | - alpha: significance threshold 53 | - subset_nhoods: list of nhoods to plot (default: None, plot all nhoods) 54 | 55 | 56 | .. py:function:: _get_palette_adata(adata, obs_col) 57 | 58 | 59 | .. py:function:: plot_nhood_counts_by_cond(adata: anndata.AnnData, test_var: str, subset_nhoods: List = None, log_counts: bool = False) 60 | 61 | Plot boxplot of cell numbers vs condition of interest 62 | 63 | Params: 64 | ------ 65 | - adata: anndata object storing neighbourhood information in adata.uns 66 | - test_var: string, name of column in adata.obs storing condition of interest (y-axis for boxplot) 67 | - subset_nhoods: list of obs_names for neighbourhoods to include in plot (default: None, plot all nhoods) 68 | - log_counts: boolean, whether to plot log1p of cell counts (default: False) 69 | 70 | 71 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/tests/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.tests` 2 | ====================== 3 | 4 | .. py:module:: milopy.tests 5 | 6 | 7 | Submodules 8 | ---------- 9 | .. toctree:: 10 | :titlesonly: 11 | :maxdepth: 1 12 | 13 | test_DA_nhoods/index.rst 14 | test_annotate_nhoods/index.rst 15 | test_count_nhoods/index.rst 16 | test_io/index.rst 17 | test_make_nhoods/index.rst 18 | test_plot/index.rst 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/tests/test_DA_nhoods/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.tests.test_DA_nhoods` 2 | ===================================== 3 | 4 | .. py:module:: milopy.tests.test_DA_nhoods 5 | 6 | 7 | Module Contents 8 | --------------- 9 | 10 | 11 | Functions 12 | ~~~~~~~~~ 13 | 14 | .. autoapisummary:: 15 | 16 | milopy.tests.test_DA_nhoods.anndata 17 | milopy.tests.test_DA_nhoods.test_missing_covariate 18 | milopy.tests.test_DA_nhoods.test_non_unique_covariate 19 | milopy.tests.test_DA_nhoods.test_pvalues 20 | milopy.tests.test_DA_nhoods.test_fdr 21 | 22 | 23 | 24 | .. py:function:: anndata(seed=42) 25 | 26 | 27 | .. py:function:: test_missing_covariate(anndata) 28 | 29 | 30 | .. py:function:: test_non_unique_covariate(anndata) 31 | 32 | 33 | .. py:function:: test_pvalues(anndata) 34 | 35 | 36 | .. py:function:: test_fdr(anndata) 37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/tests/test_annotate_nhoods/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.tests.test_annotate_nhoods` 2 | =========================================== 3 | 4 | .. py:module:: milopy.tests.test_annotate_nhoods 5 | 6 | 7 | Module Contents 8 | --------------- 9 | 10 | 11 | Functions 12 | ~~~~~~~~~ 13 | 14 | .. autoapisummary:: 15 | 16 | milopy.tests.test_annotate_nhoods.adata 17 | milopy.tests.test_annotate_nhoods.prep_nhood_matrix 18 | milopy.tests.test_annotate_nhoods.test_nhood_mean_range 19 | milopy.tests.test_annotate_nhoods.test_correct_mean 20 | milopy.tests.test_annotate_nhoods.test_nhood_annotation_frac_range 21 | milopy.tests.test_annotate_nhoods.test_nhood_annotation_cont_gives_error 22 | 23 | 24 | 25 | .. py:function:: adata(seed=42) 26 | 27 | 28 | .. py:function:: prep_nhood_matrix(seed) 29 | 30 | 31 | .. py:function:: test_nhood_mean_range(adata) 32 | 33 | 34 | .. py:function:: test_correct_mean(adata) 35 | 36 | 37 | .. py:function:: test_nhood_annotation_frac_range(adata) 38 | 39 | 40 | .. py:function:: test_nhood_annotation_cont_gives_error(adata) 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/tests/test_count_nhoods/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.tests.test_count_nhoods` 2 | ======================================== 3 | 4 | .. py:module:: milopy.tests.test_count_nhoods 5 | 6 | 7 | Module Contents 8 | --------------- 9 | 10 | 11 | Functions 12 | ~~~~~~~~~ 13 | 14 | .. autoapisummary:: 15 | 16 | milopy.tests.test_count_nhoods.test_sample_values 17 | milopy.tests.test_count_nhoods.test_sample_order 18 | 19 | 20 | 21 | Attributes 22 | ~~~~~~~~~~ 23 | 24 | .. autoapisummary:: 25 | 26 | milopy.tests.test_count_nhoods.adata 27 | 28 | 29 | .. py:data:: adata 30 | 31 | 32 | 33 | 34 | .. py:function:: test_sample_values() 35 | 36 | 37 | .. py:function:: test_sample_order() 38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/tests/test_io/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.tests.test_io` 2 | ============================== 3 | 4 | .. py:module:: milopy.tests.test_io 5 | 6 | 7 | Module Contents 8 | --------------- 9 | 10 | 11 | Functions 12 | ~~~~~~~~~ 13 | 14 | .. autoapisummary:: 15 | 16 | milopy.tests.test_io.anndata 17 | milopy.tests.test_io.test_raise_error 18 | 19 | 20 | 21 | .. py:function:: anndata(seed=42) 22 | 23 | 24 | .. py:function:: test_raise_error(anndata) 25 | 26 | 27 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/tests/test_make_nhoods/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.tests.test_make_nhoods` 2 | ======================================= 3 | 4 | .. py:module:: milopy.tests.test_make_nhoods 5 | 6 | 7 | Module Contents 8 | --------------- 9 | 10 | 11 | Functions 12 | ~~~~~~~~~ 13 | 14 | .. autoapisummary:: 15 | 16 | milopy.tests.test_make_nhoods.test_number_of_nhoods 17 | milopy.tests.test_make_nhoods.test_nhood_sizes 18 | milopy.tests.test_make_nhoods.test_neighbors_key 19 | 20 | 21 | 22 | Attributes 23 | ~~~~~~~~~~ 24 | 25 | .. autoapisummary:: 26 | 27 | milopy.tests.test_make_nhoods.adata_example 28 | 29 | 30 | .. py:data:: adata_example 31 | 32 | 33 | 34 | 35 | .. py:function:: test_number_of_nhoods() 36 | 37 | 38 | .. py:function:: test_nhood_sizes() 39 | 40 | 41 | .. py:function:: test_neighbors_key() 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/tests/test_plot/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.tests.test_plot` 2 | ================================ 3 | 4 | .. py:module:: milopy.tests.test_plot 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/utils/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.utils` 2 | ====================== 3 | 4 | .. py:module:: milopy.utils 5 | 6 | 7 | Module Contents 8 | --------------- 9 | 10 | 11 | Functions 12 | ~~~~~~~~~ 13 | 14 | .. autoapisummary:: 15 | 16 | milopy.utils.add_nhood_expression 17 | milopy.utils.build_nhood_graph 18 | milopy.utils.add_covariate_to_nhoods_var 19 | milopy.utils.annotate_nhoods 20 | milopy.utils.annotate_nhoods_continuous 21 | milopy.utils.write_milo_adata 22 | milopy.utils.read_milo_adata 23 | 24 | 25 | 26 | .. py:function:: add_nhood_expression(adata: anndata.AnnData, layer: str = None) 27 | 28 | Calculates the mean expression in neighbourhoods of each feature in `adata.X` or 29 | `adata.layers[layer]` (if layer is not None). 30 | 31 | Params: 32 | ------- 33 | - adata: AnnData object 34 | - layer: which data layer to use as expression matrix (default: None, uses `adata.X`) 35 | 36 | Returns: 37 | ------- 38 | Updates adata in place to store the matrix of average expression in each neighbourhood in `adata.uns["nhood_adata"].obsm['expr']` 39 | 40 | 41 | .. py:function:: build_nhood_graph(adata: anndata.AnnData, basis: str = 'X_umap') 42 | 43 | Build graph of neighbourhoods used for visualization of DA results 44 | 45 | Params: 46 | ------- 47 | - adata: AnnData object 48 | - basis: string indicating the name of the obsm basis to use to use for layout of neighbourhoods (key in `adata.obsm`) 49 | 50 | 51 | .. py:function:: add_covariate_to_nhoods_var(adata: anndata.AnnData, new_covariates: List[str]) 52 | 53 | Add covariate from adata.obs to adata.uns["nhood_adata"].var 54 | 55 | 56 | .. py:function:: annotate_nhoods(adata: anndata.AnnData, anno_col: str) 57 | 58 | Assigns a categorical label to neighbourhoods, based on the most frequent label 59 | among cells in each neighbourhood. This can be useful to stratify DA testing 60 | results by cell types or samples. 61 | 62 | Params: 63 | ------- 64 | - adata: AnnData object with adata.uns["nhood_adata"] 65 | - anno_col: string indicating column in adata.obs containing the cell annotations to use for nhood labelling 66 | 67 | Returns: 68 | -------- 69 | None. Adds in place: 70 | - `adata.uns["nhood_adata"].obs["nhood_annotation"]`: assigning a label to each nhood 71 | - `adata.uns["nhood_adata"].obs["nhood_annotation_frac"]` stores the fraciton of cells in the neighbourhood with the assigned label 72 | - `adata.uns["nhood_adata"].obsm['frac_annotation']`: stores the fraction of cells from each label in each nhood 73 | - `adata.uns["nhood_adata"].uns["annotation_labels"]`: stores the column names for `adata.uns["nhood_adata"].obsm['frac_annotation']` 74 | 75 | 76 | .. py:function:: annotate_nhoods_continuous(adata: anndata.AnnData, anno_col: str) 77 | 78 | Assigns a continuous value to neighbourhoods, based on mean cell level covariate stored in adata.obs. 79 | This can be useful to correlate DA log-foldChanges with continuous covariates such as pseudotime, gene expression scores etc... 80 | 81 | Params: 82 | ------- 83 | - adata: AnnData object with adata.uns["nhood_adata"] 84 | - anno_col: string indicating column in adata.obs containing the cell annotations to use for nhood labelling 85 | 86 | Returns: 87 | -------- 88 | None. Adds in place: 89 | - `adata.uns["nhood_adata"].obs["nhood_{anno_col}"]`: assigning a continuous value to each nhood 90 | 91 | 92 | .. py:function:: write_milo_adata(adata: anndata.AnnData, filepath: str, **kwargs) 93 | 94 | Save anndata objects after Milo analysis 95 | 96 | Params: 97 | ----- 98 | - adata: AnnData object with adata.uns["nhood_adata"] 99 | - filepath: path to h5ad file to save 100 | - **kwargs: arguments passed to scanpy.write_h5ad 101 | 102 | Returns: 103 | ------- 104 | None, saves 2 AnnData objects in h5ad format. The cell x gene AnnData is saved in filepath. 105 | The nhood x sample AnnData is saved in a separate object (location is stored in adata.uns['nhood_adata_filepath']) 106 | 107 | 108 | .. py:function:: read_milo_adata(filepath: str, **kwargs) -> anndata.AnnData 109 | 110 | Read AnnData objects stored after Milo analysis 111 | 112 | Params: 113 | ------ 114 | - filepath: path to h5ad file storing cell x gene AnnData object 115 | - **kwargs: additional arguments passed to scanpy.read_h5ad 116 | 117 | Returns: 118 | ------- 119 | - AnnData object storing milo slots (adata.obsm['nhoods'], adata.uns['nhood_adata']) 120 | 121 | 122 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/milopy/version/index.rst.txt: -------------------------------------------------------------------------------- 1 | :py:mod:`milopy.version` 2 | ======================== 3 | 4 | .. py:module:: milopy.version 5 | 6 | 7 | Module Contents 8 | --------------- 9 | 10 | .. py:data:: __version__ 11 | :annotation: = 0.0.999 12 | 13 | 14 | 15 | .. py:data:: __author__ 16 | :annotation: = Emma Dann 17 | 18 | 19 | 20 | .. py:data:: __author_email__ 21 | :annotation: = ed6@sanger.ac.uk 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/_build/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | Welcome to milopy's documentation! 2 | ================================= 3 | .. toctree:: 4 | :maxdepth: 4 5 | :caption: Contents: 6 | 7 | readme 8 | autoapi/index 9 | milopy_example 10 | -------------------------------------------------------------------------------- /docs/_build/api.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | API — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
34 | 56 | 57 |
61 | 62 |
63 |
64 |
65 | 72 |
73 |
74 |
75 |
76 | 77 |
78 |

API

79 |

Import milopy as:

80 |
import milopy
 81 | 
82 |
83 |
84 |

Core functions: core

85 |

Core functions for differential abundance testing

86 |
87 |

core:

88 | 97 |
98 |
99 |
100 |

Plotting functions: plot

101 |
102 |

plot:

103 | 112 |
113 |
114 |
115 |

Utility functions: utils

116 |
117 |

utils:

118 | 127 |
128 |
129 |
130 | 131 | 132 |
133 |
134 |
135 | 136 |
137 | 138 |
139 |

© Copyright 2022, Emma Dann.

140 |
141 | 142 | Built with Sphinx using a 143 | theme 144 | provided by Read the Docs. 145 | 146 | 147 |
148 |
149 |
150 |
151 |
152 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /docs/_build/autoapi/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | API Reference — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 61 | 62 |
66 | 67 |
68 |
69 |
70 | 77 |
78 |
79 |
80 |
81 | 82 |
83 |

API Reference

84 |

This page contains auto-generated API reference documentation 1.

85 | 105 |
106 |
1
107 |

Created with sphinx-autoapi

108 |
109 |
110 |
111 | 112 | 113 |
114 |
115 |
119 | 120 |
121 | 122 |
123 |

© Copyright 2022, Emma Dann.

124 |
125 | 126 | Built with Sphinx using a 127 | theme 128 | provided by Read the Docs. 129 | 130 | 131 |
132 |
133 |
134 |
135 |
136 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /docs/_build/autoapi/milopy/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | milopy — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 78 | 79 |
83 | 84 |
85 |
86 |
87 | 95 |
96 |
97 |
98 |
99 | 100 |
101 |

milopy

102 |
103 |

Subpackages

104 | 117 |
118 |
119 |

Submodules

120 |
121 | 127 |
128 |
129 |
130 |

Package Contents

131 |
132 |
133 | milopy.__version__ = 0.0.999
134 |
135 | 136 |
137 |
138 | 139 | 140 |
141 |
142 |
146 | 147 |
148 | 149 |
150 |

© Copyright 2022, Emma Dann.

151 |
152 | 153 | Built with Sphinx using a 154 | theme 155 | provided by Read the Docs. 156 | 157 | 158 |
159 |
160 |
161 |
162 |
163 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /docs/_build/autoapi/milopy/tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | milopy.tests — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 69 | 70 |
74 | 75 |
76 |
77 |
78 | 87 |
88 |
89 |
90 |
91 | 92 |
93 |

milopy.tests

94 |
95 |

Submodules

96 | 106 |
107 |
108 | 109 | 110 |
111 |
112 |
116 | 117 |
118 | 119 |
120 |

© Copyright 2022, Emma Dann.

121 |
122 | 123 | Built with Sphinx using a 124 | theme 125 | provided by Read the Docs. 126 | 127 | 128 |
129 |
130 |
131 |
132 |
133 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /docs/_build/autoapi/milopy/tests/test_DA_nhoods/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | milopy.tests.test_DA_nhoods — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 69 | 70 |
74 | 75 |
76 |
77 |
78 | 88 |
89 |
90 |
91 |
92 | 93 |
94 |

milopy.tests.test_DA_nhoods

95 |
96 |

Module Contents

97 |
98 |

Functions

99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |

anndata([seed])

test_missing_covariate(anndata)

test_non_unique_covariate(anndata)

test_pvalues(anndata)

test_fdr(anndata)

122 |
123 |
124 | milopy.tests.test_DA_nhoods.anndata(seed=42)
125 |
126 | 127 |
128 |
129 | milopy.tests.test_DA_nhoods.test_missing_covariate(anndata)
130 |
131 | 132 |
133 |
134 | milopy.tests.test_DA_nhoods.test_non_unique_covariate(anndata)
135 |
136 | 137 |
138 |
139 | milopy.tests.test_DA_nhoods.test_pvalues(anndata)
140 |
141 | 142 |
143 |
144 | milopy.tests.test_DA_nhoods.test_fdr(anndata)
145 |
146 | 147 |
148 |
149 |
150 | 151 | 152 |
153 |
154 |
158 | 159 |
160 | 161 |
162 |

© Copyright 2022, Emma Dann.

163 |
164 | 165 | Built with Sphinx using a 166 | theme 167 | provided by Read the Docs. 168 | 169 | 170 |
171 |
172 |
173 |
174 |
175 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /docs/_build/autoapi/milopy/tests/test_count_nhoods/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | milopy.tests.test_count_nhoods — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 69 | 70 |
74 | 75 |
76 |
77 |
78 | 88 |
89 |
90 |
91 |
92 | 93 |
94 |

milopy.tests.test_count_nhoods

95 |
96 |

Module Contents

97 |
98 |

Functions

99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |

test_sample_values()

test_sample_order()

113 |
114 |
115 |

Attributes

116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 |

adata

127 |
128 |
129 | milopy.tests.test_count_nhoods.adata
130 |
131 | 132 |
133 |
134 | milopy.tests.test_count_nhoods.test_sample_values()
135 |
136 | 137 |
138 |
139 | milopy.tests.test_count_nhoods.test_sample_order()
140 |
141 | 142 |
143 |
144 |
145 | 146 | 147 |
148 |
149 |
153 | 154 |
155 | 156 |
157 |

© Copyright 2022, Emma Dann.

158 |
159 | 160 | Built with Sphinx using a 161 | theme 162 | provided by Read the Docs. 163 | 164 | 165 |
166 |
167 |
168 |
169 |
170 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /docs/_build/autoapi/milopy/tests/test_io/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | milopy.tests.test_io — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 69 | 70 |
74 | 75 |
76 |
77 |
78 | 88 |
89 |
90 |
91 |
92 | 93 |
94 |

milopy.tests.test_io

95 |
96 |

Module Contents

97 |
98 |

Functions

99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |

anndata([seed])

test_raise_error(anndata)

113 |
114 |
115 | milopy.tests.test_io.anndata(seed=42)
116 |
117 | 118 |
119 |
120 | milopy.tests.test_io.test_raise_error(anndata)
121 |
122 | 123 |
124 |
125 |
126 | 127 | 128 |
129 |
130 |
134 | 135 |
136 | 137 |
138 |

© Copyright 2022, Emma Dann.

139 |
140 | 141 | Built with Sphinx using a 142 | theme 143 | provided by Read the Docs. 144 | 145 | 146 |
147 |
148 |
149 |
150 |
151 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /docs/_build/autoapi/milopy/tests/test_make_nhoods/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | milopy.tests.test_make_nhoods — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 69 | 70 |
74 | 75 |
76 |
77 |
78 | 88 |
89 |
90 |
91 |
92 | 93 |
94 |

milopy.tests.test_make_nhoods

95 |
96 |

Module Contents

97 |
98 |

Functions

99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 |

test_number_of_nhoods()

test_nhood_sizes()

test_neighbors_key()

116 |
117 |
118 |

Attributes

119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |

adata_example

130 |
131 |
132 | milopy.tests.test_make_nhoods.adata_example
133 |
134 | 135 |
136 |
137 | milopy.tests.test_make_nhoods.test_number_of_nhoods()
138 |
139 | 140 |
141 |
142 | milopy.tests.test_make_nhoods.test_nhood_sizes()
143 |
144 | 145 |
146 |
147 | milopy.tests.test_make_nhoods.test_neighbors_key()
148 |
149 | 150 |
151 |
152 |
153 | 154 | 155 |
156 |
157 |
161 | 162 |
163 | 164 |
165 |

© Copyright 2022, Emma Dann.

166 |
167 | 168 | Built with Sphinx using a 169 | theme 170 | provided by Read the Docs. 171 | 172 | 173 |
174 |
175 |
176 |
177 |
178 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /docs/_build/autoapi/milopy/tests/test_plot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | milopy.tests.test_plot — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 69 | 70 |
74 | 75 |
76 |
77 |
78 | 88 |
89 |
90 |
91 |
92 | 93 |
94 |

milopy.tests.test_plot

95 |
96 | 97 | 98 |
99 |
100 |
104 | 105 |
106 | 107 |
108 |

© Copyright 2022, Emma Dann.

109 |
110 | 111 | Built with Sphinx using a 112 | theme 113 | provided by Read the Docs. 114 | 115 | 116 |
117 |
118 |
119 |
120 |
121 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /docs/_build/autoapi/milopy/version/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | milopy.version — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 72 | 73 |
77 | 78 |
79 |
80 |
81 | 90 |
91 |
92 |
93 |
94 | 95 |
96 |

milopy.version

97 |
98 |

Module Contents

99 |
100 |
101 | milopy.version.__version__ = 0.0.999
102 |
103 | 104 |
105 |
106 | milopy.version.__author__ = Emma Dann
107 |
108 | 109 |
110 |
111 | milopy.version.__author_email__ = ed6@sanger.ac.uk
112 |
113 | 114 |
115 |
116 | 117 | 118 |
119 |
120 |
124 | 125 |
126 | 127 |
128 |

© Copyright 2022, Emma Dann.

129 |
130 | 131 | Built with Sphinx using a 132 | theme 133 | provided by Read the Docs. 134 | 135 | 136 |
137 |
138 |
139 |
140 |
141 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /docs/_build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/_build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/doctrees/index.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: 3ad72bd8b7cd9c1e17e61858fe9126c1 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | Index 2 | ----------- 3 | 4 | .. include:: ./index.md -------------------------------------------------------------------------------- /docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js: -------------------------------------------------------------------------------- 1 | /* 2 | * _sphinx_javascript_frameworks_compat.js 3 | * ~~~~~~~~~~ 4 | * 5 | * Compatability shim for jQuery and underscores.js. 6 | * 7 | * WILL BE REMOVED IN Sphinx 6.0 8 | * xref RemovedInSphinx60Warning 9 | * 10 | */ 11 | 12 | /** 13 | * select a different prefix for underscore 14 | */ 15 | $u = _.noConflict(); 16 | 17 | 18 | /** 19 | * small helper function to urldecode strings 20 | * 21 | * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL 22 | */ 23 | jQuery.urldecode = function(x) { 24 | if (!x) { 25 | return x 26 | } 27 | return decodeURIComponent(x.replace(/\+/g, ' ')); 28 | }; 29 | 30 | /** 31 | * small helper function to urlencode strings 32 | */ 33 | jQuery.urlencode = encodeURIComponent; 34 | 35 | /** 36 | * This function returns the parsed url parameters of the 37 | * current request. Multiple values per key are supported, 38 | * it will always return arrays of strings for the value parts. 39 | */ 40 | jQuery.getQueryParameters = function(s) { 41 | if (typeof s === 'undefined') 42 | s = document.location.search; 43 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 44 | var result = {}; 45 | for (var i = 0; i < parts.length; i++) { 46 | var tmp = parts[i].split('=', 2); 47 | var key = jQuery.urldecode(tmp[0]); 48 | var value = jQuery.urldecode(tmp[1]); 49 | if (key in result) 50 | result[key].push(value); 51 | else 52 | result[key] = [value]; 53 | } 54 | return result; 55 | }; 56 | 57 | /** 58 | * highlight a given string on a jquery object by wrapping it in 59 | * span elements with the given class name. 60 | */ 61 | jQuery.fn.highlightText = function(text, className) { 62 | function highlight(node, addItems) { 63 | if (node.nodeType === 3) { 64 | var val = node.nodeValue; 65 | var pos = val.toLowerCase().indexOf(text); 66 | if (pos >= 0 && 67 | !jQuery(node.parentNode).hasClass(className) && 68 | !jQuery(node.parentNode).hasClass("nohighlight")) { 69 | var span; 70 | var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); 71 | if (isInSVG) { 72 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); 73 | } else { 74 | span = document.createElement("span"); 75 | span.className = className; 76 | } 77 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 78 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 79 | document.createTextNode(val.substr(pos + text.length)), 80 | node.nextSibling)); 81 | node.nodeValue = val.substr(0, pos); 82 | if (isInSVG) { 83 | var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); 84 | var bbox = node.parentElement.getBBox(); 85 | rect.x.baseVal.value = bbox.x; 86 | rect.y.baseVal.value = bbox.y; 87 | rect.width.baseVal.value = bbox.width; 88 | rect.height.baseVal.value = bbox.height; 89 | rect.setAttribute('class', className); 90 | addItems.push({ 91 | "parent": node.parentNode, 92 | "target": rect}); 93 | } 94 | } 95 | } 96 | else if (!jQuery(node).is("button, select, textarea")) { 97 | jQuery.each(node.childNodes, function() { 98 | highlight(this, addItems); 99 | }); 100 | } 101 | } 102 | var addItems = []; 103 | var result = this.each(function() { 104 | highlight(this, addItems); 105 | }); 106 | for (var i = 0; i < addItems.length; ++i) { 107 | jQuery(addItems[i].parent).before(addItems[i].target); 108 | } 109 | return result; 110 | }; 111 | 112 | /* 113 | * backward compatibility for jQuery.browser 114 | * This will be supported until firefox bug is fixed. 115 | */ 116 | if (!jQuery.browser) { 117 | jQuery.uaMatch = function(ua) { 118 | ua = ua.toLowerCase(); 119 | 120 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 121 | /(webkit)[ \/]([\w.]+)/.exec(ua) || 122 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 123 | /(msie) ([\w.]+)/.exec(ua) || 124 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || 125 | []; 126 | 127 | return { 128 | browser: match[ 1 ] || "", 129 | version: match[ 2 ] || "0" 130 | }; 131 | }; 132 | jQuery.browser = {}; 133 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; 134 | } 135 | -------------------------------------------------------------------------------- /docs/_build/html/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* This file intentionally left blank. */ 2 | -------------------------------------------------------------------------------- /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-2022 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | "use strict"; 12 | 13 | const _ready = (callback) => { 14 | if (document.readyState !== "loading") { 15 | callback(); 16 | } else { 17 | document.addEventListener("DOMContentLoaded", callback); 18 | } 19 | }; 20 | 21 | /** 22 | * highlight a given string on a node by wrapping it in 23 | * span elements with the given class name. 24 | */ 25 | const _highlight = (node, addItems, text, className) => { 26 | if (node.nodeType === Node.TEXT_NODE) { 27 | const val = node.nodeValue; 28 | const parent = node.parentNode; 29 | const pos = val.toLowerCase().indexOf(text); 30 | if ( 31 | pos >= 0 && 32 | !parent.classList.contains(className) && 33 | !parent.classList.contains("nohighlight") 34 | ) { 35 | let span; 36 | 37 | const closestNode = parent.closest("body, svg, foreignObject"); 38 | const isInSVG = closestNode && closestNode.matches("svg"); 39 | if (isInSVG) { 40 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); 41 | } else { 42 | span = document.createElement("span"); 43 | span.classList.add(className); 44 | } 45 | 46 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 47 | parent.insertBefore( 48 | span, 49 | parent.insertBefore( 50 | document.createTextNode(val.substr(pos + text.length)), 51 | node.nextSibling 52 | ) 53 | ); 54 | node.nodeValue = val.substr(0, pos); 55 | 56 | if (isInSVG) { 57 | const rect = document.createElementNS( 58 | "http://www.w3.org/2000/svg", 59 | "rect" 60 | ); 61 | const bbox = parent.getBBox(); 62 | rect.x.baseVal.value = bbox.x; 63 | rect.y.baseVal.value = bbox.y; 64 | rect.width.baseVal.value = bbox.width; 65 | rect.height.baseVal.value = bbox.height; 66 | rect.setAttribute("class", className); 67 | addItems.push({ parent: parent, target: rect }); 68 | } 69 | } 70 | } else if (node.matches && !node.matches("button, select, textarea")) { 71 | node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); 72 | } 73 | }; 74 | const _highlightText = (thisNode, text, className) => { 75 | let addItems = []; 76 | _highlight(thisNode, addItems, text, className); 77 | addItems.forEach((obj) => 78 | obj.parent.insertAdjacentElement("beforebegin", obj.target) 79 | ); 80 | }; 81 | 82 | /** 83 | * Small JavaScript module for the documentation. 84 | */ 85 | const Documentation = { 86 | init: () => { 87 | Documentation.highlightSearchWords(); 88 | Documentation.initDomainIndexTable(); 89 | Documentation.initOnKeyListeners(); 90 | }, 91 | 92 | /** 93 | * i18n support 94 | */ 95 | TRANSLATIONS: {}, 96 | PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), 97 | LOCALE: "unknown", 98 | 99 | // gettext and ngettext don't access this so that the functions 100 | // can safely bound to a different name (_ = Documentation.gettext) 101 | gettext: (string) => { 102 | const translated = Documentation.TRANSLATIONS[string]; 103 | switch (typeof translated) { 104 | case "undefined": 105 | return string; // no translation 106 | case "string": 107 | return translated; // translation exists 108 | default: 109 | return translated[0]; // (singular, plural) translation tuple exists 110 | } 111 | }, 112 | 113 | ngettext: (singular, plural, n) => { 114 | const translated = Documentation.TRANSLATIONS[singular]; 115 | if (typeof translated !== "undefined") 116 | return translated[Documentation.PLURAL_EXPR(n)]; 117 | return n === 1 ? singular : plural; 118 | }, 119 | 120 | addTranslations: (catalog) => { 121 | Object.assign(Documentation.TRANSLATIONS, catalog.messages); 122 | Documentation.PLURAL_EXPR = new Function( 123 | "n", 124 | `return (${catalog.plural_expr})` 125 | ); 126 | Documentation.LOCALE = catalog.locale; 127 | }, 128 | 129 | /** 130 | * highlight the search words provided in the url in the text 131 | */ 132 | highlightSearchWords: () => { 133 | const highlight = 134 | new URLSearchParams(window.location.search).get("highlight") || ""; 135 | const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); 136 | if (terms.length === 0) return; // nothing to do 137 | 138 | // There should never be more than one element matching "div.body" 139 | const divBody = document.querySelectorAll("div.body"); 140 | const body = divBody.length ? divBody[0] : document.querySelector("body"); 141 | window.setTimeout(() => { 142 | terms.forEach((term) => _highlightText(body, term, "highlighted")); 143 | }, 10); 144 | 145 | const searchBox = document.getElementById("searchbox"); 146 | if (searchBox === null) return; 147 | searchBox.appendChild( 148 | document 149 | .createRange() 150 | .createContextualFragment( 151 | '" 155 | ) 156 | ); 157 | }, 158 | 159 | /** 160 | * helper function to hide the search marks again 161 | */ 162 | hideSearchWords: () => { 163 | document 164 | .querySelectorAll("#searchbox .highlight-link") 165 | .forEach((el) => el.remove()); 166 | document 167 | .querySelectorAll("span.highlighted") 168 | .forEach((el) => el.classList.remove("highlighted")); 169 | const url = new URL(window.location); 170 | url.searchParams.delete("highlight"); 171 | window.history.replaceState({}, "", url); 172 | }, 173 | 174 | /** 175 | * helper function to focus on search bar 176 | */ 177 | focusSearchBar: () => { 178 | document.querySelectorAll("input[name=q]")[0]?.focus(); 179 | }, 180 | 181 | /** 182 | * Initialise the domain index toggle buttons 183 | */ 184 | initDomainIndexTable: () => { 185 | const toggler = (el) => { 186 | const idNumber = el.id.substr(7); 187 | const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); 188 | if (el.src.substr(-9) === "minus.png") { 189 | el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; 190 | toggledRows.forEach((el) => (el.style.display = "none")); 191 | } else { 192 | el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; 193 | toggledRows.forEach((el) => (el.style.display = "")); 194 | } 195 | }; 196 | 197 | const togglerElements = document.querySelectorAll("img.toggler"); 198 | togglerElements.forEach((el) => 199 | el.addEventListener("click", (event) => toggler(event.currentTarget)) 200 | ); 201 | togglerElements.forEach((el) => (el.style.display = "")); 202 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); 203 | }, 204 | 205 | initOnKeyListeners: () => { 206 | // only install a listener if it is really needed 207 | if ( 208 | !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && 209 | !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS 210 | ) 211 | return; 212 | 213 | const blacklistedElements = new Set([ 214 | "TEXTAREA", 215 | "INPUT", 216 | "SELECT", 217 | "BUTTON", 218 | ]); 219 | document.addEventListener("keydown", (event) => { 220 | if (blacklistedElements.has(document.activeElement.tagName)) return; // bail for input elements 221 | if (event.altKey || event.ctrlKey || event.metaKey) return; // bail with special keys 222 | 223 | if (!event.shiftKey) { 224 | switch (event.key) { 225 | case "ArrowLeft": 226 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 227 | 228 | const prevLink = document.querySelector('link[rel="prev"]'); 229 | if (prevLink && prevLink.href) { 230 | window.location.href = prevLink.href; 231 | event.preventDefault(); 232 | } 233 | break; 234 | case "ArrowRight": 235 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 236 | 237 | const nextLink = document.querySelector('link[rel="next"]'); 238 | if (nextLink && nextLink.href) { 239 | window.location.href = nextLink.href; 240 | event.preventDefault(); 241 | } 242 | break; 243 | case "Escape": 244 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; 245 | Documentation.hideSearchWords(); 246 | event.preventDefault(); 247 | } 248 | } 249 | 250 | // some keyboard layouts may need Shift to get / 251 | switch (event.key) { 252 | case "/": 253 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; 254 | Documentation.focusSearchBar(); 255 | event.preventDefault(); 256 | } 257 | }); 258 | }, 259 | }; 260 | 261 | // quick alias for translations 262 | const _ = Documentation.gettext; 263 | 264 | _ready(Documentation.init); 265 | -------------------------------------------------------------------------------- /docs/_build/html/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | var DOCUMENTATION_OPTIONS = { 2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), 3 | VERSION: '0.0.999', 4 | LANGUAGE: 'en', 5 | COLLAPSE_INDEX: false, 6 | BUILDER: 'html', 7 | FILE_SUFFIX: '.html', 8 | LINK_SUFFIX: '.html', 9 | HAS_SOURCE: true, 10 | SOURCELINK_SUFFIX: '.txt', 11 | NAVIGATION_WITH_KEYS: false, 12 | SHOW_SEARCH_SUMMARY: true, 13 | ENABLE_SEARCH_SHORTCUTS: true, 14 | }; -------------------------------------------------------------------------------- /docs/_build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/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-2022 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, is 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/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/html/_static/minus.png -------------------------------------------------------------------------------- /docs/_build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/html/_static/plus.png -------------------------------------------------------------------------------- /docs/_build/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | pre { line-height: 125%; } 2 | td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 3 | span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 4 | td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 5 | span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 6 | .highlight .hll { background-color: #ffffcc } 7 | .highlight { background: #f8f8f8; } 8 | .highlight .c { color: #8f5902; font-style: italic } /* Comment */ 9 | .highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ 10 | .highlight .g { color: #000000 } /* Generic */ 11 | .highlight .k { color: #004461; font-weight: bold } /* Keyword */ 12 | .highlight .l { color: #000000 } /* Literal */ 13 | .highlight .n { color: #000000 } /* Name */ 14 | .highlight .o { color: #582800 } /* Operator */ 15 | .highlight .x { color: #000000 } /* Other */ 16 | .highlight .p { color: #000000; font-weight: bold } /* Punctuation */ 17 | .highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ 18 | .highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ 19 | .highlight .cp { color: #8f5902 } /* Comment.Preproc */ 20 | .highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ 21 | .highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ 22 | .highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ 23 | .highlight .gd { color: #a40000 } /* Generic.Deleted */ 24 | .highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ 25 | .highlight .gr { color: #ef2929 } /* Generic.Error */ 26 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 27 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 28 | .highlight .go { color: #888888 } /* Generic.Output */ 29 | .highlight .gp { color: #745334 } /* Generic.Prompt */ 30 | .highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ 31 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 32 | .highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ 33 | .highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ 34 | .highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ 35 | .highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ 36 | .highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ 37 | .highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ 38 | .highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ 39 | .highlight .ld { color: #000000 } /* Literal.Date */ 40 | .highlight .m { color: #990000 } /* Literal.Number */ 41 | .highlight .s { color: #4e9a06 } /* Literal.String */ 42 | .highlight .na { color: #c4a000 } /* Name.Attribute */ 43 | .highlight .nb { color: #004461 } /* Name.Builtin */ 44 | .highlight .nc { color: #000000 } /* Name.Class */ 45 | .highlight .no { color: #000000 } /* Name.Constant */ 46 | .highlight .nd { color: #888888 } /* Name.Decorator */ 47 | .highlight .ni { color: #ce5c00 } /* Name.Entity */ 48 | .highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ 49 | .highlight .nf { color: #000000 } /* Name.Function */ 50 | .highlight .nl { color: #f57900 } /* Name.Label */ 51 | .highlight .nn { color: #000000 } /* Name.Namespace */ 52 | .highlight .nx { color: #000000 } /* Name.Other */ 53 | .highlight .py { color: #000000 } /* Name.Property */ 54 | .highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ 55 | .highlight .nv { color: #000000 } /* Name.Variable */ 56 | .highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ 57 | .highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */ 58 | .highlight .mb { color: #990000 } /* Literal.Number.Bin */ 59 | .highlight .mf { color: #990000 } /* Literal.Number.Float */ 60 | .highlight .mh { color: #990000 } /* Literal.Number.Hex */ 61 | .highlight .mi { color: #990000 } /* Literal.Number.Integer */ 62 | .highlight .mo { color: #990000 } /* Literal.Number.Oct */ 63 | .highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ 64 | .highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ 65 | .highlight .sc { color: #4e9a06 } /* Literal.String.Char */ 66 | .highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ 67 | .highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ 68 | .highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ 69 | .highlight .se { color: #4e9a06 } /* Literal.String.Escape */ 70 | .highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ 71 | .highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ 72 | .highlight .sx { color: #4e9a06 } /* Literal.String.Other */ 73 | .highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ 74 | .highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ 75 | .highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ 76 | .highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ 77 | .highlight .fm { color: #000000 } /* Name.Function.Magic */ 78 | .highlight .vc { color: #000000 } /* Name.Variable.Class */ 79 | .highlight .vg { color: #000000 } /* Name.Variable.Global */ 80 | .highlight .vi { color: #000000 } /* Name.Variable.Instance */ 81 | .highlight .vm { color: #000000 } /* Name.Variable.Magic */ 82 | .highlight .il { color: #990000 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/_build/html/genindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Index — milopy 0.0.999 documentation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
30 | 31 | 32 |
33 | 34 | 35 |

Index

36 | 37 |
38 | 39 |
40 | 41 | 42 |
43 | 44 |
45 |
46 | 86 |
87 |
88 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /docs/_build/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Index — milopy 0.0.999 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 |
31 | 32 | 33 |
34 | 35 |
36 |

Index

37 |

`{include} ../README.md 38 | `

39 |

```{toctree} 40 | :maxdepth: 1 41 | :hidden:

42 |

autoapi/index 43 | ```

44 |
45 | 46 | 47 |
48 | 49 |
50 |
51 | 91 |
92 |
93 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /docs/_build/html/milopy.rst: -------------------------------------------------------------------------------- 1 | milopy package 2 | ============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | milopy.tests 11 | 12 | Submodules 13 | ---------- 14 | 15 | milopy.core module 16 | ------------------ 17 | 18 | .. automodule:: milopy.core 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | milopy.plot module 24 | ------------------ 25 | 26 | .. automodule:: milopy.plot 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | milopy.utils module 32 | ------------------- 33 | 34 | .. automodule:: milopy.utils 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | milopy.version module 40 | --------------------- 41 | 42 | .. automodule:: milopy.version 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | Module contents 48 | --------------- 49 | 50 | .. automodule:: milopy 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | -------------------------------------------------------------------------------- /docs/_build/html/milopy.tests.rst: -------------------------------------------------------------------------------- 1 | milopy.tests package 2 | ==================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | milopy.tests.test\_DA\_nhoods module 8 | ------------------------------------ 9 | 10 | .. automodule:: milopy.tests.test_DA_nhoods 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | milopy.tests.test\_annotate\_nhoods module 16 | ------------------------------------------ 17 | 18 | .. automodule:: milopy.tests.test_annotate_nhoods 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | milopy.tests.test\_count\_nhoods module 24 | --------------------------------------- 25 | 26 | .. automodule:: milopy.tests.test_count_nhoods 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | milopy.tests.test\_io module 32 | ---------------------------- 33 | 34 | .. automodule:: milopy.tests.test_io 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | milopy.tests.test\_make\_nhoods module 40 | -------------------------------------- 41 | 42 | .. automodule:: milopy.tests.test_make_nhoods 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | milopy.tests.test\_plot module 48 | ------------------------------ 49 | 50 | .. automodule:: milopy.tests.test_plot 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | Module contents 56 | --------------- 57 | 58 | .. automodule:: milopy.tests 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | -------------------------------------------------------------------------------- /docs/_build/html/modules.rst: -------------------------------------------------------------------------------- 1 | milopy 2 | ====== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | milopy 8 | -------------------------------------------------------------------------------- /docs/_build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/_build/html/objects.inv -------------------------------------------------------------------------------- /docs/_build/html/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Search — milopy 0.0.999 documentation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
34 |
35 |
36 | 37 | 38 |
39 | 40 |

Search

41 | 42 | 50 | 51 | 52 |

53 | Searching for multiple words only shows matches that contain 54 | all words. 55 |

56 | 57 | 58 |
59 | 60 | 61 | 62 |
63 | 64 | 65 | 66 |
67 | 68 |
69 | 70 | 71 |
72 | 73 |
74 |
75 | 105 |
106 |
107 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /docs/_build/html/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({"docnames": ["index"], "filenames": ["index.rst"], "titles": ["Index"], "terms": {"includ": 0, "readm": 0, "md": 0, "toctre": 0, "maxdepth": 0, "1": 0, "hidden": 0, "autoapi": 0}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"index": 0}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 56}}) -------------------------------------------------------------------------------- /docs/_build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Welcome to milopy’s documentation! — milopy 0.0.999 documentation 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | 57 | 58 |
62 | 63 |
64 |
65 |
66 |
    67 |
  • »
  • 68 |
  • Welcome to milopy’s documentation!
  • 69 |
  • 70 | View page source 71 |
  • 72 |
73 |
74 |
75 |
76 |
77 | 78 |
79 |

Welcome to milopy’s documentation!

80 | 116 |
117 | 118 | 119 |
120 |
121 |
124 | 125 |
126 | 127 |
128 |

© Copyright 2022, Emma Dann.

129 |
130 | 131 | Built with Sphinx using a 132 | theme 133 | provided by Read the Docs. 134 | 135 | 136 |
137 |
138 |
139 |
140 |
141 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /docs/_build/reports/milopy_example.err.log: -------------------------------------------------------------------------------- 1 | Traceback (most recent call last): 2 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/nbclient/client.py", line 780, in _async_poll_for_reply 3 | msg = await ensure_async(self.kc.shell_channel.get_msg(timeout=new_timeout)) 4 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/nbclient/util.py", line 97, in ensure_async 5 | result = await obj 6 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/jupyter_client/channels.py", line 230, in get_msg 7 | raise Empty 8 | _queue.Empty 9 | 10 | During handling of the above exception, another exception occurred: 11 | 12 | Traceback (most recent call last): 13 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/jupyter_cache/executors/utils.py", line 58, in single_nb_execution 14 | executenb( 15 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/nbclient/client.py", line 1269, in execute 16 | return NotebookClient(nb=nb, resources=resources, km=km, **kwargs).execute() 17 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/nbclient/util.py", line 85, in wrapped 18 | return just_run(coro(*args, **kwargs)) 19 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/nbclient/util.py", line 60, in just_run 20 | return loop.run_until_complete(coro) 21 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete 22 | return future.result() 23 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/nbclient/client.py", line 707, in async_execute 24 | await self.async_execute_cell( 25 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/nbclient/client.py", line 1006, in async_execute_cell 26 | exec_reply = await self.task_poll_for_reply 27 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/nbclient/client.py", line 804, in _async_poll_for_reply 28 | error_on_timeout_execute_reply = await self._async_handle_timeout(timeout, cell) 29 | File "/nfs/team205/ed6/miniconda3/lib/python3.8/site-packages/nbclient/client.py", line 856, in _async_handle_timeout 30 | raise CellTimeoutError.error_from_timeout_and_cell( 31 | nbclient.exceptions.CellTimeoutError: A cell timed out while it was being executed, after 30 seconds. 32 | The message was: Cell execution timed out. 33 | Here is a preview of the cell contents: 34 | ------------------- 35 | ['import numpy as np', 'import pandas as pd', 'import scanpy as sc', 'import scvelo ## For mouse gastrulation data ', 'import anndata'] 36 | ... 37 | ["plt.rcParams['figure.figsize']=(8,8) #rescale figures", 'sc.settings.verbosity = 3', '', 'import milopy.core as milo', 'import milopy.plot as milopl'] 38 | ------------------- 39 | 40 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | API 3 | ============ 4 | 5 | Import milopy as:: 6 | 7 | import milopy 8 | 9 | 10 | Core functions: `core` 11 | -------------------------------- 12 | 13 | Core functions for differential abundance testing 14 | 15 | .. toctree:: 16 | :maxdepth: 3 17 | :caption: core: 18 | 19 | autoapi/milopy/core/index 20 | 21 | 22 | Plotting functions: `plot` 23 | -------------------------------- 24 | .. toctree:: 25 | :maxdepth: 3 26 | :caption: plot: 27 | 28 | autoapi/milopy/plot/index 29 | 30 | 31 | 32 | Utility functions: `utils` 33 | -------------------------------- 34 | .. toctree:: 35 | :maxdepth: 3 36 | :caption: utils: 37 | 38 | autoapi/milopy/utils/index 39 | 40 | -------------------------------------------------------------------------------- /docs/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 | project = 'milopy' 10 | copyright = '2022, Emma Dann' 11 | author = 'Emma Dann' 12 | release = '0.1.0' 13 | 14 | # -- General configuration --------------------------------------------------- 15 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 16 | 17 | extensions = [ 18 | "myst_nb", 19 | # "sphinx.ext.viewcode", 20 | # "sphinx.ext.autosummary", 21 | 'autoapi.extension' 22 | ] 23 | 24 | templates_path = ['_templates'] 25 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 26 | autoapi_dirs = ['../milopy'] 27 | 28 | # # Generate the API documentation when building 29 | # autosummary_generate = True 30 | # autodoc_member_order = "bysource" 31 | 32 | # -- Options for HTML output ------------------------------------------------- 33 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 34 | 35 | html_theme = "sphinx_rtd_theme" 36 | html_static_path = ['_static'] 37 | 38 | # -- Exclude tests ---- 39 | # This is the expected signature of the handler for this event, cf doc 40 | 41 | 42 | def autodoc_skip_member_handler(app, what, name, obj, skip, options): 43 | # Basic approach; you might want a regex instead 44 | return name.startswith("test_") 45 | 46 | # Automatically called by sphinx at startup 47 | 48 | 49 | def setup(app): 50 | # Connect the autodoc-skip-member event from apidoc to the callback 51 | app.connect('autodoc-skip-member', autodoc_skip_member_handler) 52 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ```{include} ../README.md 2 | ``` 3 | 4 | ```{toctree} 5 | :maxdepth: 1 6 | :hidden: 7 | 8 | autoapi/index 9 | ``` -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to milopy's documentation! 2 | ================================= 3 | .. toctree:: 4 | :maxdepth: 4 5 | :caption: Contents: 6 | 7 | readme 8 | api 9 | milopy_example 10 | -------------------------------------------------------------------------------- /docs/jupyter_execute/19cffa128bdd43873065fb687f6783d072fd13d6a46e9571e9df4e86ef7f8e01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/jupyter_execute/19cffa128bdd43873065fb687f6783d072fd13d6a46e9571e9df4e86ef7f8e01.png -------------------------------------------------------------------------------- /docs/jupyter_execute/60fe2e0e3f3b249ef5c44df2c62e4947bfa5fe5376652a22d18cd443c25bf3f2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/jupyter_execute/60fe2e0e3f3b249ef5c44df2c62e4947bfa5fe5376652a22d18cd443c25bf3f2.png -------------------------------------------------------------------------------- /docs/jupyter_execute/882e4262f5b1f970a56379ef517f24e1c50c08880d6cfd46d6d1184318fdc5f5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/jupyter_execute/882e4262f5b1f970a56379ef517f24e1c50c08880d6cfd46d6d1184318fdc5f5.png -------------------------------------------------------------------------------- /docs/jupyter_execute/8ab561250afc6b0c8550159dd96f6ac996a77a173eac1f617b88016d594433f3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/jupyter_execute/8ab561250afc6b0c8550159dd96f6ac996a77a173eac1f617b88016d594433f3.png -------------------------------------------------------------------------------- /docs/jupyter_execute/8e315beb2b1c3159b4475845d7131f21850c0afadd685ce52119278f60d61e53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/jupyter_execute/8e315beb2b1c3159b4475845d7131f21850c0afadd685ce52119278f60d61e53.png -------------------------------------------------------------------------------- /docs/jupyter_execute/9fdf0fa20b948b519daf9016a4ef15fac541369cec8ac9c2a0f9bccf45231e71.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/jupyter_execute/9fdf0fa20b948b519daf9016a4ef15fac541369cec8ac9c2a0f9bccf45231e71.png -------------------------------------------------------------------------------- /docs/jupyter_execute/fc2ef72cf4b4a63a47d0cde09b2e76b5d70c70e17e2e30e5d9149f8a766a2675.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/docs/jupyter_execute/fc2ef72cf4b4a63a47d0cde09b2e76b5d70c70e17e2e30e5d9149f8a766a2675.png -------------------------------------------------------------------------------- /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=. 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/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.md 2 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | myst_nb 2 | sphinx-rtd-theme 3 | sphinx-autoapi 4 | -------------------------------------------------------------------------------- /milopy/__init__.py: -------------------------------------------------------------------------------- 1 | from . import core 2 | from . import utils 3 | from . import plot 4 | from .version import __version__ -------------------------------------------------------------------------------- /milopy/plot.py: -------------------------------------------------------------------------------- 1 | import scanpy as sc 2 | import pandas as pd 3 | import numpy as np 4 | import anndata 5 | from typing import Union, Optional, Sequence, Any, Mapping, List, Tuple 6 | from anndata import AnnData 7 | 8 | import matplotlib.pyplot as plt 9 | import seaborn as sns 10 | 11 | 12 | def plot_nhood_graph( 13 | adata: AnnData, 14 | alpha: float = 0.1, 15 | min_logFC: float = 0, 16 | min_size: int = 10, 17 | plot_edges: bool = False, 18 | title: str = "DA log-Fold Change", 19 | **kwargs 20 | ): 21 | ''' 22 | Visualize DA results on abstracted graph (wrapper around sc.pl.embedding) 23 | 24 | Params: 25 | ------- 26 | - adata: AnnData object 27 | - alpha: significance threshold 28 | - min_logFC: minimum absolute log-Fold Change to show results (default: 0, show all significant neighbourhoods) 29 | - min_size: minimum size of nodes in visualization (default: 10) 30 | - plot_edges: boolean indicating if edges for neighbourhood overlaps whould be plotted (default: False) 31 | - title: plot title (default: 'DA log-Fold Change') 32 | - **kwargs: other arguments to pass to scanpy.pl.embedding 33 | ''' 34 | nhood_adata = adata.uns["nhood_adata"].copy() 35 | 36 | if "Nhood_size" not in nhood_adata.obs.columns: 37 | raise KeyError( 38 | 'Cannot find "Nhood_size" column in adata.uns["nhood_adata"].obs -- \ 39 | please run milopy.utils.build_nhood_graph(adata)' 40 | ) 41 | 42 | nhood_adata.obs["graph_color"] = nhood_adata.obs["logFC"] 43 | nhood_adata.obs.loc[nhood_adata.obs["SpatialFDR"] 44 | > alpha, "graph_color"] = np.nan 45 | nhood_adata.obs["abs_logFC"] = abs(nhood_adata.obs["logFC"]) 46 | nhood_adata.obs.loc[nhood_adata.obs["abs_logFC"] 47 | < min_logFC, "graph_color"] = np.nan 48 | 49 | # Plotting order - extreme logFC on top 50 | nhood_adata.obs.loc[nhood_adata.obs["graph_color"].isna(), 51 | "abs_logFC"] = np.nan 52 | ordered = nhood_adata.obs.sort_values( 53 | 'abs_logFC', na_position='first').index 54 | nhood_adata = nhood_adata[ordered] 55 | 56 | vmax = np.max([nhood_adata.obs["graph_color"].max(), 57 | abs(nhood_adata.obs["graph_color"].min())]) 58 | vmin = - vmax 59 | 60 | sc.pl.embedding(nhood_adata, "X_milo_graph", 61 | color="graph_color", cmap="RdBu_r", 62 | size=adata.uns["nhood_adata"].obs["Nhood_size"]*min_size, 63 | edges=plot_edges, neighbors_key="nhood", 64 | # edge_width = 65 | sort_order=False, 66 | frameon=False, 67 | vmax=vmax, vmin=vmin, 68 | title=title, 69 | **kwargs 70 | ) 71 | 72 | 73 | def plot_nhood(adata, ix, basis="X_umap"): 74 | ''' 75 | Visualize cells in a neighbourhood 76 | ''' 77 | adata.obs["Nhood"] = adata.obsm["nhoods"][:, ix].toarray().ravel() 78 | sc.pl.embedding(adata, basis, color="Nhood", 79 | size=30, title="Nhood" + str(ix)) 80 | 81 | # Plot nhood beeswarm 82 | 83 | 84 | def plot_DA_beeswarm( 85 | adata: AnnData, 86 | anno_col: str = 'nhood_annotation', 87 | alpha: float = 0.1, 88 | subset_nhoods: List = None 89 | ): 90 | ''' 91 | Plot beeswarm plot of logFC against nhood labels 92 | 93 | Params: 94 | ------- 95 | - adata: AnnData object 96 | - anno_col: column in adata.uns['nhood_adata'].obs to use as annotation 97 | - alpha: significance threshold 98 | - subset_nhoods: list of nhoods to plot (default: None, plot all nhoods) 99 | ''' 100 | try: 101 | nhood_adata = adata.uns["nhood_adata"].copy() 102 | except KeyError: 103 | raise KeyError( 104 | 'Cannot find "nhood_adata" slot in adata.uns -- please run milopy.make_nhoods_adata(adata)' 105 | ) 106 | 107 | if subset_nhoods is not None: 108 | nhood_adata = nhood_adata[subset_nhoods] 109 | 110 | try: 111 | nhood_adata.obs[anno_col] 112 | except KeyError: 113 | raise KeyError( 114 | 'Cannot find {a} in adata.uns["nhood_adata"].obs -- \ 115 | please run milopy.utils.annotate_nhoods(adata, anno_col) first'.format(a=anno_col) 116 | ) 117 | 118 | try: 119 | nhood_adata.obs["logFC"] 120 | except KeyError: 121 | raise KeyError( 122 | 'Cannot find `logFC` in adata.uns["nhood_adata"].obs -- \ 123 | please run milopy.core.DA_nhoods(adata) first' 124 | ) 125 | 126 | sorted_annos = nhood_adata.obs[[anno_col, "logFC"]].\ 127 | groupby(anno_col).\ 128 | median().\ 129 | sort_values("logFC", ascending=True).index 130 | 131 | anno_df = nhood_adata.obs[[anno_col, "logFC", "SpatialFDR"]].copy() 132 | anno_df['is_signif'] = anno_df['SpatialFDR'] < alpha 133 | # anno_df['across_organs'] = ["Significant across organs" if x else "" for x in (keep_nhoods & signif_nhoods)] 134 | anno_df = anno_df[anno_df[anno_col] != "nan"] 135 | 136 | try: 137 | anno_palette = _get_palette_adata( 138 | adata, nhood_adata.uns['annotation_obs']) 139 | sns.violinplot(data=anno_df, y=anno_col, x="logFC", order=sorted_annos, 140 | size=190, inner=None, orient="h", 141 | palette=anno_palette, 142 | linewidth=0, 143 | scale="width") 144 | except: 145 | sns.violinplot(data=anno_df, y=anno_col, x="logFC", order=sorted_annos, 146 | size=190, inner=None, orient="h", 147 | linewidth=0, 148 | scale="width") 149 | sns.stripplot(data=anno_df, y=anno_col, x="logFC", order=sorted_annos, size=2, 150 | hue='is_signif', palette=['grey', 'black'], 151 | orient="h", alpha=0.5) 152 | plt.legend(loc='upper left', title=f'< {int(alpha*100)}% SpatialFDR', 153 | bbox_to_anchor=(1, 1), frameon=False) 154 | plt.axvline(x=0, ymin=0, ymax=1, color="black", linestyle="--") 155 | 156 | 157 | def _get_palette_adata(adata, obs_col): 158 | return(dict(zip(adata.obs[obs_col].cat.categories, adata.uns[f'{obs_col}_colors']))) 159 | 160 | 161 | ### Plot boxplot of cell numbers for QC ### 162 | def plot_nhood_counts_by_cond( 163 | adata: AnnData, 164 | test_var: str, 165 | subset_nhoods: List = None, 166 | log_counts: bool = False): 167 | ''' 168 | Plot boxplot of cell numbers vs condition of interest 169 | 170 | Params: 171 | ------ 172 | - adata: anndata object storing neighbourhood information in adata.uns 173 | - test_var: string, name of column in adata.obs storing condition of interest (y-axis for boxplot) 174 | - subset_nhoods: list of obs_names for neighbourhoods to include in plot (default: None, plot all nhoods) 175 | - log_counts: boolean, whether to plot log1p of cell counts (default: False) 176 | ''' 177 | try: 178 | nhood_adata = adata.uns["nhood_adata"].copy() 179 | except KeyError: 180 | raise KeyError( 181 | 'Cannot find "nhood_adata" slot in adata.uns -- please run milopy.make_nhoods_adata(adata)' 182 | ) 183 | 184 | if subset_nhoods is None: 185 | subset_nhoods = nhood_adata.obs_names 186 | 187 | pl_df = pd.DataFrame(nhood_adata[subset_nhoods].X.A, columns=nhood_adata.var_names).melt( 188 | var_name=nhood_adata.uns['sample_col'], value_name='n_cells') 189 | pl_df = pd.merge(pl_df, nhood_adata.var) 190 | pl_df['log_n_cells'] = np.log1p(pl_df['n_cells']) 191 | if not log_counts: 192 | sns.boxplot(data=pl_df, x=test_var, y='n_cells', color='lightblue') 193 | sns.stripplot(data=pl_df, x=test_var, y='n_cells', color='black', s=3) 194 | plt.ylabel('# cells') 195 | else: 196 | sns.boxplot(data=pl_df, x=test_var, y='log_n_cells', color='lightblue') 197 | sns.stripplot(data=pl_df, x=test_var, 198 | y='log_n_cells', color='black', s=3) 199 | plt.ylabel('log(# cells + 1)') 200 | 201 | plt.xticks(rotation=90) 202 | plt.xlabel(test_var) 203 | -------------------------------------------------------------------------------- /milopy/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdann/milopy/30646f538481151b6101b5e2f133858d2171000a/milopy/tests/__init__.py -------------------------------------------------------------------------------- /milopy/tests/test_DA_nhoods.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import scanpy as sc 3 | import numpy as np 4 | import pandas as pd 5 | from milopy.core import make_nhoods 6 | from milopy.core import count_nhoods 7 | from milopy.core import DA_nhoods 8 | 9 | 10 | @pytest.fixture 11 | def anndata(seed=42): 12 | adata = sc.datasets.pbmc68k_reduced() 13 | make_nhoods(adata) 14 | 15 | ## Simulate experimental condition ## 16 | np.random.seed(seed) 17 | adata.obs["condition"] = np.random.choice( 18 | ["ConditionA", "ConditionB"], size=adata.n_obs, p=[0.5, 0.5]) 19 | # we simulate differential abundance in NK cells 20 | DA_cells = adata.obs["louvain"] == "1" 21 | adata.obs.loc[DA_cells, "condition"] = np.random.choice( 22 | ["ConditionA", "ConditionB"], size=sum(DA_cells), p=[0.2, 0.8]) 23 | 24 | ## Simulate replicates ## 25 | adata.obs["replicate"] = np.random.choice( 26 | ["R1", "R2", "R3"], size=adata.n_obs) 27 | adata.obs["sample"] = adata.obs["replicate"] + adata.obs["condition"] 28 | count_nhoods(adata, sample_col="sample") 29 | return adata 30 | 31 | 32 | @pytest.fixture 33 | def anndata_subsample_samples(seed=42): 34 | adata = sc.datasets.pbmc68k_reduced() 35 | sc.pp.neighbors(adata, n_neighbors=4) 36 | make_nhoods(adata) 37 | 38 | ## Simulate experimental condition ## 39 | np.random.seed(seed) 40 | adata.obs["condition"] = np.random.choice( 41 | ["ConditionA", "ConditionB"], size=adata.n_obs, p=[0.5, 0.5]) 42 | # we simulate differential abundance in NK cells 43 | DA_cells = adata.obs["louvain"] == "1" 44 | adata.obs.loc[DA_cells, "condition"] = np.random.choice( 45 | ["ConditionA", "ConditionB"], size=sum(DA_cells), p=[0.2, 0.8]) 46 | 47 | ## Simulate replicates ## 48 | adata.obs["replicate"] = np.random.choice( 49 | ["R1", "R2", "R3", 'R4', 'R5'], size=adata.n_obs) 50 | adata.obs["sample"] = adata.obs["replicate"] + adata.obs["condition"] 51 | count_nhoods(adata, sample_col="sample") 52 | return adata 53 | 54 | 55 | def test_missing_covariate(anndata): 56 | adata = anndata.copy() 57 | with pytest.raises(KeyError): 58 | DA_nhoods(adata, design="~ciaone") 59 | 60 | 61 | def test_non_unique_covariate(anndata): 62 | adata = anndata.copy() 63 | with pytest.raises(ValueError): 64 | DA_nhoods(adata, design="~phase") 65 | 66 | # Check that results make sense 67 | 68 | 69 | def test_pvalues(anndata): 70 | adata = anndata.copy() 71 | DA_nhoods(adata, design="~condition") 72 | nhood_adata = adata.uns["nhood_adata"] 73 | min_p, max_p = nhood_adata.obs["PValue"].min( 74 | ), nhood_adata.obs["PValue"].min() 75 | assert (min_p >= 0) & (max_p <= 1), "P-values are not between 0 and 1" 76 | 77 | 78 | def test_fdr(anndata): 79 | adata = anndata.copy() 80 | DA_nhoods(adata, design="~condition") 81 | nhood_adata = adata.uns["nhood_adata"] 82 | assert np.all(np.round(nhood_adata.obs["PValue"], 10) <= np.round( 83 | nhood_adata.obs["SpatialFDR"], 10)), "FDR is higher than uncorrected P-values" 84 | 85 | 86 | def test_fdr_select_samples(anndata_subsample_samples): 87 | adata = anndata_subsample_samples.copy() 88 | DA_nhoods(adata, design="~ condition", subset_samples=[ 89 | "R1ConditionA", "R1ConditionB", "R3ConditionA", "R3ConditionB"]) 90 | nhood_adata = adata.uns["nhood_adata"] 91 | np.all((np.round(nhood_adata.obs["PValue"], 10) <= np.round(nhood_adata.obs["SpatialFDR"], 10)) | ( 92 | nhood_adata.obs["SpatialFDR"].isna())), "FDR is higher than uncorrected P-values" 93 | -------------------------------------------------------------------------------- /milopy/tests/test_annotate_nhoods.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import scanpy as sc 3 | import numpy as np 4 | from milopy.core import make_nhoods, count_nhoods 5 | from milopy.utils import annotate_nhoods, annotate_nhoods_continuous 6 | 7 | 8 | @pytest.fixture 9 | def adata(seed=42): 10 | adata = prep_nhood_matrix(seed) 11 | return adata 12 | 13 | 14 | def prep_nhood_matrix(seed): 15 | adata = sc.datasets.pbmc68k_reduced() 16 | make_nhoods(adata) 17 | 18 | ## Simulate experimental condition ## 19 | np.random.seed(seed) 20 | adata.obs["condition"] = np.random.choice( 21 | ["ConditionA", "ConditionB"], size=adata.n_obs, p=[0.5, 0.5]) 22 | # we simulate differential abundance in NK cells 23 | DA_cells = adata.obs["louvain"] == "1" 24 | adata.obs.loc[DA_cells, "condition"] = np.random.choice( 25 | ["ConditionA", "ConditionB"], size=sum(DA_cells), p=[0.2, 0.8]) 26 | 27 | ## Simulate replicates ## 28 | adata.obs["replicate"] = np.random.choice( 29 | ["R1", "R2", "R3"], size=adata.n_obs) 30 | adata.obs["sample"] = adata.obs["replicate"] + adata.obs["condition"] 31 | count_nhoods(adata, sample_col='sample') 32 | return adata 33 | 34 | # --- Annotate continuous tests --- 35 | 36 | # Test that mean values are within the expected range 37 | 38 | 39 | def test_nhood_mean_range(adata): 40 | annotate_nhoods_continuous(adata, anno_col='S_score') 41 | assert adata.uns['nhood_adata'].obs['nhood_S_score'].max( 42 | ) < adata.obs['S_score'].max() 43 | assert adata.uns['nhood_adata'].obs['nhood_S_score'].min( 44 | ) > adata.obs['S_score'].min() 45 | 46 | # Test that value corresponds to mean 47 | 48 | 49 | def test_correct_mean(adata): 50 | annotate_nhoods_continuous(adata, anno_col='S_score') 51 | i = np.random.choice(np.arange(adata.uns['nhood_adata'].n_obs)) 52 | mean_val_nhood = adata.obs[adata.obsm['nhoods'] 53 | [:, i].toarray() == 1]['S_score'].mean() 54 | assert adata.uns['nhood_adata'].obs['nhood_S_score'][i] == pytest.approx( 55 | mean_val_nhood, 0.0001) 56 | 57 | 58 | # --- Annotate labels tests --- 59 | 60 | # Test that label fractions are in the correct range 61 | 62 | 63 | def test_nhood_annotation_frac_range(adata): 64 | annotate_nhoods(adata, anno_col='louvain') 65 | assert adata.uns['nhood_adata'].obs['nhood_annotation_frac'].max() <= 1.0 66 | assert adata.uns['nhood_adata'].obs['nhood_annotation_frac'].min() >= 0.0 67 | 68 | # Test continuous covariate gives error 69 | 70 | 71 | def test_nhood_annotation_cont_gives_error(adata): 72 | with pytest.raises(ValueError): 73 | annotate_nhoods(adata, anno_col='S_score') 74 | -------------------------------------------------------------------------------- /milopy/tests/test_count_nhoods.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import scanpy as sc 3 | import numpy as np 4 | import pandas as pd 5 | from milopy.core import make_nhoods 6 | from milopy.core import count_nhoods 7 | 8 | adata = sc.datasets.pbmc68k_reduced() 9 | make_nhoods(adata) 10 | 11 | def test_sample_values(): 12 | ## Extract cells of one nhood 13 | nh=1 14 | sample_col="phase" 15 | count_nhoods(adata, sample_col=sample_col) 16 | nh_cells = adata.obsm["nhoods"][:,nh].nonzero()[0] 17 | 18 | ## Value count the sample composition 19 | top_a = adata.obs.iloc[nh_cells].value_counts(sample_col).values.ravel() 20 | 21 | ## Check it matches the one calculated 22 | df = pd.DataFrame(adata.uns["nhood_adata"].X[nh,:].toarray()).T 23 | df.index = adata.uns["nhood_adata"].var_names 24 | top_b = df.sort_values(0, ascending=False).values.ravel() 25 | assert all((top_b - top_a) == 0), 'The counts for samples in adata.uns["nhood_adata"] does not match' 26 | 27 | def test_sample_order(): 28 | ## Extract cells of one nhood 29 | nh=1 30 | sample_col="phase" 31 | count_nhoods(adata, sample_col=sample_col) 32 | nh_cells = adata.obsm["nhoods"][:,nh].nonzero()[0] 33 | 34 | ## Value count the sample composition 35 | top_a = adata.obs.iloc[nh_cells].value_counts(sample_col).index[0] 36 | 37 | ## Check it matches the one calculated 38 | df = pd.DataFrame(adata.uns["nhood_adata"].X[nh,:].toarray()).T 39 | df.index = adata.uns["nhood_adata"].var_names 40 | top_b = df.sort_values(0, ascending=False).index[0] 41 | 42 | assert top_a==top_b, 'The order of samples in adata.uns["nhood_adata"] does not match' 43 | -------------------------------------------------------------------------------- /milopy/tests/test_io.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from milopy.utils import write_milo_adata 3 | import scanpy as sc 4 | import numpy as np 5 | import pandas as pd 6 | from milopy.core import make_nhoods 7 | from milopy.core import count_nhoods 8 | from milopy.utils import write_milo_adata 9 | 10 | 11 | @pytest.fixture 12 | def anndata(seed=42): 13 | adata = sc.datasets.pbmc68k_reduced() 14 | make_nhoods(adata) 15 | 16 | ## Simulate experimental condition ## 17 | np.random.seed(seed) 18 | adata.obs["condition"] = np.random.choice( 19 | ["ConditionA", "ConditionB"], size=adata.n_obs, p=[0.5, 0.5]) 20 | # we simulate differential abundance in NK cells 21 | DA_cells = adata.obs["louvain"] == "1" 22 | adata.obs.loc[DA_cells, "condition"] = np.random.choice( 23 | ["ConditionA", "ConditionB"], size=sum(DA_cells), p=[0.2, 0.8]) 24 | 25 | ## Simulate replicates ## 26 | adata.obs["replicate"] = np.random.choice( 27 | ["R1", "R2", "R3"], size=adata.n_obs) 28 | adata.obs["sample"] = adata.obs["replicate"] + adata.obs["condition"] 29 | count_nhoods(adata, sample_col="sample") 30 | return adata 31 | 32 | 33 | def test_raise_error(anndata): 34 | adata = anndata.copy() 35 | del adata.uns['nhood_adata'] 36 | with pytest.raises(KeyError): 37 | write_milo_adata(adata, filepath='data/test.h5ad') 38 | -------------------------------------------------------------------------------- /milopy/tests/test_make_nhoods.py: -------------------------------------------------------------------------------- 1 | ### TESTS ### 2 | import pytest 3 | import scanpy as sc 4 | import numpy as np 5 | from milopy.core import make_nhoods 6 | 7 | adata_example = sc.datasets.pbmc68k_reduced() 8 | 9 | # Test there are less nhoods than n_obs*prop 10 | 11 | 12 | def test_number_of_nhoods(): 13 | p = 0.1 14 | make_nhoods(adata_example, prop=p) 15 | assert adata_example.obsm["nhoods"].shape[1] <= int( 16 | np.round(adata_example.n_obs * p)) 17 | 18 | # Test that the smallest neighbourhood is bigger or equal than 19 | # the smallest number of neighbors in the KNN graph 20 | 21 | 22 | def test_nhood_sizes(): 23 | make_nhoods(adata_example) 24 | knn_graph = adata_example.obsp["connectivities"] 25 | knn_graph[knn_graph != 0] = 1 26 | assert knn_graph.sum(0).min() <= adata_example.obsm["nhoods"].sum(0).min() 27 | 28 | ## Test that the right KNN graph is used if specified ## 29 | 30 | def test_neighbors_key(): 31 | k = adata_example.uns['neighbors']['params']['n_neighbors'] 32 | test_k = 5 33 | assert test_k < k 34 | sc.pp.neighbors(adata_example, n_neighbors=test_k, key_added='test') 35 | make_nhoods(adata_example, neighbors_key='test') 36 | smallest_size = adata_example.obsm['nhoods'].toarray().sum(0).min() 37 | assert smallest_size < k 38 | assert adata_example.uns["nhood_neighbors_key"] == 'test' 39 | -------------------------------------------------------------------------------- /milopy/tests/test_plot.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import scanpy as sc 3 | import numpy as np 4 | import pandas as pd 5 | 6 | ## There should be some tests here ## 7 | -------------------------------------------------------------------------------- /milopy/utils.py: -------------------------------------------------------------------------------- 1 | import scanpy as sc 2 | import pandas as pd 3 | import numpy as np 4 | import scipy.sparse 5 | import anndata 6 | from typing import Union, Optional, Sequence, Any, Mapping, List, Tuple 7 | from anndata import AnnData 8 | from scipy.sparse import csr_matrix 9 | import random 10 | 11 | ## -- NHOOD EXPRESSION -- ## 12 | 13 | 14 | def add_nhood_expression( 15 | adata: AnnData, 16 | layer: str = None, 17 | ): 18 | ''' 19 | Calculates the mean expression in neighbourhoods of each feature in `adata.X` or 20 | `adata.layers[layer]` (if layer is not None). 21 | 22 | Params: 23 | ------- 24 | - adata: AnnData object 25 | - layer: which data layer to use as expression matrix (default: None, uses `adata.X`) 26 | 27 | Returns: 28 | ------- 29 | Updates adata in place to store the matrix of average expression in each neighbourhood in `adata.uns["nhood_adata"].obsm['expr']` 30 | ''' 31 | try: 32 | nhood_adata = adata.uns["nhood_adata"] 33 | except KeyError: 34 | raise KeyError( 35 | 'Cannot find "nhood_adata" slot in adata.uns -- please run milopy.count_nhoods(adata)' 36 | ) 37 | 38 | # Get gene expression matrix 39 | if layer is None: 40 | X = adata.X 41 | expr_id = "expr" 42 | else: 43 | X = adata.layers[layer] 44 | expr_id = "expr_" + layer 45 | 46 | # Aggregate over nhoods -- taking the mean 47 | nhoods_X = X.T.dot(adata.obsm["nhoods"]) 48 | nhoods_X = csr_matrix(nhoods_X / adata.obsm["nhoods"].toarray().sum(0)) 49 | adata.uns["nhood_adata"].obsm[expr_id] = nhoods_X.T 50 | 51 | 52 | ## -- NHOOD GRAPH -- ## 53 | 54 | def build_nhood_graph(adata: AnnData, 55 | basis: str = "X_umap"): 56 | ''' 57 | Build graph of neighbourhoods used for visualization of DA results 58 | 59 | Params: 60 | ------- 61 | - adata: AnnData object 62 | - basis: string indicating the name of the obsm basis to use to use for layout of neighbourhoods (key in `adata.obsm`) 63 | ''' 64 | # Add embedding positions 65 | adata.uns["nhood_adata"].obsm["X_milo_graph"] = adata[adata.obs["nhood_ixs_refined"] == 1].obsm[basis] 66 | # Add nhood size 67 | adata.uns["nhood_adata"].obs["Nhood_size"] = np.array( 68 | adata.obsm["nhoods"].sum(0)).flatten() 69 | # Add adjacency graph 70 | adata.uns["nhood_adata"].obsp["nhood_connectivities"] = adata.obsm["nhoods"].T.dot( 71 | adata.obsm["nhoods"]) 72 | adata.uns["nhood_adata"].uns["nhood"] = { 73 | "connectivities_key": "nhood_connectivities", "distances_key": ""} 74 | 75 | ## -- UTILS --- ## 76 | 77 | 78 | def add_covariate_to_nhoods_var( 79 | adata: AnnData, 80 | new_covariates: List[str]): 81 | ''' 82 | Add covariate from adata.obs to adata.uns["nhood_adata"].var 83 | ''' 84 | try: 85 | nhood_adata = adata.uns["nhood_adata"].copy() 86 | except KeyError: 87 | raise KeyError( 88 | 'Cannot find "nhood_adata" slot in adata.uns -- please run milopy.count_nhoods(adata)' 89 | ) 90 | 91 | sample_col = nhood_adata.uns["sample_col"] 92 | covariates = list(set( 93 | nhood_adata.var.columns[nhood_adata.var.columns != sample_col].tolist() + new_covariates)) 94 | try: 95 | nhoods_var = adata.obs[covariates + [sample_col]].drop_duplicates() 96 | except KeyError: 97 | missing_cov = [ 98 | x for x in covariates if x not in nhood_adata.var.columns] 99 | raise KeyError( 100 | 'Covariates {c} are not columns in adata.obs'.format( 101 | c=" ".join(missing_cov)) 102 | ) 103 | nhoods_var = nhoods_var[covariates + [sample_col]].astype("str") 104 | nhoods_var.index = nhoods_var[sample_col] 105 | try: 106 | assert nhoods_var.loc[nhood_adata.var_names].shape[0] == len( 107 | nhood_adata.var_names) 108 | except: 109 | raise ValueError( 110 | "Covariates cannot be unambiguously assigned to each sample -- each sample value should match a single covariate value") 111 | nhood_adata.var = nhoods_var.loc[nhood_adata.var_names] 112 | adata.uns["nhood_adata"] = nhood_adata 113 | 114 | 115 | def annotate_nhoods(adata: AnnData, 116 | anno_col: str): 117 | ''' 118 | Assigns a categorical label to neighbourhoods, based on the most frequent label 119 | among cells in each neighbourhood. This can be useful to stratify DA testing 120 | results by cell types or samples. 121 | 122 | Params: 123 | ------- 124 | - adata: AnnData object with adata.uns["nhood_adata"] 125 | - anno_col: string indicating column in adata.obs containing the cell annotations to use for nhood labelling 126 | 127 | Returns: 128 | -------- 129 | None. Adds in place: 130 | - `adata.uns["nhood_adata"].obs["nhood_annotation"]`: assigning a label to each nhood 131 | - `adata.uns["nhood_adata"].obs["nhood_annotation_frac"]` stores the fraciton of cells in the neighbourhood with the assigned label 132 | - `adata.uns["nhood_adata"].obsm['frac_annotation']`: stores the fraction of cells from each label in each nhood 133 | - `adata.uns["nhood_adata"].uns["annotation_labels"]`: stores the column names for `adata.uns["nhood_adata"].obsm['frac_annotation']` 134 | ''' 135 | try: 136 | nhood_adata = adata.uns["nhood_adata"] 137 | except KeyError: 138 | raise KeyError( 139 | 'Cannot find "nhood_adata" slot in adata.uns -- please run milopy.make_nhoods_adata(adata)' 140 | ) 141 | 142 | # Check value is not numeric 143 | if pd.api.types.is_numeric_dtype(adata.obs[anno_col]): 144 | raise ValueError( 145 | 'adata.obs[anno_col] is not of categorical type - please use milopy.utils.annotate_nhoods_continuous for continuous variables') 146 | 147 | anno_dummies = pd.get_dummies(adata.obs[anno_col]) 148 | anno_count = adata.obsm["nhoods"].T.dot( 149 | scipy.sparse.csr_matrix(anno_dummies.values)) 150 | try: 151 | anno_frac = (anno_count/anno_count.sum(1)).toarray() 152 | except AttributeError: # for old version of python 153 | anno_frac = np.array(anno_count/anno_count.sum(1)) 154 | 155 | anno_frac = pd.DataFrame(anno_frac, 156 | columns=anno_dummies.columns, 157 | index=adata.uns["nhood_adata"].obs_names 158 | ) 159 | adata.uns["nhood_adata"].obsm["frac_annotation"] = anno_frac.values 160 | # Turn this to list so that writing out h5ad works 161 | adata.uns["nhood_adata"].uns["annotation_labels"] = anno_frac.columns.to_list() 162 | adata.uns["nhood_adata"].uns["annotation_obs"] = anno_col 163 | adata.uns["nhood_adata"].obs["nhood_annotation"] = anno_frac.idxmax(1) 164 | adata.uns["nhood_adata"].obs["nhood_annotation_frac"] = anno_frac.max(1) 165 | 166 | 167 | def annotate_nhoods_continuous( 168 | adata: AnnData, 169 | anno_col: str): 170 | ''' 171 | Assigns a continuous value to neighbourhoods, based on mean cell level covariate stored in adata.obs. 172 | This can be useful to correlate DA log-foldChanges with continuous covariates such as pseudotime, gene expression scores etc... 173 | 174 | Params: 175 | ------- 176 | - adata: AnnData object with adata.uns["nhood_adata"] 177 | - anno_col: string indicating column in adata.obs containing the cell annotations to use for nhood labelling 178 | 179 | Returns: 180 | -------- 181 | None. Adds in place: 182 | - `adata.uns["nhood_adata"].obs["nhood_{anno_col}"]`: assigning a continuous value to each nhood 183 | ''' 184 | try: 185 | nhood_adata = adata.uns["nhood_adata"] 186 | except KeyError: 187 | raise KeyError( 188 | 'Cannot find "nhood_adata" slot in adata.uns -- please run milopy.count_nhoods(adata)' 189 | ) 190 | 191 | # Check value is not categorical 192 | if not pd.api.types.is_numeric_dtype(adata.obs[anno_col]): 193 | raise ValueError( 194 | 'adata.obs[anno_col] is not of continuous type - please use milopy.utils.annotate_nhoods for categorical variables') 195 | 196 | anno_val = adata.obsm["nhoods"].T.dot( 197 | scipy.sparse.csr_matrix(adata.obs[anno_col]).T) 198 | 199 | mean_anno_val = anno_val.toarray()/np.array(adata.obsm["nhoods"].T.sum(1)) 200 | 201 | adata.uns["nhood_adata"].obs[f"nhood_{anno_col}"] = mean_anno_val 202 | 203 | 204 | ## -- I/O -- ## 205 | def write_milo_adata(adata: AnnData, 206 | filepath: str, 207 | **kwargs): 208 | ''' 209 | Save anndata objects after Milo analysis 210 | 211 | Params: 212 | ----- 213 | - adata: AnnData object with adata.uns["nhood_adata"] 214 | - filepath: path to h5ad file to save 215 | - **kwargs: arguments passed to scanpy.write_h5ad 216 | 217 | Returns: 218 | ------- 219 | None, saves 2 AnnData objects in h5ad format. The cell x gene AnnData is saved in filepath. 220 | The nhood x sample AnnData is saved in a separate object (location is stored in adata.uns['nhood_adata_filepath']) 221 | ''' 222 | nhood_filepath = filepath.split('.h5ad')[0] + ".nhood_adata.h5ad" 223 | adata.uns['nhood_adata_filepath'] = nhood_filepath 224 | 225 | if 'nhood_adata' not in adata.uns.keys(): 226 | raise KeyError( 227 | 'Cannot find "nhood_adata" slot in adata.uns -- please run milopy.make_nhoods_adata(adata)') 228 | nhood_adata = adata.uns["nhood_adata"].copy() 229 | nhood_adata.write_h5ad(nhood_filepath, **kwargs) 230 | del adata.uns["nhood_adata"] 231 | adata.write_h5ad(filepath, **kwargs) 232 | 233 | 234 | def read_milo_adata( 235 | filepath: str, 236 | **kwargs) -> AnnData: 237 | ''' 238 | Read AnnData objects stored after Milo analysis 239 | 240 | Params: 241 | ------ 242 | - filepath: path to h5ad file storing cell x gene AnnData object 243 | - **kwargs: additional arguments passed to scanpy.read_h5ad 244 | 245 | Returns: 246 | ------- 247 | - AnnData object storing milo slots (adata.obsm['nhoods'], adata.uns['nhood_adata']) 248 | ''' 249 | adata = sc.read_h5ad(filepath, **kwargs) 250 | try: 251 | nhood_filepath = adata.uns['nhood_adata_filepath'] 252 | except: 253 | raise KeyError('No nhood_adata_file associated to adata') 254 | adata.uns["nhood_adata"] = sc.read_h5ad(nhood_filepath, **kwargs) 255 | return(adata) 256 | -------------------------------------------------------------------------------- /milopy/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.1.1" 2 | __author__ = "Emma Dann" 3 | __author_email__ = "ed6@sanger.ac.uk" 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | scanpy 2 | pandas 3 | anndata 4 | numpy 5 | rpy2 >= 3.3.5 6 | scipy -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(name='milopy', 4 | version='0.1.1', 5 | description='python implementation of miloR for differential abundance analysis in single-cell datasets', 6 | url='https://github.com/emdann/milopy', 7 | author='Emma Dann', 8 | author_email='ed6@sanger.ac.uk', 9 | license='MIT', 10 | packages=['milopy'], 11 | install_requires=[ 12 | "pandas", 13 | "anndata", 14 | "scanpy>=1.6.0", 15 | "scipy", 16 | "numpy", 17 | "matplotlib", 18 | "rpy2 >= 3.3.5" 19 | ], 20 | zip_safe=False) 21 | --------------------------------------------------------------------------------