├── .github
└── workflows
│ ├── pre-commit.yml
│ ├── python-package.yml
│ └── python-publish.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yml
├── AUTHORS.rst
├── CONTRIBUTING.rst
├── HISTORY.rst
├── LICENSE
├── MANIFEST.in
├── README.md
├── docs
├── Makefile
├── _temp
│ └── example_cci.py
├── _templates
│ └── autosummary
│ │ ├── base.rst
│ │ └── class.rst
├── api.rst
├── authors.rst
├── conf.py
├── index.rst
├── installation.rst
├── interactive.rst
├── list_tutorial.txt
├── make.bat
├── references.rst
├── release_notes
│ ├── 0.3.2.rst
│ ├── 0.4.6.rst
│ └── index.rst
├── requirements.txt
└── tutorials.rst
├── requirements.txt
├── resource
├── README.md
├── connectomedb2020.txt
├── label_transfer_bc.csv
├── means.txt
└── predictions.csv
├── setup.cfg
├── setup.py
├── stlearn
├── __init__.py
├── __main__.py
├── _compat.py
├── _datasets
│ ├── __init__.py
│ └── _datasets.py
├── _settings.py
├── add.py
├── adds
│ ├── __init__.py
│ ├── add_deconvolution.py
│ ├── add_image.py
│ ├── add_labels.py
│ ├── add_loupe_clusters.py
│ ├── add_lr.py
│ ├── add_mask.py
│ ├── add_positions.py
│ ├── annotation.py
│ └── parsing.py
├── app
│ ├── __init__.py
│ ├── app.py
│ ├── cli.py
│ ├── requirements.txt
│ ├── source
│ │ ├── __init__.py
│ │ ├── forms
│ │ │ ├── __init__.py
│ │ │ ├── form_validators.py
│ │ │ ├── forms.py
│ │ │ ├── helper_functions.py
│ │ │ ├── utils.py
│ │ │ ├── view_helpers.py
│ │ │ └── views.py
│ │ └── readme.md
│ ├── static
│ │ ├── css
│ │ │ ├── material-dashboard.min.css
│ │ │ └── style.css
│ │ ├── img
│ │ │ ├── Settings.gif
│ │ │ ├── favicon.png
│ │ │ └── loading_gif.gif
│ │ └── js
│ │ │ ├── core
│ │ │ ├── bootstrap-material-design.min.js
│ │ │ ├── jquery.min.js
│ │ │ └── popper.min.js
│ │ │ └── plugins
│ │ │ └── perfect-scrollbar.jquery.min.js
│ └── templates
│ │ ├── __init__.py
│ │ ├── annotate_plot.html
│ │ ├── base.html
│ │ ├── cci.html
│ │ ├── cci_old.html
│ │ ├── cci_plot.html
│ │ ├── choose_cluster.html
│ │ ├── cluster_plot.html
│ │ ├── clustering.html
│ │ ├── dea.html
│ │ ├── flash_header.html
│ │ ├── gene_plot.html
│ │ ├── index.html
│ │ ├── lr.html
│ │ ├── lr_plot.html
│ │ ├── preprocessing.html
│ │ ├── progress.html
│ │ ├── psts.html
│ │ ├── spatial_cci_plot.html
│ │ ├── superform.html
│ │ └── upload.html
├── classes.py
├── datasets.py
├── em.py
├── embedding
│ ├── __init__.py
│ ├── diffmap.py
│ ├── fa.py
│ ├── ica.py
│ ├── pca.py
│ └── umap.py
├── gui.py
├── image_preprocessing
│ ├── __init__.py
│ ├── feature_extractor.py
│ ├── image_tiling.py
│ ├── model_zoo.py
│ └── segmentation.py
├── logging.py
├── pl.py
├── plotting
│ ├── QC_plot.py
│ ├── __init__.py
│ ├── _docs.py
│ ├── cci_plot.py
│ ├── cci_plot_helpers.py
│ ├── classes.py
│ ├── classes_bokeh.py
│ ├── cluster_plot.py
│ ├── deconvolution_plot.py
│ ├── feat_plot.py
│ ├── gene_plot.py
│ ├── mask_plot.py
│ ├── non_spatial_plot.py
│ ├── palettes_st.py
│ ├── stack_3d_plot.py
│ ├── subcluster_plot.py
│ ├── trajectory
│ │ ├── DE_transition_plot.py
│ │ ├── __init__.py
│ │ ├── check_trajectory.py
│ │ ├── local_plot.py
│ │ ├── pseudotime_plot.py
│ │ ├── transition_markers_plot.py
│ │ ├── tree_plot.py
│ │ ├── tree_plot_simple.py
│ │ └── utils.py
│ └── utils.py
├── pp.py
├── preprocessing
│ ├── __init__.py
│ ├── filter_genes.py
│ ├── graph.py
│ ├── log_scale.py
│ └── normalize.py
├── spatial.py
├── spatials
│ ├── SME
│ │ ├── __init__.py
│ │ ├── _weighting_matrix.py
│ │ ├── impute.py
│ │ └── normalize.py
│ ├── __init__.py
│ ├── clustering
│ │ ├── __init__.py
│ │ └── localization.py
│ ├── morphology
│ │ ├── __init__.py
│ │ └── adjust.py
│ ├── smooth
│ │ ├── __init__.py
│ │ └── disk.py
│ └── trajectory
│ │ ├── __init__.py
│ │ ├── compare_transitions.py
│ │ ├── detect_transition_markers.py
│ │ ├── global_level.py
│ │ ├── local_level.py
│ │ ├── pseudotime.py
│ │ ├── pseudotimespace.py
│ │ ├── set_root.py
│ │ ├── shortest_path_spatial_PAGA.py
│ │ ├── utils.py
│ │ └── weight_optimization.py
├── tl.py
├── tools
│ ├── __init__.py
│ ├── clustering
│ │ ├── __init__.py
│ │ ├── annotate.py
│ │ ├── kmeans.py
│ │ └── louvain.py
│ ├── label
│ │ ├── __init__.py
│ │ ├── label.py
│ │ ├── label_transfer.R
│ │ ├── rctd.R
│ │ └── singleR.R
│ └── microenv
│ │ ├── __init__.py
│ │ └── cci
│ │ ├── __init__.py
│ │ ├── analysis.py
│ │ ├── base.py
│ │ ├── base_grouping.py
│ │ ├── databases
│ │ ├── __init__.py
│ │ ├── connectomeDB2020_lit.txt
│ │ └── connectomeDB2020_put.txt
│ │ ├── go.R
│ │ ├── go.py
│ │ ├── het.py
│ │ ├── het_helpers.py
│ │ ├── merge.py
│ │ ├── perm_utils.py
│ │ ├── permutation.py
│ │ └── r_helpers.py
├── utils.py
└── wrapper
│ ├── __init__.py
│ ├── concatenate_spatial_adata.py
│ ├── convert_scanpy.py
│ └── read.py
├── tests
├── __init__.py
├── test_CCI.py
├── test_PSTS.py
├── test_SME.py
├── test_data
│ ├── test_data.h5
│ └── test_image.jpg
├── test_install.py
└── utils.py
└── tox.ini
/.github/workflows/pre-commit.yml:
--------------------------------------------------------------------------------
1 | name: pre-commit
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches: [master]
7 |
8 | jobs:
9 | pre-commit:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v2
13 | - uses: actions/setup-python@v2
14 | - uses: pre-commit/action@v2.0.0
15 |
--------------------------------------------------------------------------------
/.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 | matrix:
18 | python-version: [3.8]
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 | - name: Set up Python ${{ matrix.python-version }}
23 | uses: actions/setup-python@v2
24 | with:
25 | python-version: ${{ matrix.python-version }}
26 | - name: Install dependencies
27 | run: |
28 | python -m pip install --upgrade pip
29 | python -m pip install pytest
30 |
31 | pip install leidenalg
32 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
33 | pip install louvain
34 | - name: Test with pytest
35 | run: |
36 | pytest
37 |
--------------------------------------------------------------------------------
/.github/workflows/python-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will upload a Python Package using Twine when a release is created
2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3 |
4 | name: Upload Python Package
5 |
6 | on:
7 | release:
8 | types: [created]
9 |
10 | jobs:
11 | deploy:
12 |
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 | - name: Set up Python
18 | uses: actions/setup-python@v2
19 | with:
20 | python-version: '3.x'
21 | - name: Install dependencies
22 | run: |
23 | python -m pip install --upgrade pip
24 | pip install setuptools wheel twine
25 | - name: Build and publish
26 | env:
27 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
28 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
29 | run: |
30 | python setup.py sdist bdist_wheel
31 | twine upload dist/*
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | .ipynb_checkpoints
3 | */.ipynb_checkpoints/*
4 | build/
5 | dist/
6 | *.egg-info
7 | /*.ipynb
8 | /*.csv
9 | output/
10 | .DS_Store
11 | */.DS_Store
12 | .idea/
13 | docs/_build
14 | data/
15 | tiling/
16 | .pytest_cache
17 | figures/
18 | *.h5ad
19 | inferCNV/
20 | stlearn/tools/microenv/cci/junk_code.py
21 | stlearn/tools/microenv/cci/.Rhistory
22 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
3 | rev: v3.4.0
4 | hooks:
5 | - id: check-yaml
6 | - id: end-of-file-fixer
7 | - id: trailing-whitespace
8 | - id: check-added-large-files
9 | - id: check-docstring-first
10 | - id: check-byte-order-marker
11 | - id: requirements-txt-fixer
12 |
13 | - repo: https://github.com/psf/black
14 | rev: 22.3.0
15 | hooks:
16 | - id: black
17 |
--------------------------------------------------------------------------------
/.readthedocs.yml:
--------------------------------------------------------------------------------
1 | build:
2 | image: latest
3 | python:
4 | version: 3.8
5 |
--------------------------------------------------------------------------------
/AUTHORS.rst:
--------------------------------------------------------------------------------
1 | =======
2 | Credits
3 | =======
4 |
5 | Development Lead
6 | ----------------
7 |
8 | * Genomics and Machine Learning lab
9 |
10 | Contributors
11 | ------------
12 |
13 | None yet. Why not be the first?
14 |
--------------------------------------------------------------------------------
/CONTRIBUTING.rst:
--------------------------------------------------------------------------------
1 | .. highlight:: shell
2 |
3 | ============
4 | Contributing
5 | ============
6 |
7 | Contributions are welcome, and they are greatly appreciated! Every little bit
8 | helps, and credit will always be given.
9 |
10 | You can contribute in many ways:
11 |
12 | Types of Contributions
13 | ----------------------
14 |
15 | Report Bugs
16 | ~~~~~~~~~~~
17 |
18 | Report bugs at https://github.com/duypham2108/stlearn/issues.
19 |
20 | If you are reporting a bug, please include:
21 |
22 | * Your operating system name and version.
23 | * Any details about your local setup that might be helpful in troubleshooting.
24 | * Detailed steps to reproduce the bug.
25 |
26 | Fix Bugs
27 | ~~~~~~~~
28 |
29 | Look through the GitHub issues for bugs. Anything tagged with "bug" and "help
30 | wanted" is open to whoever wants to implement it.
31 |
32 | Implement Features
33 | ~~~~~~~~~~~~~~~~~~
34 |
35 | Look through the GitHub issues for features. Anything tagged with "enhancement"
36 | and "help wanted" is open to whoever wants to implement it.
37 |
38 | Write Documentation
39 | ~~~~~~~~~~~~~~~~~~~
40 |
41 | stLearn could always use more documentation, whether as part of the
42 | official stLearn docs, in docstrings, or even on the web in blog posts,
43 | articles, and such.
44 |
45 | Submit Feedback
46 | ~~~~~~~~~~~~~~~
47 |
48 | The best way to send feedback is to file an issue at https://github.com/duypham2108/stlearn/issues.
49 |
50 | If you are proposing a feature:
51 |
52 | * Explain in detail how it would work.
53 | * Keep the scope as narrow as possible, to make it easier to implement.
54 | * Remember that this is a volunteer-driven project, and that contributions
55 | are welcome :)
56 |
57 | Get Started!
58 | ------------
59 |
60 | Ready to contribute? Here's how to set up `stlearn` for local development.
61 |
62 | 1. Fork the `stlearn` repo on GitHub.
63 | 2. Clone your fork locally::
64 |
65 | $ git clone git@github.com:your_name_here/stlearn.git
66 |
67 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development::
68 |
69 | $ mkvirtualenv stlearn
70 | $ cd stlearn/
71 | $ python setup.py develop
72 |
73 | 4. Create a branch for local development::
74 |
75 | $ git checkout -b name-of-your-bugfix-or-feature
76 |
77 | Now you can make your changes locally.
78 |
79 | 5. When you're done making changes, check that your changes pass flake8 and the
80 | tests, including testing other Python versions with tox::
81 |
82 | $ flake8 stlearn tests
83 | $ python setup.py test or pytest
84 | $ tox
85 |
86 | To get flake8 and tox, just pip install them into your virtualenv.
87 |
88 | 6. Commit your changes and push your branch to GitHub::
89 |
90 | $ git add .
91 | $ git commit -m "Your detailed description of your changes."
92 | $ git push origin name-of-your-bugfix-or-feature
93 |
94 | 7. Submit a pull request through the GitHub website.
95 |
96 | Pull Request Guidelines
97 | -----------------------
98 |
99 | Before you submit a pull request, check that it meets these guidelines:
100 |
101 | 1. The pull request should include tests.
102 | 2. If the pull request adds functionality, the docs should be updated. Put
103 | your new functionality into a function with a docstring, and add the
104 | feature to the list in README.rst.
105 | 3. The pull request should work for Python 3.5, 3.6, 3.7 and 3.8, and for PyPy. Check
106 | https://travis-ci.org/duypham2108/stlearn/pull_requests
107 | and make sure that the tests pass for all supported Python versions.
108 |
109 | Tips
110 | ----
111 |
112 | To run a subset of tests::
113 |
114 |
115 | $ python -m unittest tests.test_stlearn
116 |
117 | Deploying
118 | ---------
119 |
120 | A reminder for the maintainers on how to deploy.
121 | Make sure all your changes are committed (including an entry in HISTORY.rst).
122 | Then run::
123 |
124 | $ bump2version patch # possible: major / minor / patch
125 | $ git push
126 | $ git push --tags
127 |
128 | Travis will then deploy to PyPI if tests pass.
129 |
--------------------------------------------------------------------------------
/HISTORY.rst:
--------------------------------------------------------------------------------
1 | =======
2 | History
3 | =======
4 |
5 | 0.4.11 (2022-11-25)
6 | ------------------
7 | 0.4.10 (2022-11-22)
8 | ------------------
9 | 0.4.8 (2022-06-15)
10 | ------------------
11 | 0.4.7 (2022-03-28)
12 | ------------------
13 | 0.4.6 (2022-03-09)
14 | ------------------
15 | 0.4.5 (2022-03-02)
16 | ------------------
17 | 0.4.0 (2022-02-03)
18 | ------------------
19 | 0.3.2 (2021-03-29)
20 | ------------------
21 | 0.3.1 (2020-12-24)
22 | ------------------
23 | 0.2.7 (2020-09-12)
24 | ------------------
25 | 0.2.6 (2020-08-04)
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 |
3 | BSD License
4 |
5 | Copyright (c) 2020, Genomics and Machine Learning lab
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without modification,
9 | are permitted provided that the following conditions are met:
10 |
11 | * Redistributions of source code must retain the above copyright notice, this
12 | list of conditions and the following disclaimer.
13 |
14 | * Redistributions in binary form must reproduce the above copyright notice, this
15 | list of conditions and the following disclaimer in the documentation and/or
16 | other materials provided with the distribution.
17 |
18 | * Neither the name of the copyright holder nor the names of its
19 | contributors may be used to endorse or promote products derived from this
20 | software without specific prior written permission.
21 |
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
29 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 | OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include AUTHORS.rst
2 | include CONTRIBUTING.rst
3 | include HISTORY.rst
4 | include LICENSE
5 | include README.rst
6 | include requirements.txt
7 |
8 | recursive-include tests *
9 | recursive-exclude * __pycache__
10 | recursive-exclude * *.py[co]
11 |
12 | recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif
13 | recursive-include stlearn/app *.txt
14 | recursive-include stlearn/app/templates *
15 | recursive-include stlearn/app/static *
16 | recursive-include stlearn/tools/microenv/cci/databases *.txt
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 | Package
10 |
11 |
12 |
13 |
14 |
15 |
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Documentation
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Paper
40 |
41 |
42 |
44 |
45 |
46 |
47 |
48 | License
49 |
50 |
51 |
53 |
54 |
55 |
56 |
57 |
58 | # stLearn - A downstream analysis toolkit for Spatial Transcriptomic data
59 |
60 | **stLearn** is designed to comprehensively analyse Spatial Transcriptomics (ST) data to investigate complex biological processes within an undissociated tissue. ST is emerging as the “next generation” of single-cell RNA sequencing because it adds spatial and morphological context to the transcriptional profile of cells in an intact tissue section. However, existing ST analysis methods typically use the captured spatial and/or morphological data as a visualisation tool rather than as informative features for model development. We have developed an analysis method that exploits all three data types: Spatial distance, tissue Morphology, and gene Expression measurements (SME) from ST data. This combinatorial approach allows us to more accurately model underlying tissue biology, and allows researchers to address key questions in three major research areas: cell type identification, spatial trajectory reconstruction, and the study of cell-cell interactions within an undissociated tissue sample.
61 |
62 | ---
63 |
64 | ## Getting Started
65 |
66 | - [Documentation and Tutorials](https://stlearn.readthedocs.io/en/latest/)
67 |
68 | ## Citing stLearn
69 |
70 | If you have used stLearn in your research, please consider citing us:
71 |
72 | > Pham, Duy, et al. "Robust mapping of spatiotemporal trajectories and cell–cell interactions in healthy and diseased tissues."
73 | > Nature Communications 14.1 (2023): 7739.
74 | > [https://doi.org/10.1101/2020.05.31.125658](https://doi.org/10.1038/s41467-023-43120-6)
75 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = python -msphinx
7 | SPHINXPROJ = stlearn
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/_templates/autosummary/base.rst:
--------------------------------------------------------------------------------
1 |
2 | {% extends "!autosummary/base.rst" %}
3 |
4 | .. http://www.sphinx-doc.org/en/stable/ext/autosummary.html#customizing-templates
5 |
--------------------------------------------------------------------------------
/docs/_templates/autosummary/class.rst:
--------------------------------------------------------------------------------
1 | {{ fullname | escape | underline}}
2 |
3 | .. currentmodule:: {{ module }}
4 |
5 | .. add toctree option to make autodoc generate the pages
6 |
--------------------------------------------------------------------------------
/docs/api.rst:
--------------------------------------------------------------------------------
1 | .. module:: stlearn
2 | .. automodule:: stlearn
3 | :noindex:
4 |
5 | API
6 | ======================================
7 |
8 | Import stLearn as::
9 |
10 | import stlearn as st
11 |
12 |
13 | Wrapper functions: `wrapper`
14 | ------------------------------
15 |
16 | .. module:: stlearn.wrapper
17 | .. currentmodule:: stlearn
18 |
19 | .. autosummary::
20 | :toctree: .
21 |
22 | Read10X
23 | ReadOldST
24 | ReadSlideSeq
25 | ReadMERFISH
26 | ReadSeqFish
27 | convert_scanpy
28 | create_stlearn
29 |
30 |
31 | Add: `add`
32 | -------------------
33 |
34 | .. module:: stlearn.add
35 | .. currentmodule:: stlearn
36 |
37 | .. autosummary::
38 | :toctree: .
39 |
40 | add.image
41 | add.positions
42 | add.parsing
43 | add.lr
44 | add.labels
45 | add.annotation
46 | add.add_loupe_clusters
47 | add.add_mask
48 | add.apply_mask
49 | add.add_deconvolution
50 |
51 |
52 | Preprocessing: `pp`
53 | -------------------
54 |
55 | .. module:: stlearn.pp
56 | .. currentmodule:: stlearn
57 |
58 | .. autosummary::
59 | :toctree: .
60 |
61 | pp.filter_genes
62 | pp.log1p
63 | pp.normalize_total
64 | pp.scale
65 | pp.neighbors
66 | pp.tiling
67 | pp.extract_feature
68 |
69 |
70 |
71 | Embedding: `em`
72 | -------------------
73 |
74 | .. module:: stlearn.em
75 | .. currentmodule:: stlearn
76 |
77 | .. autosummary::
78 | :toctree: .
79 |
80 | em.run_pca
81 | em.run_umap
82 | em.run_ica
83 | em.run_fa
84 | em.run_diffmap
85 |
86 |
87 | Spatial: `spatial`
88 | -------------------
89 |
90 | .. module:: stlearn.spatial.clustering
91 | .. currentmodule:: stlearn
92 |
93 | .. autosummary::
94 | :toctree: .
95 |
96 | spatial.clustering.localization
97 |
98 | .. module:: stlearn.spatial.trajectory
99 | .. currentmodule:: stlearn
100 |
101 | .. autosummary::
102 | :toctree: .
103 |
104 | spatial.trajectory.pseudotime
105 | spatial.trajectory.pseudotimespace_global
106 | spatial.trajectory.pseudotimespace_local
107 | spatial.trajectory.compare_transitions
108 | spatial.trajectory.detect_transition_markers_clades
109 | spatial.trajectory.detect_transition_markers_branches
110 | spatial.trajectory.set_root
111 |
112 | .. module:: stlearn.spatial.morphology
113 | .. currentmodule:: stlearn
114 |
115 | .. autosummary::
116 | :toctree: .
117 |
118 | spatial.morphology.adjust
119 |
120 | .. module:: stlearn.spatial.SME
121 | .. currentmodule:: stlearn
122 |
123 | .. autosummary::
124 | :toctree: .
125 |
126 | spatial.SME.SME_impute0
127 | spatial.SME.pseudo_spot
128 | spatial.SME.SME_normalize
129 |
130 | Tools: `tl`
131 | -------------------
132 |
133 | .. module:: stlearn.tl.clustering
134 | .. currentmodule:: stlearn
135 |
136 | .. autosummary::
137 | :toctree: .
138 |
139 | tl.clustering.kmeans
140 | tl.clustering.louvain
141 |
142 |
143 | .. module:: stlearn.tl.cci
144 | .. currentmodule:: stlearn
145 |
146 | .. autosummary::
147 | :toctree: .
148 |
149 | tl.cci.load_lrs
150 | tl.cci.grid
151 | tl.cci.run
152 | tl.cci.adj_pvals
153 | tl.cci.run_lr_go
154 | tl.cci.run_cci
155 |
156 | Plot: `pl`
157 | -------------------
158 |
159 | .. module:: stlearn.pl
160 | .. currentmodule:: stlearn
161 |
162 | .. autosummary::
163 | :toctree: .
164 |
165 | pl.QC_plot
166 | pl.gene_plot
167 | pl.gene_plot_interactive
168 | pl.cluster_plot
169 | pl.cluster_plot_interactive
170 | pl.subcluster_plot
171 | pl.subcluster_plot
172 | pl.non_spatial_plot
173 | pl.deconvolution_plot
174 | pl.plot_mask
175 | pl.lr_summary
176 | pl.lr_diagnostics
177 | pl.lr_n_spots
178 | pl.lr_go
179 | pl.lr_result_plot
180 | pl.lr_plot
181 | pl.cci_check
182 | pl.ccinet_plot
183 | pl.lr_chord_plot
184 | pl.lr_cci_map
185 | pl.cci_map
186 | pl.lr_plot_interactive
187 | pl.spatialcci_plot_interactive
188 |
189 | .. module:: stlearn.pl.trajectory
190 | .. currentmodule:: stlearn
191 |
192 | .. autosummary::
193 | :toctree: .
194 |
195 | pl.trajectory.pseudotime_plot
196 | pl.trajectory.local_plot
197 | pl.trajectory.tree_plot
198 | pl.trajectory.transition_markers_plot
199 | pl.trajectory.DE_transition_plot
200 |
201 | Tools: `datasets`
202 | -------------------
203 |
204 | .. module:: stlearn.datasets
205 | .. currentmodule:: stlearn
206 |
207 | .. autosummary::
208 | :toctree: .
209 |
210 | datasets.example_bcba()
211 |
--------------------------------------------------------------------------------
/docs/authors.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../AUTHORS.rst
2 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 |
2 |
3 | stLearn - a downstream analysis toolkit for Spatial Transcriptomics data
4 | ============================================================================
5 |
6 | |PyPI| |PyPIDownloads| |Docs|
7 |
8 | .. |PyPI| image:: https://img.shields.io/pypi/v/stlearn?logo=PyPI
9 | :target: https://pypi.org/project/stlearn
10 | .. |PyPIDownloads| image:: https://pepy.tech/badge/stlearn
11 | .. |Docs| image:: https://readthedocs.org/projects/stlearn/badge/?version=latest
12 | :target: https://stlearn.readthedocs.io
13 |
14 |
15 |
16 | .. image:: https://i.imgur.com/yfXlCYO.png
17 | :width: 300px
18 | :align: left
19 |
20 | stLearn is designed to comprehensively analyse Spatial Transcriptomics (ST) data to investigate complex biological processes within an undissociated tissue. ST is emerging as the “next generation” of single-cell RNA sequencing because it adds spatial and morphological context to the transcriptional profile of cells in an intact tissue section. However, existing ST analysis methods typically use the captured spatial and/or morphological data as a visualisation tool rather than as informative features for model development. We have developed an analysis method that exploits all three data types: Spatial distance, tissue Morphology, and gene Expression measurements (SME) from ST data. This combinatorial approach allows us to more accurately model underlying tissue biology, and allows researchers to address key questions in three major research areas: cell type identification, cell trajectory reconstruction, and the study of cell-cell interactions within an undissociated tissue sample.
21 |
22 | We also published stLearn-interactive which is a python-based interactive website for working with all the functions from stLearn and upgrade with some bokeh-based plots.
23 |
24 | To run the stlearn interaction webapp in your local, run:
25 | ::
26 |
27 | stlearn launch
28 |
29 |
30 | New features
31 | **********************
32 |
33 | In the new release, we provide the interactive plots:
34 |
35 | .. image:: https://media.giphy.com/media/hUHAZcbVMm5pdUKMq4/giphy.gif
36 | :width: 600px
37 |
38 |
39 |
40 | Latest additions
41 | ----------------
42 |
43 | .. include:: release_notes/0.4.11.rst
44 |
45 | .. include:: release_notes/0.4.6.rst
46 |
47 | .. include:: release_notes/0.3.2.rst
48 |
49 |
50 |
51 |
52 | .. toctree::
53 | :maxdepth: 1
54 | :hidden:
55 |
56 |
57 | installation
58 | interactive
59 | tutorials
60 | api
61 | release_notes/index
62 | authors
63 | references
64 |
--------------------------------------------------------------------------------
/docs/installation.rst:
--------------------------------------------------------------------------------
1 | .. highlight:: shell
2 |
3 | ============
4 | Installation
5 | ============
6 |
7 |
8 | Install by Anaconda
9 | ---------------
10 |
11 | **Step 1:**
12 |
13 | Prepare conda environment for stLearn
14 | ::
15 |
16 | conda create -n stlearn python=3.8
17 | conda activate stlearn
18 |
19 | **Step 2:**
20 |
21 | You can directly install stlearn in the anaconda by:
22 | ::
23 |
24 | conda install -c conda-forge stlearn
25 |
26 | Install by PyPi
27 | ---------------
28 |
29 | **Step 1:**
30 |
31 | Prepare conda environment for stLearn
32 | ::
33 |
34 | conda create -n stlearn python=3.8
35 | conda activate stlearn
36 |
37 | **Step 2:**
38 |
39 | Install stlearn using `pip`
40 | ::
41 |
42 | pip install -U stlearn
43 |
44 |
45 |
46 | Popular bugs
47 | ---------------
48 |
49 | - `DLL load failed while importing utilsextension: The specified module could not be found.`
50 |
51 | You need to uninstall package `tables` and install it again
52 | ::
53 |
54 | pip uninstall tables
55 | conda install pytables
56 |
57 | If conda version does not work, you can access to this site and download the .whl file: `https://www.lfd.uci.edu/~gohlke/pythonlibs/#pytables`
58 |
59 | ::
60 |
61 | pip install tables-3.7.0-cp38-cp38-win_amd64.whl
62 |
--------------------------------------------------------------------------------
/docs/interactive.rst:
--------------------------------------------------------------------------------
1 | .. highlight:: shell
2 |
3 | ============
4 | Interactive web application
5 | ============
6 |
7 |
8 | Launch stlearn in your local
9 | ---------------
10 |
11 | Run the launch command in the terminal:
12 | ::
13 |
14 | stlearn launch
15 |
16 | After that, you can access `https://:5000` in your web browser.
17 |
18 | Check the detail tutorial in this pdf file: `Link `_
19 |
--------------------------------------------------------------------------------
/docs/list_tutorial.txt:
--------------------------------------------------------------------------------
1 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/Pseudo-time-space-tutorial.ipynb
2 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/Read_MERFISH.ipynb
3 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/Read_seqfish.ipynb
4 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/Read_slideseq.ipynb
5 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/ST_deconvolution_visualization.ipynb
6 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/Working-with-Old-Spatial-Transcriptomics-data.ipynb
7 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/stLearn-CCI.ipynb
8 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/stSME_clustering.ipynb
9 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/stSME_comparison.ipynb
10 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/Xenium_PSTS.ipynb
11 | https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/master/tutorials/Xenium_CCI.ipynb
12 |
--------------------------------------------------------------------------------
/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=python -msphinx
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 | set SPHINXPROJ=stlearn
13 |
14 | if "%1" == "" goto help
15 |
16 | %SPHINXBUILD% >NUL 2>NUL
17 | if errorlevel 9009 (
18 | echo.
19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed,
20 | echo.then set the SPHINXBUILD environment variable to point to the full
21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the
22 | echo.Sphinx directory to PATH.
23 | echo.
24 | echo.If you don't have Sphinx installed, grab it from
25 | echo.http://sphinx-doc.org/
26 | exit /b 1
27 | )
28 |
29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
30 | goto end
31 |
32 | :help
33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
34 |
35 | :end
36 | popd
37 |
--------------------------------------------------------------------------------
/docs/references.rst:
--------------------------------------------------------------------------------
1 | References
2 | ----------
3 | .. [Coifman05] Coifman *et al.* (2005),
4 | *Geometric diffusions as a tool for harmonic analysis and structure definition of data: Diffusion maps*,
5 | `PNAS `__.
6 |
7 | .. [Haghverdi15] Haghverdi *et al.* (2015),
8 | *Diffusion maps for high-dimensional single-cell analysis of differentiation data*,
9 | `Bioinformatics `__.
10 |
11 | .. [Haghverdi16] Haghverdi *et al.* (2016),
12 | *Diffusion pseudotime robustly reconstructs branching cellular lineages*,
13 | `Nature Methods `__.
14 |
15 | .. [Wolf18] Wolf *et al.* (2018),
16 | *Scanpy: large-scale single-cell gene expression data analysis*,
17 | `Genome Biology `__.
18 |
19 | .. [Pedregosa11] Pedregosa *et al.* (2011),
20 | *Scikit-learn: Machine Learning in Python*,
21 | `JMLR `__.
22 |
23 | .. [McInnes18] McInnes & Healy (2018),
24 | *UMAP: Uniform Manifold Approximation and Projection for Dimension Reduction*,
25 | `arXiv `__.
26 |
27 | .. [Weinreb16] Weinreb *et al.* (2016),
28 | *SPRING: a kinetic interface for visualizing high dimensional single-cell expression data*,
29 | `bioRxiv `__.
30 |
31 | .. [Satija15] Satija *et al.* (2015),
32 | *Spatial reconstruction of single-cell gene expression data*,
33 | `Nature Biotechnology `__.
34 |
35 | .. [Zheng17] Zheng *et al.* (2017),
36 | *Massively parallel digital transcriptional profiling of single cells*,
37 | `Nature Communications `__.
38 |
39 | .. [Weinreb17] Weinreb *et al.* (2016),
40 | *SPRING: a kinetic interface for visualizing high dimensional single-cell expression data*,
41 | `bioRxiv `__.
42 |
43 | .. [Blondel08] Blondel *et al.* (2008),
44 | *Fast unfolding of communities in large networks*,
45 | `J. Stat. Mech. `__.
46 |
47 | .. [Levine15] Levine *et al.* (2015),
48 | *Data-Driven Phenotypic Dissection of AML Reveals Progenitor--like Cells that Correlate with Prognosis*,
49 | `Cell `__.
50 |
51 | .. [Traag17] (2017),
52 | *Louvain*,
53 | `GitHub `__.
54 |
55 | .. [Lambiotte09] Lambiotte *et al.* (2009)
56 | *Laplacian Dynamics and Multiscale Modular Structure in Networks*
57 | `arXiv `__.
58 |
--------------------------------------------------------------------------------
/docs/release_notes/0.3.2.rst:
--------------------------------------------------------------------------------
1 | 0.3.2 `2021-03-29`
2 | ~~~~~~~~~~~~~~~~~~~~~~~~~
3 |
4 | .. rubric:: Feature
5 |
6 | - Add interactive plotting functions: :func:`~stlearn.pl.gene_plot_interactive`, :func:`~stlearn.pl.cluster_plot_interactive`, :func:`~stlearn.pl.het_plot_interactive`
7 | - Add basic unittest (will add more in the future).
8 | - Add `'contour'` parameter to use contour plot in :func:`~stlearn.pl.gene_plot` and :func:`~stlearn.pl.het_plot`.
9 | - Add :func:`~stlearn.convert_scanpy` to convert object from scanpy to stLearn.
10 |
11 | .. rubric:: Bug fixes
12 |
13 | - Refactor :func:`~stlearn.pl.gene_plot`
14 | - Refactor :func:`~stlearn.pl.cluster_plot`
15 | - Refactor :func:`~stlearn.pl.het_plot`
16 | - Fixed issue with `networkx` object cannot write `h5ad` file.
17 |
--------------------------------------------------------------------------------
/docs/release_notes/0.4.6.rst:
--------------------------------------------------------------------------------
1 | 0.4.0 `2022-02-03`
2 | ~~~~~~~~~~~~~~~~~~~~~~~~~
3 |
4 | .. rubric:: Feature
5 |
6 | - Upgrade stSME, PSTS and CCI analysis methods.
7 |
8 | - Add CCI analysis functions: :func:`~stlearn.tl.cci.load_lrs`, :func:`~stlearn.tl.cci.grid`, :func:`~stlearn.tl.cci.run`, :func:`~stlearn.tl.cci.adj_pvals`, :func:`~stlearn.tl.cci.run_lr_go`, :func:`~stlearn.pl.lr_summary`, :func:`~stlearn.pl.lr_diagnostics`, :func:`~stlearn.pl.lr_n_spots`, :func:`~stlearn.pl.lr_go`, :func:`~stlearn.pl.lr_result_plot`, :func:`~stlearn.pl.lr_plot`, :func:`~stlearn.pl.cci_check`, :func:`~stlearn.pl.ccinet_plot`, :func:`~stlearn.pl.lr_chord_plot`, :func:`~stlearn.pl.lr_cci_map`, :func:`~stlearn.pl.cci_map`, :func:`~stlearn.pl.lr_plot_interactive`, :func:`~stlearn.pl.spatialcci_plot_interactive`
9 |
--------------------------------------------------------------------------------
/docs/release_notes/index.rst:
--------------------------------------------------------------------------------
1 | Release notes
2 | ===================================================
3 |
4 | Version 0.4.9
5 | ---------------------------
6 |
7 | .. include:: 0.4.10.rst
8 |
9 | .. include:: 0.4.6.rst
10 |
11 | .. include:: 0.3.2.rst
12 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | -r ../requirements.txt
2 | ipyvolume
3 | ipywebrtc
4 | ipywidgets
5 | jupyter_sphinx
6 | nbclean
7 | nbformat
8 | nbsphinx
9 | pygments
10 | recommonmark
11 | sphinx
12 | sphinx-autodoc-typehints
13 | sphinx_gallery==0.10.1
14 | sphinx_rtd_theme
15 | typing_extensions
16 |
--------------------------------------------------------------------------------
/docs/tutorials.rst:
--------------------------------------------------------------------------------
1 | Tutorials
2 | ===========================
3 |
4 | .. nbgallery::
5 | :caption: Main features:
6 |
7 | tutorials/stSME_clustering
8 | tutorials/stSME_comparison
9 | tutorials/Pseudo-time-space-tutorial
10 | tutorials/stLearn-CCI
11 | tutorials/Xenium_PSTS
12 | tutorials/Xenium_CCI
13 |
14 | .. nbgallery::
15 | :caption: Visualisation and additional functionalities:
16 |
17 | tutorials/Interactive_plot
18 | tutorials/Core_plots
19 | tutorials/ST_deconvolution_visualization
20 | tutorials/Integration_multiple_datasets
21 |
22 |
23 | .. nbgallery::
24 | :caption: Supporting platforms:
25 |
26 |
27 | tutorials/Read_MERFISH
28 | tutorials/Read_seqfish
29 | tutorials/Working-with-Old-Spatial-Transcriptomics-data
30 | tutorials/Read_slideseq
31 |
32 | .. nbgallery::
33 | :caption: Integration with other spatial tools:
34 |
35 | tutorials/Read_any_data
36 | tutorials/Working_with_scanpy
37 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | bokeh>= 2.4.2
2 | click>=8.0.4
3 | leidenalg
4 | louvain
5 | numba<=0.57.1
6 | numpy>=1.18,<1.22
7 | Pillow>=9.0.1
8 | scanpy>=1.8.2
9 | scikit-image>=0.19.2
10 | tensorflow
11 |
--------------------------------------------------------------------------------
/resource/README.md:
--------------------------------------------------------------------------------
1 | **This folder** contains different stlearn tutorials for performing different analysis tasks of spatial transcriptomics data. The tutorials are being actively updated. The official tutorial versions will be hosted in another site linked to this repository.
2 |
--------------------------------------------------------------------------------
/resource/connectomedb2020.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/resource/connectomedb2020.txt
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bumpversion]
2 | current_version = 0.4.11
3 | commit = True
4 | tag = True
5 |
6 | [bumpversion:file:setup.py]
7 | search = version='{current_version}'
8 | replace = version='{new_version}'
9 |
10 | [bumpversion:file:stlearn/__init__.py]
11 | search = __version__ = '{current_version}'
12 | replace = __version__ = '{new_version}'
13 |
14 | [bdist_wheel]
15 | universal = 1
16 |
17 | [flake8]
18 | exclude = docs
19 |
20 | [aliases]
21 | # Define setup.py command aliases here
22 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """The setup script."""
4 |
5 | from setuptools import setup, find_packages
6 |
7 | with open("README.md", encoding="utf8") as readme_file:
8 | readme = readme_file.read()
9 |
10 | with open("HISTORY.rst") as history_file:
11 | history = history_file.read()
12 |
13 | with open("requirements.txt") as f:
14 | requirements = f.read().splitlines()
15 |
16 |
17 | setup_requirements = []
18 |
19 | test_requirements = []
20 |
21 | setup(
22 | author="Genomics and Machine Learning lab",
23 | author_email="duy.pham@uq.edu.au",
24 | python_requires=">=3.7",
25 | classifiers=[
26 | "Development Status :: 2 - Pre-Alpha",
27 | "Intended Audience :: Developers",
28 | "License :: OSI Approved :: BSD License",
29 | "Natural Language :: English",
30 | "Programming Language :: Python :: 3",
31 | "Programming Language :: Python :: 3.7",
32 | "Programming Language :: Python :: 3.8",
33 | ],
34 | description="A downstream analysis toolkit for Spatial Transcriptomic data",
35 | entry_points={
36 | "console_scripts": [
37 | "stlearn=stlearn.app.cli:main",
38 | ],
39 | },
40 | install_requires=requirements,
41 | license="BSD license",
42 | long_description=readme + "\n\n" + history,
43 | long_description_content_type="text/markdown",
44 | include_package_data=True,
45 | keywords="stlearn",
46 | name="stlearn",
47 | packages=find_packages(include=["stlearn", "stlearn.*"]),
48 | setup_requires=setup_requirements,
49 | test_suite="tests",
50 | tests_require=test_requirements,
51 | url="https://github.com/BiomedicalMachineLearning/stLearn",
52 | version="0.4.11",
53 | zip_safe=False,
54 | )
55 |
--------------------------------------------------------------------------------
/stlearn/__init__.py:
--------------------------------------------------------------------------------
1 | """Top-level package for stLearn."""
2 |
3 | __author__ = """Genomics and Machine Learning lab"""
4 | __email__ = "duy.pham@uq.edu.au"
5 | __version__ = "0.4.11"
6 |
7 |
8 | from . import add
9 | from . import pp
10 | from . import em
11 | from . import tl
12 | from . import pl
13 | from . import spatial
14 | from . import datasets
15 |
16 | # Wrapper
17 |
18 | from .wrapper.read import ReadSlideSeq
19 | from .wrapper.read import Read10X
20 | from .wrapper.read import ReadOldST
21 | from .wrapper.read import ReadMERFISH
22 | from .wrapper.read import ReadSeqFish
23 | from .wrapper.read import ReadXenium
24 | from .wrapper.read import create_stlearn
25 |
26 | from ._settings import settings
27 | from .wrapper.convert_scanpy import convert_scanpy
28 | from .wrapper.concatenate_spatial_adata import concatenate_spatial_adata
29 |
30 | # from . import cli
31 |
--------------------------------------------------------------------------------
/stlearn/__main__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Package entry point."""
4 |
5 |
6 | from stlearn.app import main
7 |
8 |
9 | if __name__ == "__main__": # pragma: no cover
10 | main()
11 |
--------------------------------------------------------------------------------
/stlearn/_compat.py:
--------------------------------------------------------------------------------
1 | try:
2 | from typing import Literal
3 | except ImportError:
4 | try:
5 | from typing_extensions import Literal
6 | except ImportError:
7 |
8 | class LiteralMeta(type):
9 | def __getitem__(cls, values):
10 | if not isinstance(values, tuple):
11 | values = (values,)
12 | return type("Literal_", (Literal,), dict(__args__=values))
13 |
14 | class Literal(metaclass=LiteralMeta):
15 | pass
16 |
--------------------------------------------------------------------------------
/stlearn/_datasets/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/_datasets/__init__.py
--------------------------------------------------------------------------------
/stlearn/_datasets/_datasets.py:
--------------------------------------------------------------------------------
1 | import scanpy as sc
2 | from .._settings import settings
3 | from pathlib import Path
4 | from anndata import AnnData
5 |
6 |
7 | def example_bcba() -> AnnData:
8 | """\
9 | Download processed BCBA data (10X genomics published data).
10 | Reference: https://support.10xgenomics.com/spatial-gene-expression/datasets/1.1.0/V1_Breast_Cancer_Block_A_Section_1
11 | """
12 | settings.datasetdir.mkdir(exist_ok=True)
13 | filename = settings.datasetdir / "example_bcba.h5"
14 | url = "https://www.dropbox.com/s/u3m2f16mvdom1am/example_bcba.h5ad?dl=1"
15 | if not filename.is_file():
16 | sc.readwrite._download(url=url, path=filename)
17 | adata = sc.read_h5ad(filename)
18 | return adata
19 |
--------------------------------------------------------------------------------
/stlearn/add.py:
--------------------------------------------------------------------------------
1 | from .adds.add_image import image
2 | from .adds.add_positions import positions
3 | from .adds.parsing import parsing
4 | from .adds.add_lr import lr
5 | from .adds.annotation import annotation
6 | from .adds.add_labels import labels
7 | from .adds.add_deconvolution import add_deconvolution
8 | from .adds.add_mask import add_mask
9 | from .adds.add_mask import apply_mask
10 | from .adds.add_loupe_clusters import add_loupe_clusters
11 |
--------------------------------------------------------------------------------
/stlearn/adds/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/adds/__init__.py
--------------------------------------------------------------------------------
/stlearn/adds/add_deconvolution.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | from anndata import AnnData
3 | import pandas as pd
4 | import numpy as np
5 | from pathlib import Path
6 |
7 |
8 | def add_deconvolution(
9 | adata: AnnData,
10 | annotation_path: Union[Path, str],
11 | copy: bool = False,
12 | ) -> Optional[AnnData]:
13 |
14 | """\
15 | Adding label transfered from Seurat
16 |
17 | Parameters
18 | ----------
19 | adata
20 | Annotated data matrix.
21 | annotation_path
22 | Path of the output of label transfer result by Seurat
23 | copy
24 | Return a copy instead of writing to adata.
25 | Returns
26 | -------
27 | Depending on `copy`, returns or updates `adata` with the following fields.
28 | **[cluster method name]_anno** : `adata.obs` field
29 | The annotation of cluster results.
30 |
31 | """
32 | label = pd.read_csv(annotation_path, index_col=0)
33 | label = label[adata.obs_names]
34 |
35 | adata.obsm["deconvolution"] = label[adata.obs.index].T
36 |
--------------------------------------------------------------------------------
/stlearn/adds/add_image.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | from anndata import AnnData
3 | from matplotlib import pyplot as plt
4 | from pathlib import Path
5 | import os
6 | from PIL import Image
7 |
8 | Image.MAX_IMAGE_PIXELS = None
9 |
10 |
11 | def image(
12 | adata: AnnData,
13 | imgpath: Union[Path, str],
14 | library_id: str,
15 | quality: str = "hires",
16 | scale: float = 1.0,
17 | visium: bool = False,
18 | spot_diameter_fullres: float = 50,
19 | copy: bool = False,
20 | ) -> Optional[AnnData]:
21 |
22 | """\
23 | Adding image data to the Anndata object
24 |
25 | Parameters
26 | ----------
27 | adata
28 | Annotated data matrix.
29 | imgpath
30 | Image path.
31 | library_id
32 | Identifier for the visium library. Can be modified when concatenating multiple adata objects.
33 | scale
34 | Set scale factor.
35 | quality
36 | Set quality that convert to stlearn to use. Store in anndata.obs['imagecol' & 'imagerow'].
37 | visium
38 | Is this anndata read from Visium platform or not.
39 | copy
40 | Return a copy instead of writing to adata.
41 | Returns
42 | -------
43 | Depending on `copy`, returns or updates `adata` with the following fields.
44 | **tissue_img** : `adata.uns` field
45 | Array format of image, saving by Pillow package.
46 | """
47 |
48 | if imgpath is not None and os.path.isfile(imgpath):
49 | try:
50 | img = plt.imread(imgpath, 0)
51 |
52 | if visium:
53 | adata.uns["spatial"][library_id]["images"][quality] = img
54 | else:
55 | adata.uns["spatial"] = {}
56 | adata.uns["spatial"][library_id] = {}
57 | adata.uns["spatial"][library_id]["images"] = {}
58 | adata.uns["spatial"][library_id]["images"][quality] = img
59 | adata.uns["spatial"][library_id]["use_quality"] = quality
60 | adata.uns["spatial"][library_id]["scalefactors"] = {}
61 | adata.uns["spatial"][library_id]["scalefactors"][
62 | "tissue_" + quality + "_scalef"
63 | ] = scale
64 | adata.uns["spatial"][library_id]["scalefactors"][
65 | "spot_diameter_fullres"
66 | ] = spot_diameter_fullres
67 | adata.obsm["spatial"] = adata.obs[["imagecol", "imagerow"]].values
68 | adata.obs[["imagecol", "imagerow"]] = adata.obsm["spatial"] * scale
69 |
70 | print("Added tissue image to the object!")
71 |
72 | return adata if copy else None
73 | except:
74 | raise ValueError(
75 | f"""\
76 | {imgpath!r} does not end on a valid extension.
77 | """
78 | )
79 | else:
80 | raise ValueError(
81 | f"""\
82 | {imgpath!r} does not end on a valid extension.
83 | """
84 | )
85 | return adata if copy else None
86 |
--------------------------------------------------------------------------------
/stlearn/adds/add_labels.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | from anndata import AnnData
3 | from pathlib import Path
4 | import os
5 | import pandas as pd
6 | import numpy as np
7 | from natsort import natsorted
8 |
9 |
10 | def labels(
11 | adata: AnnData,
12 | label_filepath: str = None,
13 | index_col: int = 0,
14 | use_label: str = None,
15 | sep: str = "\t",
16 | copy: bool = False,
17 | ) -> Optional[AnnData]:
18 | """\
19 | Add label transfer results into AnnData object
20 |
21 | Parameters
22 | ----------
23 | adata: AnnData The data object to add L-R info into
24 | label_filepath: str The path to the label transfer results file
25 | use_label: str Where to store the label_transfer results, defaults to 'predictions' in adata.obs & 'label_transfer' in adata.uns.
26 | sep: str Separator of the csv file
27 | copy: bool Copy flag indicating copy or direct edit
28 |
29 | Returns
30 | -------
31 | adata: AnnData The data object that L-R added into
32 |
33 | """
34 | labels = pd.read_csv(label_filepath, index_col=index_col, sep=sep)
35 | uns_key = "label_transfer" if type(use_label) == type(None) else use_label
36 | adata.uns[uns_key] = labels.drop(["predicted.id", "prediction.score.max"], axis=1)
37 |
38 | key_add = "predictions" if type(use_label) == type(None) else use_label
39 | key_source = "predicted.id"
40 | adata.obs[key_add] = pd.Categorical(
41 | values=np.array(labels[key_source]).astype("U"),
42 | categories=natsorted(labels[key_source].unique().astype("U")),
43 | )
44 |
45 | print(f"label transfer results added to adata.uns['{uns_key}']")
46 | print(f"predicted label added to adata.obs['{key_add}'].")
47 |
48 | return adata if copy else None
49 |
--------------------------------------------------------------------------------
/stlearn/adds/add_loupe_clusters.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | from anndata import AnnData
3 | import pandas as pd
4 | import numpy as np
5 | import stlearn
6 | from pathlib import Path
7 | from natsort import natsorted
8 |
9 |
10 | def add_loupe_clusters(
11 | adata: AnnData,
12 | loupe_path: Union[Path, str],
13 | key_add: str = "multiplex",
14 | copy: bool = False,
15 | ) -> Optional[AnnData]:
16 |
17 | """\
18 | Adding label transfered from Seurat
19 |
20 | Parameters
21 | ----------
22 | adata
23 | Annotated data matrix.
24 | annotation_path
25 | Path of the output of label transfer result by Seurat
26 | use_label
27 | Choosing cluster type.
28 | threshold
29 | Quantile threshold of label
30 | copy
31 | Return a copy instead of writing to adata.
32 | Returns
33 | -------
34 | Depending on `copy`, returns or updates `adata` with the following fields.
35 | **[cluster method name]_anno** : `adata.obs` field
36 | The annotation of cluster results.
37 |
38 | """
39 | label = pd.read_csv(loupe_path)
40 |
41 | adata.obs[key_add] = pd.Categorical(
42 | values=np.array(label[key_add]).astype("U"),
43 | categories=natsorted(label[key_add].unique().astype("U")),
44 | )
45 |
--------------------------------------------------------------------------------
/stlearn/adds/add_lr.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | from anndata import AnnData
3 | from pathlib import Path
4 | import os
5 | import pandas as pd
6 |
7 |
8 | def lr(
9 | adata: AnnData,
10 | db_filepath: str = None,
11 | sep: str = "\t",
12 | source: str = "connectomedb",
13 | copy: bool = False,
14 | ) -> Optional[AnnData]:
15 | """Add significant Ligand-Receptor pairs into AnnData object
16 |
17 | Parameters
18 | ----------
19 | adata: AnnData The data object to add L-R info into
20 | db_filepath: str The path to the CPDB results file
21 | sep: str Separator of the CPDB results file
22 | source: str Source of LR database (default: connectomedb, can also support 'cellphonedb')
23 | copy: bool Copy flag indicating copy or direct edit
24 |
25 | Returns
26 | -------
27 | adata: AnnData The data object that L-R added into
28 |
29 | """
30 |
31 | if source == "cellphonedb":
32 | cpdb = pd.read_csv(db_filepath, sep=sep)
33 | adata.uns["cpdb"] = cpdb
34 | lr = cpdb["interacting_pair"].to_list()
35 | lr2 = [i for i in lr if "complex" not in i]
36 | lr3 = [i for i in lr2 if " " not in i]
37 | lr4 = [i for i in lr3 if i.count("_") == 1]
38 | adata.uns["lr"] = lr4
39 | print("cpdb results added to adata.uns['cpdb']")
40 | print("Added ligand receptor pairs to adata.uns['lr'].")
41 |
42 | elif source == "connectomedb":
43 | ctdb = pd.read_csv(db_filepath, sep=sep, quotechar='"', encoding="latin1")
44 | adata.uns["lr"] = (
45 | ctdb["Ligand gene symbol"] + "_" + ctdb["Receptor gene symbol"]
46 | ).values.tolist()
47 | print("connectomedb results added to adata.uns['ctdb']")
48 | print("Added ligand receptor pairs to adata.uns['lr'].")
49 |
50 | return adata if copy else None
51 |
--------------------------------------------------------------------------------
/stlearn/adds/add_positions.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | from anndata import AnnData
3 | import pandas as pd
4 | from pathlib import Path
5 | import os
6 |
7 |
8 | def positions(
9 | adata: AnnData,
10 | position_filepath: Union[Path, str] = None,
11 | scale_filepath: Union[Path, str] = None,
12 | quality: str = "low",
13 | copy: bool = False,
14 | ) -> Optional[AnnData]:
15 |
16 | """\
17 | Adding spatial information into the Anndata object
18 |
19 | Parameters
20 | ----------
21 | adata
22 | Annotated data matrix.
23 | position_filepath
24 | Path to tissue_positions_list file.
25 | scale_filepath
26 | Path to scalefactors_json file.
27 | quality
28 | Choosing low or high resolution image.
29 | copy
30 | Return a copy instead of writing to adata.
31 | Returns
32 | -------
33 | Depending on `copy`, returns or updates `adata` with the following fields.
34 | **imagecol** and **imagerow** : `adata.obs` field
35 | Spatial information of the tissue image.
36 | """
37 |
38 | tissue_positions = pd.read_csv(position_filepath, header=None)
39 | tissue_positions.columns = [
40 | "barcode",
41 | "tissue",
42 | "row",
43 | "col",
44 | "imagerow",
45 | "imagecol",
46 | ]
47 | import json
48 |
49 | with open(scale_filepath) as json_file:
50 | scale_factors = json.load(json_file)
51 |
52 | if quality == "low":
53 | tissue_positions["imagerow"] = (
54 | tissue_positions["imagerow"] * scale_factors["tissue_lowres_scalef"]
55 | )
56 | tissue_positions["imagecol"] = (
57 | tissue_positions["imagecol"] * scale_factors["tissue_lowres_scalef"]
58 | )
59 | elif quality == "high":
60 | tissue_positions["imagerow"] = (
61 | tissue_positions["imagerow"] * scale_factors["tissue_hires_scalef"]
62 | )
63 | tissue_positions["imagecol"] = (
64 | tissue_positions["imagecol"] * scale_factors["tissue_hires_scalef"]
65 | )
66 |
67 | tmp = adata.obs.merge(
68 | tissue_positions.reset_index().set_index(["barcode"]),
69 | left_index=True,
70 | right_index=True,
71 | how="left",
72 | ).reset_index()[["imagerow", "imagecol"]]
73 |
74 | adata.obs["imagerow"] = tmp["imagerow"].values
75 | adata.obs["imagecol"] = tmp["imagecol"].values
76 |
77 | return adata if copy else None
78 |
--------------------------------------------------------------------------------
/stlearn/adds/annotation.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union, List
2 | from anndata import AnnData
3 | from matplotlib import pyplot as plt
4 | from pathlib import Path
5 | import os
6 |
7 |
8 | def annotation(
9 | adata: AnnData,
10 | label_list: List[str],
11 | use_label: str = "louvain",
12 | copy: bool = False,
13 | ) -> Optional[AnnData]:
14 | """\
15 | Adding annotation for cluster
16 |
17 | Parameters
18 | ----------
19 | adata
20 | Annotated data matrix.
21 | label_list
22 | List of the labels which assigned to current cluster result.
23 | use_label
24 | Choosing cluster type.
25 | copy
26 | Return a copy instead of writing to adata.
27 | Returns
28 | -------
29 | Depending on `copy`, returns or updates `adata` with the following fields.
30 | **[cluster method name]_anno** : `adata.obs` field
31 | The annotation of cluster results.
32 | """
33 |
34 | if label_list is None:
35 | raise ValueError("Please give the label list!")
36 |
37 | if len(label_list) != len(adata.obs[use_label].unique()):
38 | raise ValueError("Please give the correct number of label list!")
39 |
40 | adata.obs[use_label + "_anno"] = adata.obs[use_label].cat.rename_categories(
41 | label_list
42 | )
43 |
44 | print("The annotation is added to adata.obs['" + use_label + "_anno" + "']")
45 |
46 | return adata if copy else None
47 |
--------------------------------------------------------------------------------
/stlearn/adds/parsing.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | from anndata import AnnData
3 | from matplotlib import pyplot as plt
4 | from pathlib import Path
5 | import os
6 | import sys
7 | import numpy as np
8 |
9 |
10 | def parsing(
11 | adata: AnnData,
12 | coordinates_file: Union[Path, str],
13 | copy: bool = True,
14 | ) -> Optional[AnnData]:
15 |
16 | """\
17 | Parsing the old spaital transcriptomics data
18 |
19 | Parameters
20 | ----------
21 | adata
22 | Annotated data matrix.
23 | coordinates_file
24 | Coordinate file generated by st_spot_detector.
25 | copy
26 | Return a copy instead of writing to adata.
27 | Returns
28 | -------
29 | Depending on `copy`, returns or updates `adata` with the following fields.
30 | **imagecol** and **imagerow** : `adata.obs` field
31 | Spatial information of the tissue image.
32 | """
33 |
34 | # Get a map of the new coordinates
35 | new_coordinates = dict()
36 | with open(coordinates_file, "r") as filehandler:
37 | for line in filehandler.readlines():
38 | tokens = line.split()
39 | assert len(tokens) >= 6 or len(tokens) == 4
40 | if tokens[0] != "x":
41 | old_x = int(tokens[0])
42 | old_y = int(tokens[1])
43 | new_x = round(float(tokens[2]), 2)
44 | new_y = round(float(tokens[3]), 2)
45 | if len(tokens) >= 6:
46 | pixel_x = float(tokens[4])
47 | pixel_y = float(tokens[5])
48 | new_coordinates[(old_x, old_y)] = (pixel_x, pixel_y)
49 | else:
50 | raise ValueError(
51 | "Error, output format is pixel coordinates but\n "
52 | "the coordinates file only contains 4 columns\n"
53 | )
54 |
55 | counts_table = adata.to_df()
56 | new_index_values = list()
57 |
58 | imgcol = []
59 | imgrow = []
60 | for index in counts_table.index:
61 | tokens = index.split("x")
62 | x = int(tokens[0])
63 | y = int(tokens[1])
64 | try:
65 | new_x, new_y = new_coordinates[(x, y)]
66 | imgcol.append(new_x)
67 | imgrow.append(new_y)
68 |
69 | new_index_values.append("{0}x{1}".format(new_x, new_y))
70 | except KeyError:
71 | counts_table.drop(index, inplace=True)
72 |
73 | # Assign the new indexes
74 | # counts_table.index = new_index_values
75 |
76 | # Remove genes that have now a total count of zero
77 | counts_table = counts_table.transpose()[counts_table.sum(axis=0) > 0].transpose()
78 |
79 | adata = AnnData(counts_table)
80 |
81 | adata.obs["imagecol"] = imgcol
82 | adata.obs["imagerow"] = imgrow
83 |
84 | adata.obsm["spatial"] = np.c_[[imgcol, imgrow]].reshape(-1, 2)
85 |
86 | return adata if copy else None
87 |
--------------------------------------------------------------------------------
/stlearn/app/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/app/__init__.py
--------------------------------------------------------------------------------
/stlearn/app/cli.py:
--------------------------------------------------------------------------------
1 | import click
2 | from .. import __version__
3 |
4 | import os
5 |
6 |
7 | @click.group(
8 | name="stlearn",
9 | subcommand_metavar="COMMAND ",
10 | options_metavar="",
11 | context_settings=dict(max_content_width=85, help_option_names=["-h", "--help"]),
12 | )
13 | @click.help_option("--help", "-h", help="Show this message and exit.")
14 | @click.version_option(
15 | version=__version__,
16 | prog_name="stlearn",
17 | message="[%(prog)s] Version %(version)s",
18 | help="Show the software version and exit.",
19 | )
20 | def main():
21 | os._exit
22 | click.echo("Please run `stlearn launch` to start the web app")
23 |
24 |
25 | @main.command(short_help="Launch the stlearn interactive app")
26 | def launch():
27 | from .app import app
28 |
29 | try:
30 | app.run(host="0.0.0.0", port=5000, debug=True, use_reloader=False)
31 | except OSError as e:
32 | if e.errno == errno.EADDRINUSE:
33 | raise click.ClickException(
34 | "Port is in use, please specify an open port using the --port flag."
35 | ) from e
36 | raise
37 |
--------------------------------------------------------------------------------
/stlearn/app/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==2.3.2
2 | flask_wtf==1.0.0
3 | markupsafe==2.1.0
4 | WTForms==3.0.1
5 |
--------------------------------------------------------------------------------
/stlearn/app/source/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/app/source/__init__.py
--------------------------------------------------------------------------------
/stlearn/app/source/forms/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/app/source/forms/__init__.py
--------------------------------------------------------------------------------
/stlearn/app/source/forms/form_validators.py:
--------------------------------------------------------------------------------
1 | """ Contains different kinds of form validators.
2 | """
3 | from wtforms.validators import ValidationError
4 |
5 |
6 | class CheckNumberRange(object):
7 | def __init__(self, lower, upper, hint=""):
8 | self.lower = lower
9 | self.upper = upper
10 | self.hint = hint
11 |
12 | def __call__(self, form, field):
13 |
14 | if field.data is not None:
15 | if not (self.lower <= float(field.data) <= self.upper):
16 | if self.hint:
17 | raise ValidationError(self.hint)
18 | else:
19 | raise ValidationError("Not in correct range")
20 |
--------------------------------------------------------------------------------
/stlearn/app/source/forms/helper_functions.py:
--------------------------------------------------------------------------------
1 | # Purpose of this script is to write the functions that help facilitate
2 | # subsetting of the data depending on the users input
3 | import numpy
4 |
5 |
6 | def printOut(text, fileName="stdout.txt", close=True, file=None):
7 | """Prints to the specified file name. Used for debugging.
8 | If close is Fale, returns open file.
9 | """
10 |
11 | if type(file) == type(None):
12 | file = open(fileName, "w")
13 |
14 | print(text, file=file)
15 |
16 | if close:
17 | file.close()
18 | else:
19 | return file
20 |
21 |
22 | def filterOptions(metaDataSets, options):
23 | """Returns options that overlap with keys in metaDataSets dictionary"""
24 | if type(options) == type(None):
25 | options = list(metaDataSets.keys())
26 | else:
27 | options = [option for option in options if option in metaDataSets.keys()]
28 |
29 | return options
30 |
31 |
32 | def addChoices(metaDataSets, options, elementValues):
33 | """Helper function which generates choices for SelectMultiField"""
34 | for option in options:
35 | choices = [(optioni, optioni) for optioni in metaDataSets[option]]
36 | elementValues.append(choices)
37 |
38 |
39 | # TODO update this so has 'options' as input
40 | def subsetSCA(sca, subsetForm):
41 | """Subsets the SCA based on the selected fields and the inputted genes."""
42 |
43 | # Getting the attached fields from the form which refer subset options #
44 | options = filterOptions(sca.metaDataSets, subsetForm.elements)
45 |
46 | # Subsetting based on selection #
47 | conditionSelection = {} # selection dictionary
48 | for i, option in enumerate(options):
49 | selected = getattr(subsetForm, option).data
50 | if len(selected) != 0:
51 | conditionSelection[option] = selected
52 |
53 | # Subsetting based on conditions #
54 | if len(conditionSelection) != 0:
55 | sca = sca.createConditionSubset("subset", conditionSelection)
56 |
57 | # Subsetting based on inputted genes #
58 | geneList = getattr(subsetForm, "Select Cells Expressing Gene/s").data.split(",")
59 | if geneList != [""]:
60 | # Filter to just the genes which express all of the inputted genes #
61 | sca = sca.createGeneExprsSubset(
62 | "subset", genesToFilter=geneList, cutoff=0, keep=True, useOr=False
63 | )
64 |
65 | return sca, conditionSelection, geneList
66 |
--------------------------------------------------------------------------------
/stlearn/app/source/forms/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """Helper utilities and decorators."""
3 | from flask import flash
4 | import matplotlib.pyplot as plt
5 |
6 |
7 | def flash_errors(form, category="warning"):
8 | """Flash all errors for a form."""
9 | for field, errors in form.errors.items():
10 | for error in errors:
11 | flash(getattr(form, field).label.text + " - " + error + ", category")
12 |
13 |
14 | def get_all_paths(adata):
15 |
16 | import networkx as nx
17 |
18 | G = nx.from_numpy_array(adata.uns["paga"]["connectivities_tree"].toarray())
19 | mapping = {int(k): v for k, v in zip(G.nodes, adata.obs.clusters.cat.categories)}
20 | G = nx.relabel_nodes(G, mapping)
21 |
22 | all_paths = []
23 | for source in G.nodes:
24 | for target in G.nodes:
25 | paths = nx.all_simple_paths(G, source=source, target=target)
26 | for path in paths:
27 | all_paths.append(path)
28 |
29 | import numpy as np
30 |
31 | all_paths = list(map(lambda x: " - ".join(np.array(x).astype(str)), all_paths))
32 |
33 | return all_paths
34 |
--------------------------------------------------------------------------------
/stlearn/app/source/forms/view_helpers.py:
--------------------------------------------------------------------------------
1 | """ Helper functions for views.py.
2 | """
3 |
4 | import numpy
5 |
6 |
7 | def getVal(form, element):
8 | return getattr(form, element).data
9 |
10 |
11 | def getData(form):
12 | """Retrieves the data from the form and places into dictionary."""
13 | params = {}
14 | form_elements = form.elements
15 | form_fields = form.element_fields
16 | for i, element in enumerate(form_elements):
17 | if form_fields[i] != "Title":
18 | data = getVal(form, element)
19 | params[element] = data
20 | return params
21 |
22 |
23 | def getLR(lr_input, gene_names):
24 | """Returns list of lr_inputs and error message, if any."""
25 | if lr_input == "":
26 | return None, "ERROR: LR pairs required input."
27 |
28 | try:
29 | lrs = [lr.strip(" ") for lr in lr_input.split(",")]
30 | absent_genes = []
31 | for lr in lrs:
32 | genes = lr.split("_")
33 | absent_genes.extend([gene for gene in genes if gene not in gene_names])
34 |
35 | if len(absent_genes) != 0:
36 | return None, f"ERROR: inputted genes not found {absent_genes}."
37 |
38 | return lrs, ""
39 |
40 | except:
41 | return None, "ERROR: LR pairs misformatted."
42 |
--------------------------------------------------------------------------------
/stlearn/app/source/readme.md:
--------------------------------------------------------------------------------
1 | # Pre-processing Form Design Notes
2 | Flow of data:
3 |
4 | app.py/preprocessing()
5 | -> source/forms/views.py/run_preprocessing(request, adata, step_log)
6 | -> source/forms/forms.py/getPreprocessForm()
7 | -> templates/preprocessing.html
8 | -> templates/superform.html
9 |
10 | Notes:
11 |
12 | * step_log defined in app.py, keeps track whether pre-processing was run.
13 | -> If not run, then run_preprocessing shows just the form.
14 | -> If has run, shows banner that preprocessing complete.
15 |
16 | * If attempt to run_preprocessing() when adata not yet loaded, shows banner
17 | indicating need to upload the data first.
18 |
19 | * source/forms/forms.py/getPreprocessForm() generates a WTForm class using a
20 | general WTForm generator, as defined in:
21 | source/forms/forms.py/createSuperForm()
22 |
23 | * templates/preprocessing.html is the preprocessing page, which also injects
24 | in a form to display using templates/superform.html.
25 |
26 | * templates/superform.html renders a general WTForm that was created using
27 | the source/forms/forms.py/createSuperForm() function, thereby allowing
28 | easy generation of new forms if need to add extra information.
29 |
--------------------------------------------------------------------------------
/stlearn/app/static/css/style.css:
--------------------------------------------------------------------------------
1 | .container-fluid {
2 | width: 80%;
3 | padding-right: 15px;
4 | padding-left: 15px;
5 | margin-right: auto;
6 | margin-left: auto;
7 | }
8 |
9 | .right {
10 | float: right;
11 | width: 300px;
12 | border: 3px solid #73AD21;
13 | padding: 10px;
14 | }
15 |
16 | .card {
17 | border: 0;
18 | margin-bottom: 30px;
19 | margin-top: 10px;
20 | border-radius: 6px;
21 | color: #333;
22 | background: #fff;
23 | width: 100%;
24 | box-shadow: 0 2px 2px 0 rgb(0 0 0 / 14%), 0 3px 1px -2px rgb(0 0 0 / 20%), 0 1px 5px 0 rgb(0 0 0 / 12%);
25 | }
26 |
27 | .main-panel>.content {
28 | margin-top: 0px;
29 | padding: 30px 15px;
30 | min-height: calc(100vh - 123px);
31 | }
32 |
33 | a.disabled, fieldset:disabled a {
34 | pointer-events: none;
35 | background-color: #D8D8D8;
36 | }
37 |
38 |
39 | .list-group-item {
40 | position: relative;
41 | display: block;
42 | padding: 0.25rem 1.25rem;
43 | margin-bottom: 0;
44 | background-color: inherit;
45 | border: 0 solid rgba(0,0,0,.125);
46 | }
47 |
48 | #Cluster\ Select {
49 | height: 150px
50 | }
51 |
52 | #overlay { width:100px;
53 | height: 100px;
54 | position: fixed;
55 | top: 50%;
56 | left: 50%;
57 | z-index: -1;
58 | }
59 |
60 | #loading { width:100px;
61 | height: 200px;
62 | position: fixed;
63 | top: 50%;
64 | left: 50%;
65 | }
66 |
67 | .btn, .btn.btn-default {
68 | color: #fff;
69 | background-color: #9124a3;
70 | border-color: #9c27b0;
71 | box-shadow: 0 2px 2px 0 hsl(0deg 0% 60% / 14%), 0 3px 1px -2px hsl(0deg 0% 60% / 20%), 0 1px 5px 0 hsl(0deg 0% 60% / 12%);
72 | }
73 |
74 | .logging_window{
75 | display: block;
76 | padding: 9.5px;
77 | font-size: 13px;
78 | line-height: 1.42857143;
79 | color: #333;
80 | word-break: break-all;
81 | word-wrap: break-word;
82 | background-color: #f5f5f5;
83 | border: 1px solid #ccc;
84 | border-radius: 4px;
85 | width: 50%;
86 | margin: auto;
87 | }
88 |
89 | .sidebar {
90 | width: 285px;
91 | }
92 |
93 | .sidebar .sidebar-wrapper {
94 | width: 285px;
95 | }
96 |
--------------------------------------------------------------------------------
/stlearn/app/static/img/Settings.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/app/static/img/Settings.gif
--------------------------------------------------------------------------------
/stlearn/app/static/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/app/static/img/favicon.png
--------------------------------------------------------------------------------
/stlearn/app/static/img/loading_gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/app/static/img/loading_gif.gif
--------------------------------------------------------------------------------
/stlearn/app/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/app/templates/__init__.py
--------------------------------------------------------------------------------
/stlearn/app/templates/annotate_plot.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block content %}
3 |
4 |
8 |
9 | {{ script|safe }}
10 |
11 |
12 | Loading plot...
13 |
14 |
15 |
16 | {% endblock %}
17 |
18 | {% block status %}
19 | {% include "progress.html" %}
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/stlearn/app/templates/cci.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block content %}
4 |
5 |
8 |
9 |
10 | {# Gives the user errors if didn't fill out form correctly #}
11 | {% include "flash_header.html" %}
12 |
13 | {# Below is the form. #}
14 | {% with superForm=cci_form %}
15 | {% include "superform.html" %}
16 | {% endwith %}
17 |
18 |
19 |
20 | {% endblock %}
21 |
22 | {% block status %}
23 | {% include "progress.html" %}
24 | {% endblock %}
25 |
--------------------------------------------------------------------------------
/stlearn/app/templates/cci_old.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block content %}
4 |
5 |
8 |
9 |
10 | {# Gives the user errors if didn't fill out form correctly #}
11 | {% include "flash_header.html" %}
12 |
13 | {# Below is the form. #}
14 | {% with superForm=cci_form %}
15 | {% include "superform.html" %}
16 | {% endwith %}
17 |
18 |
19 | *Optional
20 |
21 | **Required
22 |
23 |
24 |
25 | {% endblock %}
26 |
27 | {% block status %}
28 | {% include "progress.html" %}
29 | {% endblock %}
30 |
--------------------------------------------------------------------------------
/stlearn/app/templates/cci_plot.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block content %}
3 |
4 |
8 |
9 | {{ script|safe }}
10 |
11 |
12 | Loading plot...
13 |
14 |
15 |
16 | {% endblock %}
17 |
18 | {% block status %}
19 | {% include "progress.html" %}
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/stlearn/app/templates/choose_cluster.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block content %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 | Cluster list:
16 |
17 |
28 |
29 |
30 |
31 |
32 | {% endblock %}
33 |
34 |
35 | {% block status %}
36 | {% include "progress.html" %}
37 | {% endblock %}
38 |
--------------------------------------------------------------------------------
/stlearn/app/templates/cluster_plot.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block content %}
3 |
4 |
8 |
9 | {{ script|safe }}
10 |
11 |
12 | Loading plot...
13 |
14 |
15 |
16 |
17 |
18 | {% endblock %}
19 |
20 | {% block status %}
21 | {% include "progress.html" %}
22 | {% endblock %}
23 |
--------------------------------------------------------------------------------
/stlearn/app/templates/clustering.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block content %}
3 |
4 |
7 |
8 |
9 | {# Below indicates whether clustering already completed #}
10 | {% include "flash_header.html" %}
11 |
12 | {# Below is the form. #}
13 | {% with superForm=clustering_form %}
14 | {% include "superform.html" %}
15 | {% endwith %}
16 |
17 |
18 |
19 |
20 | {% endblock %}
21 |
22 | {% block status %}
23 | {% include "progress.html" %}
24 | {% endblock %}
25 |
26 | {% block javascript %}
27 |
46 | {% endblock %}
47 |
--------------------------------------------------------------------------------
/stlearn/app/templates/dea.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block content %}
4 |
5 |
8 |
9 |
10 | {# Below indicates whether dea already completed #}
11 | {% include "flash_header.html" %}
12 |
13 | {# Below is the form. #}
14 | {% with superForm=dea_form %}
15 | {% include "superform.html" %}
16 | {% endwith %}
17 |
18 |
19 |
20 | {% endblock %}
21 |
22 | {% block status %}
23 | {% include "progress.html" %}
24 | {% endblock %}
25 |
--------------------------------------------------------------------------------
/stlearn/app/templates/flash_header.html:
--------------------------------------------------------------------------------
1 | {# Flashes message at the top of the page to the user.
2 | #}
3 |
4 | {% if flash_bool %}
5 |
6 | {% for message in get_flashed_messages() %}
7 |
8 | ×
9 | {{ message }}
10 |
11 | {% endfor %}
12 |
13 | {% block page_content %}{% endblock %}
14 |
15 | {% endif %}
16 |
--------------------------------------------------------------------------------
/stlearn/app/templates/gene_plot.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block content %}
3 |
4 |
8 |
9 | {{ script|safe }}
10 |
11 |
12 |
13 | Loading plot...
14 |
15 |
16 |
17 |
18 |
19 | {% endblock %}
20 |
21 | {% block status %}
22 | {% include "progress.html" %}
23 | {% endblock %}
24 |
--------------------------------------------------------------------------------
/stlearn/app/templates/lr.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block content %}
4 |
5 |
8 |
9 |
10 | {# Gives the user errors if didn't fill out form correctly #}
11 | {% include "flash_header.html" %}
12 |
13 | {# Below is the form. #}
14 | {% with superForm=lr_form %}
15 | {% include "superform.html" %}
16 | {% endwith %}
17 |
18 |
19 |
20 | {% endblock %}
21 |
22 | {% block status %}
23 | {% include "progress.html" %}
24 | {% endblock %}
25 |
--------------------------------------------------------------------------------
/stlearn/app/templates/lr_plot.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block content %}
3 |
4 |
8 |
9 | {{ script|safe }}
10 |
11 |
12 | Loading plot...
13 |
14 |
15 |
16 | {% endblock %}
17 |
18 | {% block status %}
19 | {% include "progress.html" %}
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/stlearn/app/templates/preprocessing.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block content %}
4 |
5 |
8 |
9 |
10 | {# Below indicates whether pre-processing already completed #}
11 | {% include "flash_header.html" %}
12 |
13 | {# Below is the form. #}
14 | {% with superForm=preprocess_form %}
15 | {% include "superform.html" %}
16 | {% endwith %}
17 |
18 |
19 |
20 | {% endblock %}
21 |
22 | {% block status %}
23 | {% include "progress.html" %}
24 | {% endblock %}
25 |
--------------------------------------------------------------------------------
/stlearn/app/templates/progress.html:
--------------------------------------------------------------------------------
1 | {# Code which displays the progress bar, indicating where in the analysis the
2 | user is.
3 | #}
4 |
5 |
6 | {% for key, value in step_log.items() %}
7 | {% if 'params' not in key %}
8 | {% if value[0] %}
9 | Success {{ value[1] }}
10 | {% else %}
11 | None {{ value[1] }}
12 | {% endif %}
13 | {% endif %}
14 | {% endfor %}
15 |
16 |
17 |
20 |
--------------------------------------------------------------------------------
/stlearn/app/templates/psts.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block content %}
3 |
4 |
7 |
8 |
9 |
10 |
13 |
14 |
15 | {# Below indicates whether clustering already completed #}
16 | {% include "flash_header.html" %}
17 |
18 | {# Below is the form. #}
19 | {% with superForm=psts_form %}
20 | {% include "superform.html" %}
21 | {% endwith %}
22 |
23 |
24 | {% endblock %}
25 |
26 | {% block status %}
27 | {% include "progress.html" %}
28 | {% endblock %}
29 |
--------------------------------------------------------------------------------
/stlearn/app/templates/spatial_cci_plot.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% block content %}
3 |
4 |
8 |
9 | {{ script|safe }}
10 |
11 |
12 | Loading plot...
13 |
14 |
15 |
16 | {% endblock %}
17 |
18 | {% block status %}
19 | {% include "progress.html" %}
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/stlearn/app/templates/superform.html:
--------------------------------------------------------------------------------
1 | {# Generalised, injectable html for rendering a WTForm generated using:
2 | source.forms.forms.createSuperForm()
3 | #}
4 |
5 | {% block content %}
6 |
7 | {# Pre-processing form #}
8 |
74 |
Processing...
75 |
76 | {% endblock %}
77 |
--------------------------------------------------------------------------------
/stlearn/app/templates/upload.html:
--------------------------------------------------------------------------------
1 |
2 | {% extends 'base.html' %}
3 |
4 | {% block content %}
5 |
6 |
7 |
10 |
11 |
12 |
30 |
Loading data...
31 |
32 |
33 |
34 |
35 |
53 |
Loading data...
54 |
55 |
56 |
57 |
58 |
63 |
64 |
65 | {% endblock %}
66 |
67 |
68 | {% block status %}
69 | {% include "progress.html" %}
70 | {% endblock %}
71 |
72 | {% block javascript %}
73 |
80 | {% endblock %}
81 |
--------------------------------------------------------------------------------
/stlearn/classes.py:
--------------------------------------------------------------------------------
1 | """
2 | Title: SpatialBasePlot for all spatial coordinates and image plot
3 | Author: Duy Pham
4 | Date: 20 Feb 2021
5 | """
6 |
7 | from typing import Optional, Union, Mapping # Special
8 | from typing import Sequence, Iterable # ABCs
9 | from typing import Tuple # Classes
10 |
11 | import numpy as np
12 | from anndata import AnnData
13 |
14 | from .utils import (
15 | Empty,
16 | _empty,
17 | _check_spatial_data,
18 | _check_img,
19 | _check_spot_size,
20 | _check_scale_factor,
21 | _check_coords,
22 | )
23 |
24 |
25 | class Spatial(object):
26 | def __init__(
27 | self,
28 | adata: AnnData,
29 | basis: str = "spatial",
30 | img: Union[np.ndarray, None] = None,
31 | img_key: Union[str, None, Empty] = _empty,
32 | library_id: Union[str, None] = _empty,
33 | crop_coord: Optional[bool] = True,
34 | bw: Optional[bool] = False,
35 | scale_factor: Optional[float] = None,
36 | spot_size: Optional[float] = None,
37 | use_raw: Optional[bool] = False,
38 | **kwargs,
39 | ):
40 |
41 | self.adata = (adata,)
42 | self.library_id, self.spatial_data = _check_spatial_data(adata.uns, library_id)
43 | self.img, self.img_key = _check_img(self.spatial_data, img, img_key, bw=bw)
44 | self.spot_size = _check_spot_size(self.spatial_data, spot_size)
45 | self.scale_factor = _check_scale_factor(
46 | self.spatial_data, img_key=self.img_key, scale_factor=scale_factor
47 | )
48 | self.crop_coord = crop_coord
49 | self.use_raw = use_raw
50 | self.imagecol, self.imagerow = _check_coords(adata.obsm, self.scale_factor)
51 |
--------------------------------------------------------------------------------
/stlearn/datasets.py:
--------------------------------------------------------------------------------
1 | from ._datasets._datasets import example_bcba
2 |
--------------------------------------------------------------------------------
/stlearn/em.py:
--------------------------------------------------------------------------------
1 | from .embedding.pca import run_pca
2 | from .embedding.umap import run_umap
3 | from .embedding.ica import run_ica
4 |
5 | # from .embedding.scvi import run_ldvae
6 | from .embedding.fa import run_fa
7 | from .embedding.diffmap import run_diffmap
8 |
--------------------------------------------------------------------------------
/stlearn/embedding/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/embedding/__init__.py
--------------------------------------------------------------------------------
/stlearn/embedding/diffmap.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | import numpy as np
3 | from anndata import AnnData
4 | from numpy.random.mtrand import RandomState
5 | from scipy.sparse import issparse
6 | import scanpy
7 |
8 |
9 | def run_diffmap(adata: AnnData, n_comps: int = 15, copy: bool = False):
10 | """\
11 | Diffusion Maps [Coifman05]_ [Haghverdi15]_ [Wolf18]_.
12 | Diffusion maps [Coifman05]_ has been proposed for visualizing single-cell
13 | data by [Haghverdi15]_. The tool uses the adapted Gaussian kernel suggested
14 | by [Haghverdi16]_ in the implementation of [Wolf18]_.
15 | The width ("sigma") of the connectivity kernel is implicitly determined by
16 | the number of neighbors used to compute the single-cell graph in
17 | :func:`~scanpy.pp.neighbors`. To reproduce the original implementation
18 | using a Gaussian kernel, use `method=='gauss'` in
19 | :func:`~scanpy.pp.neighbors`. To use an exponential kernel, use the default
20 | `method=='umap'`. Differences between these options shouldn't usually be
21 | dramatic.
22 | Parameters
23 | ----------
24 | adata
25 | Annotated data matrix.
26 | n_comps
27 | The number of dimensions of the representation.
28 | copy
29 | Return a copy instead of writing to adata.
30 | Returns
31 | -------
32 | Depending on `copy`, returns or updates `adata` with the following fields.
33 | `X_diffmap` : :class:`numpy.ndarray` (`adata.obsm`)
34 | Diffusion map representation of data, which is the right eigen basis of
35 | the transition matrix with eigenvectors as columns.
36 | `diffmap_evals` : :class:`numpy.ndarray` (`adata.uns`)
37 | Array of size (number of eigen vectors).
38 | Eigenvalues of transition matrix.
39 | """
40 |
41 | scanpy.tl.diffmap(adata, n_comps=n_comps, copy=copy)
42 |
43 | print(
44 | "Diffusion Map is done! Generated in adata.obsm['X_diffmap'] nad adata.uns['diffmap_evals']"
45 | )
46 |
47 | return adata if copy else None
48 |
--------------------------------------------------------------------------------
/stlearn/embedding/fa.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 | from typing import Optional
4 |
5 | from anndata import AnnData
6 | from sklearn.decomposition import FactorAnalysis
7 | from scipy.sparse import issparse
8 |
9 |
10 | def run_fa(
11 | adata: AnnData,
12 | n_factors: int = 20,
13 | tol: float = 0.01,
14 | max_iter: int = 1000,
15 | svd_method: str = "randomized",
16 | iterated_power: int = 3,
17 | random_state: int = 2108,
18 | use_data: str = None,
19 | copy: bool = False,
20 | ) -> Optional[AnnData]:
21 |
22 | """\
23 | Factor Analysis (FA)
24 | A simple linear generative model with Gaussian latent variables.
25 | The observations are assumed to be caused by a linear transformation of
26 | lower dimensional latent factors and added Gaussian noise.
27 | Without loss of generality the factors are distributed according to a
28 | Gaussian with zero mean and unit covariance. The noise is also zero mean
29 | and has an arbitrary diagonal covariance matrix.
30 | If we would restrict the model further, by assuming that the Gaussian
31 | noise is even isotropic (all diagonal entries are the same) we would obtain
32 | :class:`PPCA`.
33 | FactorAnalysis performs a maximum likelihood estimate of the so-called
34 | `loading` matrix, the transformation of the latent variables to the
35 | observed ones, using SVD based approach.
36 |
37 | Parameters
38 | ----------
39 | adata
40 | Annotated data matrix.
41 | n_components
42 | Dimensionality of latent space, the number of components
43 | of ``X`` that are obtained after ``transform``.
44 | If None, n_components is set to the number of features.
45 | tol
46 | Stopping tolerance for log-likelihood increase.
47 | max_iter
48 | Maximum number of iterations.
49 | noise_variance_init
50 | The initial guess of the noise variance for each feature.
51 | If None, it defaults to np.ones(n_features)
52 | svd_method
53 | Which SVD method to use. If 'lapack' use standard SVD from
54 | scipy.linalg, if 'randomized' use fast ``randomized_svd`` function.
55 | Defaults to 'randomized'. For most applications 'randomized' will
56 | be sufficiently precise while providing significant speed gains.
57 | Accuracy can also be improved by setting higher values for
58 | `iterated_power`. If this is not sufficient, for maximum precision
59 | you should choose 'lapack'.
60 | iterated_power
61 | Number of iterations for the power method. 3 by default. Only used
62 | if ``svd_method`` equals 'randomized'
63 | random_state
64 | If int, random_state is the seed used by the random number generator;
65 | If RandomState instance, random_state is the random number generator;
66 | If None, the random number generator is the RandomState instance used
67 | by `np.random`. Only used when ``svd_method`` equals 'randomized'.
68 | copy
69 | Return a copy instead of writing to adata.
70 | Returns
71 | -------
72 | Depending on `copy`, returns or updates `adata` with the following fields.
73 | `X_fa` : :class:`numpy.ndarray` (`adata.obsm`)
74 | Factor analysis representation of data.
75 | """
76 |
77 | if use_data is None:
78 | if issparse(adata.X):
79 | matrix = adata.X.toarray()
80 | else:
81 | matrix = adata.X
82 |
83 | else:
84 | matrix = adata.obsm[use_data].values
85 |
86 | fa = FactorAnalysis(
87 | n_components=n_factors,
88 | tol=tol,
89 | max_iter=max_iter,
90 | svd_method=svd_method,
91 | iterated_power=iterated_power,
92 | random_state=random_state,
93 | )
94 |
95 | latent = fa.fit_transform(matrix)
96 |
97 | adata.obsm["X_fa"] = latent
98 |
99 | adata.uns["fa_params"] = {
100 | "params": {
101 | "n_factors": n_factors,
102 | "tol": tol,
103 | "max_iter": max_iter,
104 | "svd_method": svd_method,
105 | "iterated_power": iterated_power,
106 | "random_state": random_state,
107 | }
108 | }
109 |
110 | print('FA is done! Generated in adata.obsm["X_fa"]')
111 |
112 | return adata if copy else None
113 |
--------------------------------------------------------------------------------
/stlearn/embedding/ica.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 | from typing import Optional
4 | from anndata import AnnData
5 | from sklearn.decomposition import FastICA
6 | from scipy.sparse import issparse
7 |
8 |
9 | def run_ica(
10 | adata: AnnData,
11 | n_factors: int = 20,
12 | fun: str = "logcosh",
13 | tol: float = 0.0001,
14 | use_data: str = None,
15 | copy: bool = False,
16 | ) -> Optional[AnnData]:
17 |
18 | """\
19 | FastICA: a fast algorithm for Independent Component Analysis.
20 |
21 | Parameters
22 | ----------
23 | adata
24 | Annotated data matrix.
25 | n_factors
26 | Number of components to use. If none is passed, all are used.
27 | fun
28 | The functional form of the G function used in the
29 | approximation to neg-entropy. Could be either 'logcosh', 'exp',
30 | or 'cube'.
31 | You can also provide your own function. It should return a tuple
32 | containing the value of the function, and of its derivative, in the
33 | point. Example:
34 | def my_g(x):
35 | return x ** 3, (3 * x ** 2).mean(axis=-1)
36 | tol
37 | Tolerance on update at each iteration.
38 | use_data
39 | if None, then using all the gene expression profile. Else, use
40 | the chosen data from adata.obsm.
41 | copy
42 | Return a copy instead of writing to adata.
43 | Returns
44 | -------
45 | Depending on `copy`, returns or updates `adata` with the following fields.
46 | `X_ica` : :class:`numpy.ndarray` (`adata.obsm`)
47 | Independent Component Analysis representation of data.
48 | """
49 |
50 | if use_data is None:
51 | if issparse(adata.X):
52 | matrix = adata.X.toarray()
53 | else:
54 | matrix = adata.X
55 |
56 | else:
57 | matrix = adata.obsm[use_data].values
58 |
59 | ica = FastICA(n_components=n_factors, fun=fun, tol=tol)
60 |
61 | latent = ica.fit_transform(matrix)
62 |
63 | adata.obsm["X_ica"] = latent
64 |
65 | adata.uns["ica"] = {"params": {"n_factors": n_factors, "fun": fun, "tol": tol}}
66 |
67 | print(
68 | "ICA is done! Generated in adata.obsm['X_ica'] and parameters in adata.uns['ica']"
69 | )
70 |
71 | return adata if copy else None
72 |
--------------------------------------------------------------------------------
/stlearn/embedding/pca.py:
--------------------------------------------------------------------------------
1 | import logging as logg
2 | from typing import Union, Optional, Tuple, Collection, Sequence, Iterable
3 | from anndata import AnnData
4 | import numpy as np
5 | from scipy.sparse import issparse, isspmatrix_csr, csr_matrix, spmatrix
6 | from numpy.random.mtrand import RandomState
7 | import scanpy
8 |
9 |
10 | def run_pca(
11 | data: Union[AnnData, np.ndarray, spmatrix],
12 | n_comps: int = 50,
13 | zero_center: Optional[bool] = True,
14 | svd_solver: str = "auto",
15 | random_state: Optional[Union[int, RandomState]] = 0,
16 | return_info: bool = False,
17 | use_highly_variable: Optional[bool] = None,
18 | dtype: str = "float32",
19 | copy: bool = False,
20 | chunked: bool = False,
21 | chunk_size: Optional[int] = None,
22 | ) -> Union[AnnData, np.ndarray, spmatrix]:
23 | """\
24 | Wrap function scanpy.pp.pca
25 | Principal component analysis [Pedregosa11]_.
26 | Computes PCA coordinates, loadings and variance decomposition.
27 | Uses the implementation of *scikit-learn* [Pedregosa11]_.
28 | Parameters
29 | ----------
30 | data
31 | The (annotated) data matrix of shape `n_obs` × `n_vars`.
32 | Rows correspond to cells and columns to genes.
33 | n_comps
34 | Number of principal components to compute.
35 | zero_center
36 | If `True`, compute standard PCA from covariance matrix.
37 | If `False`, omit zero-centering variables
38 | (uses :class:`~sklearn.decomposition.TruncatedSVD`),
39 | which allows to handle sparse input efficiently.
40 | Passing `None` decides automatically based on sparseness of the data.
41 | svd_solver
42 | SVD solver to use:
43 | `'arpack'`
44 | for the ARPACK wrapper in SciPy (:func:`~scipy.sparse.linalg.svds`)
45 | `'randomized'`
46 | for the randomized algorithm due to Halko (2009).
47 | `'auto'` (the default)
48 | chooses automatically depending on the size of the problem.
49 | random_state
50 | Change to use different initial states for the optimization.
51 | return_info
52 | Only relevant when not passing an :class:`~anndata.AnnData`:
53 | see “**Returns**”.
54 | use_highly_variable
55 | Whether to use highly variable genes only, stored in
56 | `.var['highly_variable']`.
57 | By default uses them if they have been determined beforehand.
58 | dtype
59 | Numpy data type string to which to convert the result.
60 | copy
61 | If an :class:`~anndata.AnnData` is passed, determines whether a copy
62 | is returned. Is ignored otherwise.
63 | chunked
64 | If `True`, perform an incremental PCA on segments of `chunk_size`.
65 | The incremental PCA automatically zero centers and ignores settings of
66 | `random_seed` and `svd_solver`. If `False`, perform a full PCA.
67 | chunk_size
68 | Number of observations to include in each chunk.
69 | Required if `chunked=True` was passed.
70 | Returns
71 | -------
72 | X_pca : :class:`~scipy.sparse.spmatrix`, :class:`~numpy.ndarray`
73 | If `data` is array-like and `return_info=False` was passed,
74 | this function only returns `X_pca`…
75 | adata : anndata.AnnData
76 | …otherwise if `copy=True` it returns or else adds fields to `adata`:
77 | `.obsm['X_pca']`
78 | PCA representation of data.
79 | `.varm['PCs']`
80 | The principal components containing the loadings.
81 | `.uns['pca']['variance_ratio']`
82 | Ratio of explained variance.
83 | `.uns['pca']['variance']`
84 | Explained variance, equivalent to the eigenvalues of the
85 | covariance matrix.
86 | """
87 |
88 | scanpy.pp.pca(
89 | data,
90 | n_comps=n_comps,
91 | zero_center=zero_center,
92 | svd_solver=svd_solver,
93 | random_state=random_state,
94 | return_info=return_info,
95 | use_highly_variable=use_highly_variable,
96 | dtype=dtype,
97 | copy=copy,
98 | chunked=chunked,
99 | chunk_size=chunk_size,
100 | )
101 |
102 | print(
103 | "PCA is done! Generated in adata.obsm['X_pca'], adata.uns['pca'] and adata.varm['PCs']"
104 | )
105 |
--------------------------------------------------------------------------------
/stlearn/embedding/umap.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 |
3 | import numpy as np
4 | from anndata import AnnData
5 | from numpy.random.mtrand import RandomState
6 |
7 | from .._compat import Literal
8 | import scanpy
9 |
10 | _InitPos = Literal["paga", "spectral", "random"]
11 |
12 |
13 | def run_umap(
14 | adata: AnnData,
15 | min_dist: float = 0.5,
16 | spread: float = 1.0,
17 | n_components: int = 2,
18 | maxiter: Optional[int] = None,
19 | alpha: float = 1.0,
20 | gamma: float = 1.0,
21 | negative_sample_rate: int = 5,
22 | init_pos: Union[_InitPos, np.ndarray, None] = "spectral",
23 | random_state: Optional[Union[int, RandomState]] = 0,
24 | a: Optional[float] = None,
25 | b: Optional[float] = None,
26 | copy: bool = False,
27 | method: Literal["umap", "rapids"] = "umap",
28 | ) -> Optional[AnnData]:
29 | """\
30 | Wrap function scanpy.pp.umap
31 | Embed the neighborhood graph using UMAP [McInnes18]_.
32 | UMAP (Uniform Manifold Approximation and Projection) is a manifold learning
33 | technique suitable for visualizing high-dimensional data. Besides tending to
34 | be faster than tSNE, it optimizes the embedding such that it best reflects
35 | the topology of the data, which we represent throughout Scanpy using a
36 | neighborhood graph. tSNE, by contrast, optimizes the distribution of
37 | nearest-neighbor distances in the embedding such that these best match the
38 | distribution of distances in the high-dimensional space. We use the
39 | implementation of `umap-learn `__
40 | [McInnes18]_. For a few comparisons of UMAP with tSNE, see this `preprint
41 | `__.
42 | Parameters
43 | ----------
44 | adata
45 | Annotated data matrix.
46 | n_components
47 | The number of dimensions of the embedding.
48 | random_state
49 | If `int`, `random_state` is the seed used by the random number generator;
50 | If `RandomState`, `random_state` is the random number generator;
51 | If `None`, the random number generator is the `RandomState` instance used
52 | by `np.random`.
53 | Returns
54 | -------
55 | Depending on `copy`, returns or updates `adata` with the following fields.
56 | `X_umap` : :class:`numpy.ndarray` (`adata.obsm`)
57 | Independent Component Analysis representation of data.
58 |
59 | """
60 |
61 | scanpy.tl.umap(
62 | adata,
63 | min_dist=min_dist,
64 | spread=spread,
65 | n_components=n_components,
66 | maxiter=maxiter,
67 | alpha=alpha,
68 | gamma=gamma,
69 | negative_sample_rate=negative_sample_rate,
70 | init_pos=init_pos,
71 | random_state=random_state,
72 | a=a,
73 | b=b,
74 | copy=copy,
75 | method=method,
76 | )
77 |
78 | print("UMAP is done! Generated in adata.obsm['X_umap'] nad adata.uns['umap']")
79 |
--------------------------------------------------------------------------------
/stlearn/gui.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/gui.py
--------------------------------------------------------------------------------
/stlearn/image_preprocessing/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/image_preprocessing/__init__.py
--------------------------------------------------------------------------------
/stlearn/image_preprocessing/feature_extractor.py:
--------------------------------------------------------------------------------
1 | from .model_zoo import encode, Model
2 | from typing import Optional, Union
3 | from anndata import AnnData
4 | import numpy as np
5 | from .._compat import Literal
6 | from PIL import Image
7 | import pandas as pd
8 | from pathlib import Path
9 |
10 | # Test progress bar
11 | from tqdm import tqdm
12 |
13 | _CNN_BASE = Literal["resnet50", "vgg16", "inception_v3", "xception"]
14 |
15 |
16 | def extract_feature(
17 | adata: AnnData,
18 | cnn_base: _CNN_BASE = "resnet50",
19 | n_components: int = 50,
20 | verbose: bool = False,
21 | copy: bool = False,
22 | seeds: int = 1,
23 | ) -> Optional[AnnData]:
24 | """\
25 | Extract latent morphological features from H&E images using pre-trained
26 | convolutional neural network base
27 |
28 | Parameters
29 | ----------
30 | adata
31 | Annotated data matrix.
32 | cnn_base
33 | Established convolutional neural network bases
34 | choose one from ['resnet50', 'vgg16', 'inception_v3', 'xception']
35 | n_components
36 | Number of principal components to compute for latent morphological features
37 | verbose
38 | Verbose output
39 | copy
40 | Return a copy instead of writing to adata.
41 | seeds
42 | Fix random state
43 | Returns
44 | -------
45 | Depending on `copy`, returns or updates `adata` with the following fields.
46 | **X_morphology** : `adata.obsm` field
47 | Dimension reduced latent morphological features.
48 | """
49 | feature_dfs = []
50 | model = Model(cnn_base)
51 |
52 | if "tile_path" not in adata.obs:
53 | raise ValueError("Please run the function stlearn.pp.tiling")
54 |
55 | with tqdm(
56 | total=len(adata),
57 | desc="Extract feature",
58 | bar_format="{l_bar}{bar} [ time left: {remaining} ]",
59 | ) as pbar:
60 | for spot, tile_path in adata.obs["tile_path"].items():
61 | tile = Image.open(tile_path)
62 | tile = np.asarray(tile, dtype="int32")
63 | tile = tile.astype(np.float32)
64 | tile = np.stack([tile])
65 | if verbose:
66 | print("extract feature for spot: {}".format(str(spot)))
67 | features = encode(tile, model)
68 | feature_dfs.append(pd.DataFrame(features, columns=[spot]))
69 | pbar.update(1)
70 |
71 | feature_df = pd.concat(feature_dfs, axis=1)
72 |
73 | adata.obsm["X_tile_feature"] = feature_df.transpose().to_numpy()
74 |
75 | from sklearn.decomposition import PCA
76 |
77 | pca = PCA(n_components=n_components, random_state=seeds)
78 | pca.fit(feature_df.transpose().to_numpy())
79 |
80 | adata.obsm["X_morphology"] = pca.transform(feature_df.transpose().to_numpy())
81 |
82 | print("The morphology feature is added to adata.obsm['X_morphology']!")
83 |
84 | return adata if copy else None
85 |
--------------------------------------------------------------------------------
/stlearn/image_preprocessing/image_tiling.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | from anndata import AnnData
3 | from .._compat import Literal
4 | from PIL import Image
5 | from pathlib import Path
6 |
7 | # Test progress bar
8 | from tqdm import tqdm
9 | import numpy as np
10 | import os
11 |
12 |
13 | def tiling(
14 | adata: AnnData,
15 | out_path: Union[Path, str] = "./tiling",
16 | library_id: Union[str, None] = None,
17 | crop_size: int = 40,
18 | target_size: int = 299,
19 | img_fmt: str = "JPEG",
20 | verbose: bool = False,
21 | copy: bool = False,
22 | ) -> Optional[AnnData]:
23 | """\
24 | Tiling H&E images to small tiles based on spot spatial location
25 |
26 | Parameters
27 | ----------
28 | adata
29 | Annotated data matrix.
30 | out_path
31 | Path to save spot image tiles
32 | library_id
33 | Library id stored in AnnData.
34 | crop_size
35 | Size of tiles
36 | verbose
37 | Verbose output
38 | copy
39 | Return a copy instead of writing to adata.
40 | target_size
41 | Input size for convolutional neuron network
42 | Returns
43 | -------
44 | Depending on `copy`, returns or updates `adata` with the following fields.
45 | **tile_path** : `adata.obs` field
46 | Saved path for each spot image tiles
47 | """
48 |
49 | if library_id is None:
50 | library_id = list(adata.uns["spatial"].keys())[0]
51 |
52 | # Check the exist of out_path
53 | if not os.path.isdir(out_path):
54 | os.mkdir(out_path)
55 |
56 | image = adata.uns["spatial"][library_id]["images"][
57 | adata.uns["spatial"][library_id]["use_quality"]
58 | ]
59 | if image.dtype == np.float32 or image.dtype == np.float64:
60 | image = (image * 255).astype(np.uint8)
61 | img_pillow = Image.fromarray(image)
62 |
63 | if img_pillow.mode == "RGBA":
64 | img_pillow = img_pillow.convert("RGB")
65 |
66 | tile_names = []
67 |
68 | with tqdm(
69 | total=len(adata),
70 | desc="Tiling image",
71 | bar_format="{l_bar}{bar} [ time left: {remaining} ]",
72 | ) as pbar:
73 | for imagerow, imagecol in zip(adata.obs["imagerow"], adata.obs["imagecol"]):
74 | imagerow_down = imagerow - crop_size / 2
75 | imagerow_up = imagerow + crop_size / 2
76 | imagecol_left = imagecol - crop_size / 2
77 | imagecol_right = imagecol + crop_size / 2
78 | tile = img_pillow.crop(
79 | (imagecol_left, imagerow_down, imagecol_right, imagerow_up)
80 | )
81 | tile.thumbnail((target_size, target_size), Image.Resampling.LANCZOS)
82 | tile = tile.resize((target_size, target_size))
83 | tile_name = str(imagecol) + "-" + str(imagerow) + "-" + str(crop_size)
84 |
85 | if img_fmt == "JPEG":
86 | out_tile = Path(out_path) / (tile_name + ".jpeg")
87 | tile_names.append(str(out_tile))
88 | tile.save(out_tile, "JPEG")
89 | else:
90 | out_tile = Path(out_path) / (tile_name + ".png")
91 | tile_names.append(str(out_tile))
92 | tile.save(out_tile, "PNG")
93 |
94 | if verbose:
95 | print(
96 | "generate tile at location ({}, {})".format(
97 | str(imagecol), str(imagerow)
98 | )
99 | )
100 |
101 | pbar.update(1)
102 |
103 | adata.obs["tile_path"] = tile_names
104 | return adata if copy else None
105 |
--------------------------------------------------------------------------------
/stlearn/image_preprocessing/model_zoo.py:
--------------------------------------------------------------------------------
1 | def encode(tiles, model):
2 | features = model.predict(tiles)
3 | features = features.ravel()
4 | return features
5 |
6 |
7 | class Model:
8 | __name__ = "CNN base model"
9 |
10 | def __init__(self, base, batch_size=1):
11 | from tensorflow.keras import backend as K
12 |
13 | self.base = base
14 | self.model, self.preprocess = self.load_model()
15 | self.batch_size = batch_size
16 | self.data_format = K.image_data_format()
17 |
18 | def load_model(self):
19 | if self.base == "resnet50":
20 | from tensorflow.keras.applications.resnet50 import (
21 | ResNet50,
22 | preprocess_input,
23 | )
24 |
25 | cnn_base_model = ResNet50(
26 | include_top=False, weights="imagenet", pooling="avg"
27 | )
28 | elif self.base == "vgg16":
29 | from tensorflow.keras.applications.vgg16 import VGG16, preprocess_input
30 |
31 | cnn_base_model = VGG16(include_top=False, weights="imagenet", pooling="avg")
32 | elif self.base == "inception_v3":
33 | from tensorflow.keras.applications.inception_v3 import (
34 | InceptionV3,
35 | preprocess_input,
36 | )
37 |
38 | cnn_base_model = InceptionV3(
39 | include_top=False, weights="imagenet", pooling="avg"
40 | )
41 | elif self.base == "xception":
42 | from tensorflow.keras.applications.xception import (
43 | Xception,
44 | preprocess_input,
45 | )
46 |
47 | cnn_base_model = Xception(
48 | include_top=False, weights="imagenet", pooling="avg"
49 | )
50 | else:
51 | raise ValueError("{} is not a valid model".format(self.base))
52 | return cnn_base_model, preprocess_input
53 |
54 | def predict(self, x):
55 | from tensorflow.keras import backend as K
56 |
57 | if self.data_format == "channels_first":
58 | x = x.transpose(0, 3, 1, 2)
59 | x = self.preprocess(x.astype(K.floatx()))
60 | return self.model.predict(x, batch_size=self.batch_size, verbose=False)
61 |
--------------------------------------------------------------------------------
/stlearn/pl.py:
--------------------------------------------------------------------------------
1 | from .plotting.gene_plot import gene_plot
2 | from .plotting.gene_plot import gene_plot_interactive
3 | from .plotting.feat_plot import feat_plot
4 | from .plotting.cluster_plot import cluster_plot
5 | from .plotting.cluster_plot import cluster_plot_interactive
6 | from .plotting.subcluster_plot import subcluster_plot
7 | from .plotting.non_spatial_plot import non_spatial_plot
8 | from .plotting.deconvolution_plot import deconvolution_plot
9 | from .plotting.stack_3d_plot import stack_3d_plot
10 | from .plotting import trajectory
11 | from .plotting.QC_plot import QC_plot
12 | from .plotting.cci_plot import het_plot
13 |
14 | # from .plotting.cci_plot import het_plot_interactive
15 | from .plotting.cci_plot import lr_plot_interactive, spatialcci_plot_interactive
16 | from .plotting.cci_plot import grid_plot
17 | from .plotting.cci_plot import lr_diagnostics, lr_n_spots, lr_summary, lr_go
18 | from .plotting.cci_plot import lr_plot, lr_result_plot
19 | from .plotting.cci_plot import (
20 | ccinet_plot,
21 | cci_map,
22 | lr_cci_map,
23 | lr_chord_plot,
24 | cci_check,
25 | )
26 | from .plotting.mask_plot import plot_mask
27 |
--------------------------------------------------------------------------------
/stlearn/plotting/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/plotting/__init__.py
--------------------------------------------------------------------------------
/stlearn/plotting/_docs.py:
--------------------------------------------------------------------------------
1 | doc_spatial_base_plot = """\
2 | adata
3 | Annotated data matrix.
4 | title
5 | Title name of the figure.
6 | figsize
7 | Figure size with the format (width,height).
8 | cmap
9 | Color map to use for continous variables or discretes variables (e.g. viridis, Set1,...).
10 | use_label
11 | Key for the label use in `adata.obs` (e.g. `leiden`, `louvain`,...).
12 | list_clusters
13 | A set of cluster to be displayed in the figure (e.g. [0,1,2,3]).
14 | ax
15 | A matplotlib axes object.
16 | show_plot
17 | Option to display the figure.
18 | show_image
19 | Option to display the H&E image.
20 | show_color_bar
21 | Option to display color bar.
22 | crop
23 | Option to crop the figure based on the spot locations.
24 | margin
25 | Margin to crop.
26 | size
27 | Spot size to display in figure.
28 | image_alpha
29 | Opacity of H&E image.
30 | cell_alpha
31 | Opacity of spots/cells.
32 | use_raw
33 | Option to use `adata.raw` data.
34 | fname
35 | Output path to the output if user want to save the figure.
36 | dpi
37 | Dots per inch values for the output.
38 | """
39 |
40 | doc_gene_plot = """\
41 | gene_symbols
42 | Single gene (str) or multiple genes (list) that user wants to display. It should be available in `adata.var_names`.
43 | threshold
44 | Threshold to display genes in the figure.
45 | method
46 | Method to combine multiple genes:
47 | `'CumSum'` is cummulative sum of genes expression values,
48 | `'NaiveMean'` is the mean of the genes expression values.
49 | contour
50 | Option to show the contour plot.
51 | step_size
52 | Determines the number and positions of the contour lines / regions.
53 | """
54 |
55 | doc_cluster_plot = """\
56 | show_subcluster
57 | Display the subcluster in the figure.
58 | show_cluster_labels
59 | Display the labels of clusters.
60 | show_trajectories
61 | Display the spatial trajectory analysis results.
62 | reverse
63 | Reverse the direction of spatial trajectories.
64 | show_node
65 | Show node of PAGA graph mapping in spatial.
66 | threshold_spots
67 | The number of spots threshold for not display the subcluster labels
68 | text_box_size
69 | The font size in the box of labels.
70 | color_bar_size
71 | The size of color bar.
72 | bbox_to_anchor
73 | Set the position of box of color bar. Default is `(1,1)`
74 | """
75 |
76 | doc_lr_plot = """\
77 | adata
78 | AnnData object with run st.tl.cci_rank.run performed on.
79 | lr
80 | Ligand receptor paid (in format L_R)
81 | min_expr
82 | Minimum expression for gene to be considered expressed.
83 | sig_spots
84 | Whether to filter to significant spots or not.
85 | use_label
86 | Label to use for the inner points, can be in adata.obs or in the lr stats of adata.uns['per_lr_results'][lr].columns
87 | use_mix
88 | The deconvolution/label_transfer results to use for visualising pie charts in the inner point, not currently implimented.
89 | outer_mode
90 | Either 'binary', 'continuous', or None; controls how ligand-receptor expression shown (or not shown).
91 | l_cmap
92 | matplotlib cmap controlling ligand continous expression.
93 | r_cmap
94 | matplotlib cmap controlling receptor continuous expression.
95 | lr_cmap
96 | matplotlib cmap controlling the ligand receptor binary expression, but have atleast 4 colours.
97 | inner_cmap
98 | matplotlib cmap controlling the inner point colours.
99 | inner_size_prop
100 | multiplier which controls size of inner points.
101 | middle_size_prop
102 | Multiplier which controls size of middle point (only relevant when outer_mode='continuous')
103 | outer_size_prop
104 | Multiplier which controls size of the outter point.
105 | pt_scale
106 | Multiplier which scales overall point size of all points plotted.
107 | title
108 | Title of the plot.
109 | show_image
110 | Whether to show the background H&E or not.
111 | kwargs
112 | Extra arguments parsed to the other plotting functions such as gene_plot, cluster_plot, &/or het_plot.
113 | """
114 |
115 | doc_het_plot = """\
116 | use_het
117 | Single gene (str) or multiple genes (list) that user wants to display. It should be available in `adata.var_names`.
118 | contour
119 | Option to show the contour plot.
120 | step_size
121 | Determines the number and positions of the contour lines / regions.
122 | vmin
123 | Lower end of scale bar.
124 | vmax
125 | Upper end of scale bar.
126 | """
127 |
128 | doc_subcluster_plot = """\
129 | cluster
130 | Choose cluster to plot the sub-clusters.
131 | text_box_size
132 | The font size in the box of labels.
133 | bbox_to_anchor
134 | Set the position of box of color bar. Default is `(1,1)`
135 | """
136 |
--------------------------------------------------------------------------------
/stlearn/plotting/cluster_plot.py:
--------------------------------------------------------------------------------
1 | from matplotlib import pyplot as plt
2 | from PIL import Image
3 | import pandas as pd
4 | import matplotlib
5 | import numpy as np
6 | import networkx as nx
7 |
8 | from typing import Optional, Union, Mapping # Special
9 | from typing import Sequence, Iterable # ABCs
10 | from typing import Tuple # Classes
11 |
12 | from anndata import AnnData
13 | import warnings
14 |
15 | from stlearn.plotting.classes import ClusterPlot
16 | from stlearn.plotting.classes_bokeh import BokehClusterPlot
17 | from stlearn.plotting._docs import doc_spatial_base_plot, doc_cluster_plot
18 | from stlearn.utils import _AxesSubplot, Axes, _docs_params
19 |
20 | from bokeh.io import push_notebook, output_notebook
21 | from bokeh.plotting import show
22 |
23 |
24 | @_docs_params(spatial_base_plot=doc_spatial_base_plot, cluster_plot=doc_cluster_plot)
25 | def cluster_plot(
26 | adata: AnnData,
27 | # plotting param
28 | title: Optional["str"] = None,
29 | figsize: Optional[Tuple[float, float]] = None,
30 | cmap: Optional[str] = "default",
31 | use_label: Optional[str] = None,
32 | list_clusters: Optional[list] = None,
33 | ax: Optional[matplotlib.axes.Axes] = None,
34 | fig: Optional[matplotlib.figure.Figure] = None,
35 | show_plot: Optional[bool] = True,
36 | show_axis: Optional[bool] = False,
37 | show_image: Optional[bool] = True,
38 | show_color_bar: Optional[bool] = True,
39 | zoom_coord: Optional[float] = None,
40 | crop: Optional[bool] = True,
41 | margin: Optional[bool] = 100,
42 | size: Optional[float] = 5,
43 | image_alpha: Optional[float] = 1.0,
44 | cell_alpha: Optional[float] = 1.0,
45 | fname: Optional[str] = None,
46 | dpi: Optional[int] = 120,
47 | # cluster plot param
48 | show_subcluster: Optional[bool] = False,
49 | show_cluster_labels: Optional[bool] = False,
50 | show_trajectories: Optional[bool] = False,
51 | reverse: Optional[bool] = False,
52 | show_node: Optional[bool] = False,
53 | threshold_spots: Optional[int] = 5,
54 | text_box_size: Optional[float] = 5,
55 | color_bar_size: Optional[float] = 10,
56 | bbox_to_anchor: Optional[Tuple[float, float]] = (1, 1),
57 | # trajectory
58 | trajectory_node_size: Optional[int] = 10,
59 | trajectory_alpha: Optional[float] = 1.0,
60 | trajectory_width: Optional[float] = 2.5,
61 | trajectory_edge_color: Optional[str] = "#f4efd3",
62 | trajectory_arrowsize: Optional[int] = 17,
63 | ) -> Optional[AnnData]:
64 |
65 | """\
66 | Allows the visualization of a cluster results as the discretes values
67 | of dot points in the Spatial transcriptomics array. We also support to
68 | visualize the spatial trajectory results
69 |
70 |
71 | Parameters
72 | -------------------------------------
73 | {spatial_base_plot}
74 | {cluster_plot}
75 |
76 | Examples
77 | -------------------------------------
78 | >>> import stlearn as st
79 | >>> adata = st.datasets.example_bcba()
80 | >>> label = "louvain"
81 | >>> st.pl.cluster_plot(adata, use_label = label, show_trajectories = True)
82 |
83 | """
84 |
85 | assert use_label != None, "Please select `use_label` parameter"
86 |
87 | ClusterPlot(
88 | adata,
89 | title=title,
90 | figsize=figsize,
91 | cmap=cmap,
92 | use_label=use_label,
93 | list_clusters=list_clusters,
94 | ax=ax,
95 | fig=fig,
96 | show_plot=show_plot,
97 | show_axis=show_axis,
98 | show_image=show_image,
99 | show_color_bar=show_color_bar,
100 | zoom_coord=zoom_coord,
101 | crop=crop,
102 | margin=margin,
103 | size=size,
104 | image_alpha=image_alpha,
105 | cell_alpha=cell_alpha,
106 | fname=fname,
107 | dpi=dpi,
108 | show_subcluster=show_subcluster,
109 | show_cluster_labels=show_cluster_labels,
110 | show_trajectories=show_trajectories,
111 | reverse=reverse,
112 | show_node=show_node,
113 | threshold_spots=threshold_spots,
114 | text_box_size=text_box_size,
115 | color_bar_size=color_bar_size,
116 | bbox_to_anchor=bbox_to_anchor,
117 | trajectory_node_size=trajectory_node_size,
118 | trajectory_alpha=trajectory_alpha,
119 | trajectory_width=trajectory_width,
120 | trajectory_edge_color=trajectory_edge_color,
121 | trajectory_arrowsize=trajectory_arrowsize,
122 | )
123 |
124 |
125 | def cluster_plot_interactive(
126 | adata: AnnData,
127 | ):
128 |
129 | bokeh_object = BokehClusterPlot(adata)
130 | output_notebook()
131 | show(bokeh_object.app, notebook_handle=True)
132 |
--------------------------------------------------------------------------------
/stlearn/plotting/feat_plot.py:
--------------------------------------------------------------------------------
1 | """
2 | Plotting of continuous features stored in adata.obs.
3 | """
4 |
5 | from matplotlib import pyplot as plt
6 | from PIL import Image
7 | import pandas as pd
8 | import matplotlib
9 | import numpy as np
10 |
11 | from typing import Optional, Union, Mapping # Special
12 | from typing import Sequence, Iterable # ABCs
13 | from typing import Tuple # Classes
14 |
15 | from anndata import AnnData
16 | import warnings
17 |
18 | from stlearn.plotting.classes import FeaturePlot
19 | from stlearn.plotting.classes_bokeh import BokehGenePlot
20 | from stlearn.plotting._docs import doc_spatial_base_plot, doc_gene_plot
21 | from stlearn.utils import Empty, _empty, _AxesSubplot, _docs_params
22 |
23 | from bokeh.io import push_notebook, output_notebook
24 | from bokeh.plotting import show
25 |
26 | # @_docs_params(spatial_base_plot=doc_spatial_base_plot, gene_plot=doc_gene_plot)
27 | def feat_plot(
28 | adata: AnnData,
29 | feature: str = None,
30 | threshold: Optional[float] = None,
31 | contour: bool = False,
32 | step_size: Optional[int] = None,
33 | title: Optional["str"] = None,
34 | figsize: Optional[Tuple[float, float]] = None,
35 | cmap: Optional[str] = "Spectral_r",
36 | use_label: Optional[str] = None,
37 | list_clusters: Optional[list] = None,
38 | ax: Optional[matplotlib.axes.Axes] = None,
39 | fig: Optional[matplotlib.figure.Figure] = None,
40 | show_plot: Optional[bool] = True,
41 | show_axis: Optional[bool] = False,
42 | show_image: Optional[bool] = True,
43 | show_color_bar: Optional[bool] = True,
44 | color_bar_label: Optional[str] = "",
45 | zoom_coord: Optional[float] = None,
46 | crop: Optional[bool] = True,
47 | margin: Optional[bool] = 100,
48 | size: Optional[float] = 7,
49 | image_alpha: Optional[float] = 1.0,
50 | cell_alpha: Optional[float] = 0.7,
51 | use_raw: Optional[bool] = False,
52 | fname: Optional[str] = None,
53 | dpi: Optional[int] = 120,
54 | vmin: Optional[float] = None,
55 | vmax: Optional[float] = None,
56 | ) -> Optional[AnnData]:
57 | """\
58 | Allows the visualization of a continuous features stored in adata.obs
59 | for Spatial transcriptomics array.
60 |
61 |
62 | Parameters
63 | -------------------------------------
64 | {spatial_base_plot}
65 | {feature_plot}
66 |
67 | Examples
68 | -------------------------------------
69 | >>> import stlearn as st
70 | >>> adata = st.datasets.example_bcba()
71 | >>> st.pl.gene_plot(adata, 'dpt_pseudotime')
72 |
73 | """
74 | FeaturePlot(
75 | adata,
76 | feature=feature,
77 | threshold=threshold,
78 | contour=contour,
79 | step_size=step_size,
80 | title=title,
81 | figsize=figsize,
82 | cmap=cmap,
83 | use_label=use_label,
84 | list_clusters=list_clusters,
85 | ax=ax,
86 | fig=fig,
87 | show_plot=show_plot,
88 | show_axis=show_axis,
89 | show_image=show_image,
90 | show_color_bar=show_color_bar,
91 | color_bar_label=color_bar_label,
92 | zoom_coord=zoom_coord,
93 | crop=crop,
94 | margin=margin,
95 | size=size,
96 | image_alpha=image_alpha,
97 | cell_alpha=cell_alpha,
98 | use_raw=use_raw,
99 | fname=fname,
100 | dpi=dpi,
101 | vmin=vmin,
102 | vmax=vmax,
103 | )
104 |
--------------------------------------------------------------------------------
/stlearn/plotting/gene_plot.py:
--------------------------------------------------------------------------------
1 | from matplotlib import pyplot as plt
2 | from PIL import Image
3 | import pandas as pd
4 | import matplotlib
5 | import numpy as np
6 |
7 | from typing import Optional, Union, Mapping # Special
8 | from typing import Sequence, Iterable # ABCs
9 | from typing import Tuple # Classes
10 |
11 | from anndata import AnnData
12 | import warnings
13 |
14 | from stlearn.plotting.classes import GenePlot
15 | from stlearn.plotting.classes_bokeh import BokehGenePlot
16 | from stlearn.plotting._docs import doc_spatial_base_plot, doc_gene_plot
17 | from stlearn.utils import Empty, _empty, _AxesSubplot, _docs_params
18 |
19 | from bokeh.io import push_notebook, output_notebook
20 | from bokeh.plotting import show
21 |
22 |
23 | @_docs_params(spatial_base_plot=doc_spatial_base_plot, gene_plot=doc_gene_plot)
24 | def gene_plot(
25 | adata: AnnData,
26 | gene_symbols: Union[str, list] = None,
27 | threshold: Optional[float] = None,
28 | method: str = "CumSum",
29 | contour: bool = False,
30 | step_size: Optional[int] = None,
31 | title: Optional["str"] = None,
32 | figsize: Optional[Tuple[float, float]] = None,
33 | cmap: Optional[str] = "Spectral_r",
34 | use_label: Optional[str] = None,
35 | list_clusters: Optional[list] = None,
36 | ax: Optional[matplotlib.axes.Axes] = None,
37 | fig: Optional[matplotlib.figure.Figure] = None,
38 | show_plot: Optional[bool] = True,
39 | show_axis: Optional[bool] = False,
40 | show_image: Optional[bool] = True,
41 | show_color_bar: Optional[bool] = True,
42 | color_bar_label: Optional[str] = "",
43 | zoom_coord: Optional[float] = None,
44 | crop: Optional[bool] = True,
45 | margin: Optional[bool] = 100,
46 | size: Optional[float] = 7,
47 | image_alpha: Optional[float] = 1.0,
48 | cell_alpha: Optional[float] = 0.7,
49 | use_raw: Optional[bool] = False,
50 | fname: Optional[str] = None,
51 | dpi: Optional[int] = 120,
52 | vmin: Optional[float] = None,
53 | vmax: Optional[float] = None,
54 | ) -> Optional[AnnData]:
55 | """\
56 | Allows the visualization of a single gene or multiple genes as the values
57 | of dot points or contour in the Spatial transcriptomics array.
58 |
59 |
60 | Parameters
61 | -------------------------------------
62 | {spatial_base_plot}
63 | {gene_plot}
64 |
65 | Examples
66 | -------------------------------------
67 | >>> import stlearn as st
68 | >>> adata = st.datasets.example_bcba()
69 | >>> genes = ["BRCA1","BRCA2"]
70 | >>> st.pl.gene_plot(adata, gene_symbols = genes)
71 |
72 | """
73 | GenePlot(
74 | adata,
75 | gene_symbols=gene_symbols,
76 | threshold=threshold,
77 | method=method,
78 | contour=contour,
79 | step_size=step_size,
80 | title=title,
81 | figsize=figsize,
82 | cmap=cmap,
83 | use_label=use_label,
84 | list_clusters=list_clusters,
85 | ax=ax,
86 | fig=fig,
87 | show_plot=show_plot,
88 | show_axis=show_axis,
89 | show_image=show_image,
90 | show_color_bar=show_color_bar,
91 | color_bar_label=color_bar_label,
92 | zoom_coord=zoom_coord,
93 | crop=crop,
94 | margin=margin,
95 | size=size,
96 | image_alpha=image_alpha,
97 | cell_alpha=cell_alpha,
98 | use_raw=use_raw,
99 | fname=fname,
100 | dpi=dpi,
101 | vmin=vmin,
102 | vmax=vmax,
103 | )
104 |
105 |
106 | def gene_plot_interactive(adata: AnnData):
107 | bokeh_object = BokehGenePlot(adata)
108 | output_notebook()
109 | show(bokeh_object.app, notebook_handle=True)
110 |
--------------------------------------------------------------------------------
/stlearn/plotting/non_spatial_plot.py:
--------------------------------------------------------------------------------
1 | from matplotlib import pyplot as plt
2 | from PIL import Image
3 | import pandas as pd
4 | import matplotlib
5 | import numpy as np
6 |
7 | from stlearn._compat import Literal
8 | from typing import Optional, Union
9 | from anndata import AnnData
10 | import warnings
11 |
12 | # from .utils import get_img_from_fig, checkType
13 | import scanpy
14 |
15 |
16 | def non_spatial_plot(
17 | adata: AnnData,
18 | use_label: str = "louvain",
19 | ) -> Optional[AnnData]:
20 |
21 | """\
22 | A wrap function to plot all the non-spatial plot from scanpy.
23 |
24 | This function will produce 3 plots: PAGA graph, cluster plot in PAGA space and
25 | DPT in PAGA space.
26 |
27 | Parameters
28 | ----------
29 | adata
30 | Annotated data matrix.
31 | use_label
32 | Use label result of cluster method.
33 | dpi
34 | Set dpi as the resolution for the plot.
35 | Returns
36 | -------
37 | Nothing
38 | """
39 |
40 | # plt.rcParams['figure.dpi'] = dpi
41 |
42 | if "paga" in adata.uns.keys():
43 | # adata.uns[use_label+"_colors"] = adata.uns["tmp_color"]
44 |
45 | print("PAGA plot:")
46 |
47 | scanpy.pl.paga(adata, color=use_label)
48 |
49 | scanpy.tl.draw_graph(adata, init_pos="paga")
50 | # adata.uns[use_label+"_colors"] = adata.uns["tmp_color"]
51 |
52 | print("Gene expression (reduced dimension) plot:")
53 | scanpy.pl.draw_graph(adata, color=use_label, legend_loc="on data")
54 |
55 | print("Diffusion pseudotime plot:")
56 | scanpy.pl.draw_graph(adata, color="dpt_pseudotime")
57 |
58 | else:
59 |
60 | scanpy.pl.draw_graph(adata)
61 | # adata.uns[use_label+"_colors"] = adata.uns["tmp_color"]
62 |
63 | scanpy.pl.draw_graph(adata, color=use_label, legend_loc="on data")
64 |
--------------------------------------------------------------------------------
/stlearn/plotting/palettes_st.py:
--------------------------------------------------------------------------------
1 | jana_40 = [
2 | "#5C5C5C",
3 | "#969696",
4 | "#BEBEBE",
5 | "#8B0000",
6 | "#EE5C42",
7 | "#8B3E2F",
8 | "#CD3700",
9 | "#FF7F24",
10 | "#F4A460",
11 | "#FFA500",
12 | "#8B5A00",
13 | "#8B8B00",
14 | "#FFFF00",
15 | "#9ACD32",
16 | "#ADFF2F",
17 | "#458B00",
18 | "#90EE90",
19 | "#32CD32",
20 | "#008B45",
21 | "#7FFFD4",
22 | "#458B74",
23 | "#008B8B",
24 | "#5F9EA0",
25 | "#00C5CD",
26 | "#009ACD",
27 | "#00688B",
28 | "#B0E2FF",
29 | "#4682B4",
30 | "#1E90FF",
31 | "#000080",
32 | "#0000CD",
33 | "#8470FF",
34 | "#7B68EE",
35 | "#9B30FF",
36 | "#BF3EFF",
37 | "#EED2EE",
38 | "#8B668B",
39 | "#EE82EE",
40 | "#8B008B",
41 | "#D02090",
42 | "#FF1493",
43 | ]
44 |
45 | default = [
46 | "#1f77b4",
47 | "#ff7f0e",
48 | "#279e68",
49 | "#d62728",
50 | "#633194",
51 | "#8c564b",
52 | "#F73BAD",
53 | "#F6E800",
54 | "#01F7F7",
55 | "#aec7e8",
56 | "#ffbb78",
57 | "#98df8a",
58 | "#ff9896",
59 | "#c5b0d5",
60 | "#c49c94",
61 | "#f7b6d2",
62 | "#dbdb8d",
63 | "#9edae5",
64 | "#ad494a",
65 | "#8c6d31",
66 | ]
67 |
--------------------------------------------------------------------------------
/stlearn/plotting/stack_3d_plot.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | from anndata import AnnData
3 | import pandas as pd
4 |
5 |
6 | def stack_3d_plot(
7 | adata: AnnData,
8 | slides,
9 | cmap="viridis",
10 | slide_col="sample_id",
11 | use_label=None,
12 | gene_symbol=None,
13 | ) -> Optional[AnnData]:
14 |
15 | """\
16 | Clustering plot for sptial transcriptomics data. Also it has a function to display trajectory inference.
17 |
18 | Parameters
19 | ----------
20 | adata
21 | Annotated data matrix.
22 | slides
23 | A list of slide id
24 | cmap
25 | Color map
26 | use_label
27 | Choose label to plot (priotize)
28 | gene_symbol
29 | Choose gene symbol to plot
30 | width
31 | Witdh of the plot
32 | height
33 | Height of the plot
34 | Returns
35 | -------
36 | Nothing
37 | """
38 | try:
39 | import plotly.express as px
40 | except ModuleNotFoundError:
41 | raise ModuleNotFoundError("Please install plotly by `pip install plotly`")
42 |
43 | assert (
44 | slide_col in adata.obs.columns
45 | ), "Please provide the right column for slide_id!"
46 |
47 | list_df = []
48 | for i, slide in enumerate(slides):
49 | tmp = data.obs[data.obs[slide_col] == slide][["imagecol", "imagerow"]]
50 | tmp["sample_id"] = slide
51 | tmp["z-dimension"] = i
52 | list_df.append(tmp)
53 |
54 | df = pd.concat(list_df)
55 |
56 | if use_label != None:
57 | assert use_label in adata.obs.columns, "Please use the right `use_label`"
58 | df[use_label] = adata[df.index].obs[use_label].values
59 |
60 | fig = px.scatter_3d(
61 | df,
62 | x="imagecol",
63 | y="imagerow",
64 | z="z-dimension",
65 | color=use_label,
66 | width=width,
67 | height=height,
68 | color_continuous_scale=cmap,
69 | )
70 | fig.show()
71 |
72 | else:
73 | assert gene_symbol in adata.var_names, "Please use the right `gene_symbol`"
74 | df[gene_symbol] = adata[df.index][:, gene_symbol].X
75 |
76 | fig = px.scatter_3d(
77 | df,
78 | x="imagecol",
79 | y="imagerow",
80 | z="z-dimension",
81 | color=gene_symbol,
82 | width=width,
83 | height=height,
84 | color_continuous_scale=cmap,
85 | )
86 | fig.show()
87 |
--------------------------------------------------------------------------------
/stlearn/plotting/subcluster_plot.py:
--------------------------------------------------------------------------------
1 | from matplotlib import pyplot as plt
2 | from PIL import Image
3 | import pandas as pd
4 | import matplotlib
5 | import numpy as np
6 |
7 | from typing import Optional, Union, Mapping # Special
8 | from typing import Sequence, Iterable # ABCs
9 | from typing import Tuple # Classes
10 |
11 | from anndata import AnnData
12 | import warnings
13 |
14 | from stlearn.plotting.classes import SubClusterPlot
15 | from stlearn.plotting._docs import doc_spatial_base_plot, doc_subcluster_plot
16 | from stlearn.utils import _AxesSubplot, Axes, _docs_params
17 |
18 |
19 | @_docs_params(
20 | spatial_base_plot=doc_spatial_base_plot, subcluster_plot=doc_subcluster_plot
21 | )
22 | def subcluster_plot(
23 | adata: AnnData,
24 | # plotting param
25 | title: Optional["str"] = None,
26 | figsize: Optional[Tuple[float, float]] = None,
27 | cmap: Optional[str] = "jet",
28 | use_label: Optional[str] = None,
29 | list_clusters: Optional[list] = None,
30 | ax: Optional[_AxesSubplot] = None,
31 | show_plot: Optional[bool] = True,
32 | show_axis: Optional[bool] = False,
33 | show_image: Optional[bool] = True,
34 | show_color_bar: Optional[bool] = True,
35 | crop: Optional[bool] = True,
36 | margin: Optional[bool] = 100,
37 | size: Optional[float] = 5,
38 | image_alpha: Optional[float] = 1.0,
39 | cell_alpha: Optional[float] = 1.0,
40 | fname: Optional[str] = None,
41 | dpi: Optional[int] = 120,
42 | # subcluster plot param
43 | cluster: Optional[int] = 0,
44 | threshold_spots: Optional[int] = 5,
45 | text_box_size: Optional[float] = 5,
46 | bbox_to_anchor: Optional[Tuple[float, float]] = (1, 1),
47 | ) -> Optional[AnnData]:
48 | """\
49 | Allows the visualization of a subclustering results as the discretes values
50 | of dot points in the Spatial transcriptomics array.
51 |
52 | Parameters
53 | -------------------------------------
54 | {spatial_base_plot}
55 | {subcluster_plot}
56 |
57 | Examples
58 | -------------------------------------
59 | >>> import stlearn as st
60 | >>> adata = st.datasets.example_bcba()
61 | >>> label = "louvain"
62 | >>> cluster = 6
63 | >>> st.pl.cluster_plot(adata, use_label = label, cluster = cluster)
64 |
65 | """
66 |
67 | assert use_label != None, "Please select `use_label` parameter"
68 | assert (
69 | use_label in adata.obs.columns
70 | ), "Please run `stlearn.spatial.cluster.localization` function!"
71 |
72 | SubClusterPlot(
73 | adata,
74 | title=title,
75 | figsize=figsize,
76 | cmap=cmap,
77 | use_label=use_label,
78 | list_clusters=list_clusters,
79 | ax=ax,
80 | show_plot=show_plot,
81 | show_axis=show_axis,
82 | show_image=show_image,
83 | show_color_bar=show_color_bar,
84 | crop=crop,
85 | margin=margin,
86 | size=size,
87 | image_alpha=image_alpha,
88 | cell_alpha=cell_alpha,
89 | fname=fname,
90 | dpi=dpi,
91 | text_box_size=text_box_size,
92 | bbox_to_anchor=bbox_to_anchor,
93 | cluster=cluster,
94 | threshold_spots=threshold_spots,
95 | )
96 |
--------------------------------------------------------------------------------
/stlearn/plotting/trajectory/__init__.py:
--------------------------------------------------------------------------------
1 | from .pseudotime_plot import pseudotime_plot
2 | from .local_plot import local_plot
3 | from .tree_plot_simple import tree_plot_simple
4 | from .tree_plot import tree_plot
5 | from .transition_markers_plot import transition_markers_plot
6 | from .DE_transition_plot import DE_transition_plot
7 | from .check_trajectory import check_trajectory
8 |
--------------------------------------------------------------------------------
/stlearn/plotting/trajectory/check_trajectory.py:
--------------------------------------------------------------------------------
1 | from anndata import AnnData
2 | from typing import Optional, Union
3 | import matplotlib.pyplot as plt
4 | import scanpy as sc
5 | import numpy as np
6 |
7 |
8 | def check_trajectory(
9 | adata: AnnData,
10 | library_id: str = None,
11 | use_label: str = "louvain",
12 | basis: str = "umap",
13 | pseudotime_key: str = "dpt_pseudotime",
14 | trajectory: list = None,
15 | figsize=(10, 4),
16 | size_umap: int = 50,
17 | size_spatial: int = 1.5,
18 | img_key: str = "hires",
19 | ) -> Optional[AnnData]:
20 | trajectory = np.array(trajectory).astype(int)
21 | assert (
22 | trajectory in adata.uns["available_paths"].values()
23 | ), "Please choose the right path!"
24 | trajectory = trajectory.astype(str)
25 | assert (
26 | pseudotime_key in adata.obs.columns
27 | ), "Please run the pseudotime or choose the right one!"
28 | assert (
29 | use_label in adata.obs.columns
30 | ), "Please run the cluster or choose the right label!"
31 | assert basis in adata.obsm, (
32 | "Please run the " + basis + "before you check the trajectory!"
33 | )
34 | if library_id is None:
35 | library_id = list(adata.uns["spatial"].keys())[0]
36 |
37 | adata.obsm["X_spatial"] = adata.obs[["imagecol", "imagerow"]].values
38 |
39 | fig, (ax1, ax2) = plt.subplots(1, 2, figsize=figsize)
40 |
41 | ax1 = sc.pl.umap(adata, size=size_umap, show=False, ax=ax1)
42 | sc.pl.umap(
43 | adata[adata.obs[use_label].isin(trajectory)],
44 | size=size_umap,
45 | color=pseudotime_key,
46 | ax=ax1,
47 | show=False,
48 | frameon=False,
49 | )
50 |
51 | ax2 = sc.pl.scatter(
52 | adata,
53 | size=25,
54 | show=False,
55 | basis="spatial",
56 | ax=ax2,
57 | )
58 | sc.pl.spatial(
59 | adata[adata.obs[use_label].isin(trajectory)],
60 | size=size_spatial,
61 | ax=ax2,
62 | color=pseudotime_key,
63 | legend_loc="none",
64 | basis="spatial",
65 | frameon=False,
66 | show=False,
67 | )
68 |
69 | im = ax2.imshow(
70 | adata.uns["spatial"][library_id]["images"][img_key], alpha=0, zorder=-1
71 | )
72 |
73 | plt.show()
74 |
75 | del adata.obsm["X_spatial"]
76 |
--------------------------------------------------------------------------------
/stlearn/plotting/trajectory/utils.py:
--------------------------------------------------------------------------------
1 | def checkType(arr, n=2):
2 |
3 | # If the first two and the last two elements
4 | # of the array are in increasing order
5 | if arr[0] <= arr[1] and arr[n - 2] <= arr[n - 1]:
6 | return True
7 |
8 | # If the first two and the last two elements
9 | # of the array are in decreasing order
10 | elif arr[0] >= arr[1] and arr[n - 2] >= arr[n - 1]:
11 | return False
12 |
--------------------------------------------------------------------------------
/stlearn/pp.py:
--------------------------------------------------------------------------------
1 | from .preprocessing.filter_genes import filter_genes
2 | from .preprocessing.normalize import normalize_total
3 | from .preprocessing.log_scale import log1p
4 | from .preprocessing.log_scale import scale
5 | from .preprocessing.graph import neighbors
6 | from .image_preprocessing.image_tiling import tiling
7 | from .image_preprocessing.feature_extractor import extract_feature
8 |
--------------------------------------------------------------------------------
/stlearn/preprocessing/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/preprocessing/__init__.py
--------------------------------------------------------------------------------
/stlearn/preprocessing/filter_genes.py:
--------------------------------------------------------------------------------
1 | from typing import Union, Optional, Tuple, Collection, Sequence, Iterable
2 | from anndata import AnnData
3 | import numpy as np
4 | from scipy.sparse import issparse, isspmatrix_csr, csr_matrix, spmatrix
5 | import scanpy
6 |
7 |
8 | def filter_genes(
9 | adata: AnnData,
10 | min_counts: Optional[int] = None,
11 | min_cells: Optional[int] = None,
12 | max_counts: Optional[int] = None,
13 | max_cells: Optional[int] = None,
14 | inplace: bool = True,
15 | ) -> Union[AnnData, None, Tuple[np.ndarray, np.ndarray]]:
16 | """\
17 | Wrap function scanpy.pp.filter_genes
18 |
19 | Filter genes based on number of cells or counts.
20 | Keep genes that have at least `min_counts` counts or are expressed in at
21 | least `min_cells` cells or have at most `max_counts` counts or are expressed
22 | in at most `max_cells` cells.
23 | Only provide one of the optional parameters `min_counts`, `min_cells`,
24 | `max_counts`, `max_cells` per call.
25 | Parameters
26 | ----------
27 | data
28 | An annotated data matrix of shape `n_obs` × `n_vars`. Rows correspond
29 | to cells and columns to genes.
30 | min_counts
31 | Minimum number of counts required for a gene to pass filtering.
32 | min_cells
33 | Minimum number of cells expressed required for a gene to pass filtering.
34 | max_counts
35 | Maximum number of counts required for a gene to pass filtering.
36 | max_cells
37 | Maximum number of cells expressed required for a gene to pass filtering.
38 | inplace
39 | Perform computation inplace or return result.
40 | Returns
41 | -------
42 | Depending on `inplace`, returns the following arrays or directly subsets
43 | and annotates the data matrix
44 | gene_subset
45 | Boolean index mask that does filtering. `True` means that the
46 | gene is kept. `False` means the gene is removed.
47 | number_per_gene
48 | Depending on what was tresholded (`counts` or `cells`), the array stores
49 | `n_counts` or `n_cells` per gene.
50 | """
51 |
52 | scanpy.pp.filter_genes(
53 | adata,
54 | min_counts=min_counts,
55 | min_cells=min_cells,
56 | max_counts=max_counts,
57 | max_cells=max_cells,
58 | inplace=inplace,
59 | )
60 |
--------------------------------------------------------------------------------
/stlearn/preprocessing/graph.py:
--------------------------------------------------------------------------------
1 | from types import MappingProxyType
2 | from typing import Union, Optional, Any, Mapping, Callable
3 |
4 | import numpy as np
5 | import scipy
6 | from anndata import AnnData
7 | from numpy.random import RandomState
8 | from .._compat import Literal
9 | import scanpy
10 |
11 | _Method = Literal["umap", "gauss", "rapids"]
12 | _MetricFn = Callable[[np.ndarray, np.ndarray], float]
13 | # from sklearn.metrics.pairwise_distances.__doc__:
14 | _MetricSparseCapable = Literal[
15 | "cityblock", "cosine", "euclidean", "l1", "l2", "manhattan"
16 | ]
17 | _MetricScipySpatial = Literal[
18 | "braycurtis",
19 | "canberra",
20 | "chebyshev",
21 | "correlation",
22 | "dice",
23 | "hamming",
24 | "jaccard",
25 | "kulsinski",
26 | "mahalanobis",
27 | "minkowski",
28 | "rogerstanimoto",
29 | "russellrao",
30 | "seuclidean",
31 | "sokalmichener",
32 | "sokalsneath",
33 | "sqeuclidean",
34 | "yule",
35 | ]
36 | _Metric = Union[_MetricSparseCapable, _MetricScipySpatial]
37 |
38 |
39 | def neighbors(
40 | adata: AnnData,
41 | n_neighbors: int = 15,
42 | n_pcs: Optional[int] = None,
43 | use_rep: Optional[str] = None,
44 | knn: bool = True,
45 | random_state: Optional[Union[int, RandomState]] = 0,
46 | method: Optional[_Method] = "umap",
47 | metric: Union[_Metric, _MetricFn] = "euclidean",
48 | metric_kwds: Mapping[str, Any] = MappingProxyType({}),
49 | copy: bool = False,
50 | ) -> Optional[AnnData]:
51 | """\
52 | Compute a neighborhood graph of observations [McInnes18]_.
53 | The neighbor search efficiency of this heavily relies on UMAP [McInnes18]_,
54 | which also provides a method for estimating connectivities of data points -
55 | the connectivity of the manifold (`method=='umap'`). If `method=='gauss'`,
56 | connectivities are computed according to [Coifman05]_, in the adaption of
57 | [Haghverdi16]_.
58 | Parameters
59 | ----------
60 | adata
61 | Annotated data matrix.
62 | n_neighbors
63 | The size of local neighborhood (in terms of number of neighboring data
64 | points) used for manifold approximation. Larger values result in more
65 | global views of the manifold, while smaller values result in more local
66 | data being preserved. In general values should be in the range 2 to 100.
67 | If `knn` is `True`, number of nearest neighbors to be searched. If `knn`
68 | is `False`, a Gaussian kernel width is set to the distance of the
69 | `n_neighbors` neighbor.
70 | {n_pcs}
71 | {use_rep}
72 | knn
73 | If `True`, use a hard threshold to restrict the number of neighbors to
74 | `n_neighbors`, that is, consider a knn graph. Otherwise, use a Gaussian
75 | Kernel to assign low weights to neighbors more distant than the
76 | `n_neighbors` nearest neighbor.
77 | random_state
78 | A numpy random seed.
79 | method
80 | Use 'umap' [McInnes18]_ or 'gauss' (Gauss kernel following [Coifman05]_
81 | with adaptive width [Haghverdi16]_) for computing connectivities.
82 | Use 'rapids' for the RAPIDS implementation of UMAP (experimental, GPU
83 | only).
84 | metric
85 | A known metric’s name or a callable that returns a distance.
86 | metric_kwds
87 | Options for the metric.
88 | copy
89 | Return a copy instead of writing to adata.
90 | Returns
91 | -------
92 | Depending on `copy`, updates or returns `adata` with the following:
93 | **connectivities** : sparse matrix (`.uns['neighbors']`, dtype `float32`)
94 | Weighted adjacency matrix of the neighborhood graph of data
95 | points. Weights should be interpreted as connectivities.
96 | **distances** : sparse matrix (`.uns['neighbors']`, dtype `float32`)
97 | Instead of decaying weights, this stores distances for each pair of
98 | neighbors.
99 | """
100 |
101 | scanpy.pp.neighbors(
102 | adata,
103 | n_neighbors=n_neighbors,
104 | n_pcs=n_pcs,
105 | use_rep=use_rep,
106 | knn=knn,
107 | random_state=random_state,
108 | method=method,
109 | metric=metric,
110 | metric_kwds=metric_kwds,
111 | copy=copy,
112 | )
113 |
114 | print("Created k-Nearest-Neighbor graph in adata.uns['neighbors'] ")
115 |
--------------------------------------------------------------------------------
/stlearn/preprocessing/log_scale.py:
--------------------------------------------------------------------------------
1 | from typing import Union, Optional, Tuple, Collection, Sequence, Iterable
2 | from anndata import AnnData
3 | import numpy as np
4 | from scipy.sparse import issparse, isspmatrix_csr, csr_matrix, spmatrix
5 | from scipy import sparse
6 | from stlearn import logging as logg
7 | import scanpy
8 |
9 |
10 | def log1p(
11 | adata: Union[AnnData, np.ndarray, spmatrix],
12 | copy: bool = False,
13 | chunked: bool = False,
14 | chunk_size: Optional[int] = None,
15 | base: Optional[float] = None,
16 | ) -> Optional[AnnData]:
17 | """\
18 | Wrap function of scanpy.pp.log1p
19 | Copyright (c) 2017 F. Alexander Wolf, P. Angerer, Theis Lab
20 |
21 | Logarithmize the data matrix.
22 | Computes :math:`X = \\log(X + 1)`,
23 | where :math:`log` denotes the natural logarithm unless a different base is given.
24 | Parameters
25 | ----------
26 | data
27 | The (annotated) data matrix of shape `n_obs` × `n_vars`.
28 | Rows correspond to cells and columns to genes.
29 | copy
30 | If an :class:`~anndata.AnnData` is passed, determines whether a copy
31 | is returned.
32 | chunked
33 | Process the data matrix in chunks, which will save memory.
34 | Applies only to :class:`~anndata.AnnData`.
35 | chunk_size
36 | `n_obs` of the chunks to process the data in.
37 | base
38 | Base of the logarithm. Natural logarithm is used by default.
39 | Returns
40 | -------
41 | Returns or updates `data`, depending on `copy`.
42 | """
43 |
44 | scanpy.pp.log1p(adata, copy=copy, chunked=chunked, chunk_size=chunk_size, base=base)
45 |
46 | print("Log transformation step is finished in adata.X")
47 |
48 |
49 | def scale(
50 | adata: Union[AnnData, np.ndarray, spmatrix],
51 | zero_center: bool = True,
52 | max_value: Optional[float] = None,
53 | copy: bool = False,
54 | ) -> Optional[AnnData]:
55 | """\
56 | Wrap function of scanpy.pp.scale
57 |
58 | Scale data to unit variance and zero mean.
59 | .. note::
60 | Variables (genes) that do not display any variation (are constant across
61 | all observations) are retained and set to 0 during this operation. In
62 | the future, they might be set to NaNs.
63 | Parameters
64 | ----------
65 | data
66 | The (annotated) data matrix of shape `n_obs` × `n_vars`.
67 | Rows correspond to cells and columns to genes.
68 | zero_center
69 | If `False`, omit zero-centering variables, which allows to handle sparse
70 | input efficiently.
71 | max_value
72 | Clip (truncate) to this value after scaling. If `None`, do not clip.
73 | copy
74 | If an :class:`~anndata.AnnData` is passed,
75 | determines whether a copy is returned.
76 | Returns
77 | -------
78 | Depending on `copy` returns or updates `adata` with a scaled `adata.X`.
79 | """
80 |
81 | scanpy.pp.scale(adata, zero_center=zero_center, max_value=max_value, copy=copy)
82 |
83 | print("Scale step is finished in adata.X")
84 |
--------------------------------------------------------------------------------
/stlearn/preprocessing/normalize.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union, Iterable, Dict
2 |
3 | import numpy as np
4 | from anndata import AnnData
5 | from scipy.sparse import issparse
6 | from sklearn.utils import sparsefuncs
7 | from stlearn._compat import Literal
8 | import scanpy
9 |
10 |
11 | def normalize_total(
12 | adata: AnnData,
13 | target_sum: Optional[float] = None,
14 | exclude_highly_expressed: bool = False,
15 | max_fraction: float = 0.05,
16 | key_added: Optional[str] = None,
17 | layers: Union[Literal["all"], Iterable[str]] = None,
18 | layer_norm: Optional[str] = None,
19 | inplace: bool = True,
20 | ) -> Optional[Dict[str, np.ndarray]]:
21 | """\
22 | Wrap function from scanpy.pp.log1p
23 | Normalize counts per cell.
24 | If choosing `target_sum=1e6`, this is CPM normalization.
25 | If `exclude_highly_expressed=True`, very highly expressed genes are excluded
26 | from the computation of the normalization factor (size factor) for each
27 | cell. This is meaningful as these can strongly influence the resulting
28 | normalized values for all other genes [Weinreb17]_.
29 | Similar functions are used, for example, by Seurat [Satija15]_, Cell Ranger
30 | [Zheng17]_ or SPRING [Weinreb17]_.
31 | Params
32 | ------
33 | adata
34 | The annotated data matrix of shape `n_obs` × `n_vars`.
35 | Rows correspond to cells and columns to genes.
36 | target_sum
37 | If `None`, after normalization, each observation (cell) has a total
38 | count equal to the median of total counts for observations (cells)
39 | before normalization.
40 | exclude_highly_expressed
41 | Exclude (very) highly expressed genes for the computation of the
42 | normalization factor (size factor) for each cell. A gene is considered
43 | highly expressed, if it has more than `max_fraction` of the total counts
44 | in at least one cell. The not-excluded genes will sum up to
45 | `target_sum`.
46 | max_fraction
47 | If `exclude_highly_expressed=True`, consider cells as highly expressed
48 | that have more counts than `max_fraction` of the original total counts
49 | in at least one cell.
50 | key_added
51 | Name of the field in `adata.obs` where the normalization factor is
52 | stored.
53 | layers
54 | List of layers to normalize. Set to `'all'` to normalize all layers.
55 | layer_norm
56 | Specifies how to normalize layers:
57 | * If `None`, after normalization, for each layer in *layers* each cell
58 | has a total count equal to the median of the *counts_per_cell* before
59 | normalization of the layer.
60 | * If `'after'`, for each layer in *layers* each cell has
61 | a total count equal to `target_sum`.
62 | * If `'X'`, for each layer in *layers* each cell has a total count
63 | equal to the median of total counts for observations (cells) of
64 | `adata.X` before normalization.
65 | inplace
66 | Whether to update `adata` or return dictionary with normalized copies of
67 | `adata.X` and `adata.layers`.
68 | Returns
69 | -------
70 | Returns dictionary with normalized copies of `adata.X` and `adata.layers`
71 | or updates `adata` with normalized version of the original
72 | `adata.X` and `adata.layers`, depending on `inplace`.
73 | """
74 |
75 | scanpy.pp.normalize_total(
76 | adata,
77 | target_sum=target_sum,
78 | exclude_highly_expressed=exclude_highly_expressed,
79 | max_fraction=max_fraction,
80 | key_added=key_added,
81 | layers=layers,
82 | layer_norm=layer_norm,
83 | inplace=inplace,
84 | )
85 |
86 | print("Normalization step is finished in adata.X")
87 |
--------------------------------------------------------------------------------
/stlearn/spatial.py:
--------------------------------------------------------------------------------
1 | from .spatials import clustering
2 | from .spatials import smooth
3 | from .spatials import trajectory
4 | from .spatials import morphology
5 | from .spatials import SME
6 |
--------------------------------------------------------------------------------
/stlearn/spatials/SME/__init__.py:
--------------------------------------------------------------------------------
1 | from .normalize import SME_normalize
2 | from .impute import SME_impute0, pseudo_spot
3 |
--------------------------------------------------------------------------------
/stlearn/spatials/SME/normalize.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 | from anndata import AnnData
3 | import numpy as np
4 | from scipy.sparse import csr_matrix
5 | import pandas as pd
6 | from ._weighting_matrix import (
7 | calculate_weight_matrix,
8 | impute_neighbour,
9 | _WEIGHTING_MATRIX,
10 | _PLATFORM,
11 | )
12 |
13 |
14 | def SME_normalize(
15 | adata: AnnData,
16 | use_data: str = "raw",
17 | weights: _WEIGHTING_MATRIX = "weights_matrix_all",
18 | platform: _PLATFORM = "Visium",
19 | copy: bool = False,
20 | ) -> Optional[AnnData]:
21 | """\
22 | using spatial location (S), tissue morphological feature (M) and gene expression (E) information to normalize data.
23 |
24 | Parameters
25 | ----------
26 | adata
27 | Annotated data matrix.
28 | use_data
29 | Input data, can be `raw` counts or log transformed data
30 | weights
31 | Weighting matrix for imputation.
32 | if `weights_matrix_all`, matrix combined all information from spatial location (S),
33 | tissue morphological feature (M) and gene expression (E)
34 | if `weights_matrix_pd_md`, matrix combined information from spatial location (S),
35 | tissue morphological feature (M)
36 | platform
37 | `Visium` or `Old_ST`
38 | copy
39 | Return a copy instead of writing to adata.
40 | Returns
41 | -------
42 | Anndata
43 | """
44 | if use_data == "raw":
45 | if isinstance(adata.X, csr_matrix):
46 | count_embed = adata.X.toarray()
47 | elif isinstance(adata.X, np.ndarray):
48 | count_embed = adata.X
49 | elif isinstance(adata.X, pd.Dataframe):
50 | count_embed = adata.X.values
51 | else:
52 | raise ValueError(
53 | f"""\
54 | {type(adata.X)} is not a valid type.
55 | """
56 | )
57 | else:
58 | count_embed = adata.obsm[use_data]
59 |
60 | calculate_weight_matrix(adata, platform=platform)
61 |
62 | impute_neighbour(adata, count_embed=count_embed, weights=weights)
63 |
64 | imputed_data = adata.obsm["imputed_data"].astype(float)
65 | imputed_data[imputed_data == 0] = np.nan
66 | adjusted_count_matrix = np.nanmean(np.array([count_embed, imputed_data]), axis=0)
67 |
68 | key_added = use_data + "_SME_normalized"
69 | adata.obsm[key_added] = adjusted_count_matrix
70 |
71 | print("The data adjusted by SME is added to adata.obsm['" + key_added + "']")
72 |
73 | return adata if copy else None
74 |
--------------------------------------------------------------------------------
/stlearn/spatials/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/spatials/__init__.py
--------------------------------------------------------------------------------
/stlearn/spatials/clustering/__init__.py:
--------------------------------------------------------------------------------
1 | from .localization import localization
2 |
--------------------------------------------------------------------------------
/stlearn/spatials/clustering/localization.py:
--------------------------------------------------------------------------------
1 | from anndata import AnnData
2 | from typing import Optional, Union
3 | import numpy as np
4 | import pandas as pd
5 | from sklearn.cluster import DBSCAN
6 | from natsort import natsorted
7 |
8 |
9 | def localization(
10 | adata: AnnData,
11 | use_label: str = "louvain",
12 | eps: int = 20,
13 | min_samples: int = 0,
14 | copy: bool = False,
15 | ) -> Optional[AnnData]:
16 |
17 | """\
18 | Perform local cluster by using DBSCAN.
19 |
20 | Parameters
21 | ----------
22 | adata
23 | Annotated data matrix.
24 | use_label
25 | Use label result of cluster method.
26 | eps
27 | The maximum distance between two samples for one to be considered as
28 | in the neighborhood of the other. This is not a maximum bound on the
29 | distances of points within a cluster. This is the most important DBSCAN
30 | parameter to choose appropriately for your data set and distance function.
31 | min_samples
32 | The number of samples (or total weight) in a neighborhood for a point to be
33 | considered as a core point. This includes the point itself.
34 | copy
35 | Return a copy instead of writing to adata.
36 | Returns
37 | -------
38 | Anndata
39 | """
40 |
41 | if "sub_cluster_labels" in adata.obs.columns:
42 | adata.obs = adata.obs.drop("sub_cluster_labels", axis=1)
43 |
44 | pd.set_option("mode.chained_assignment", None)
45 | subclusters_list = []
46 | for i in adata.obs[use_label].unique():
47 |
48 | tmp = adata.obs[adata.obs[use_label] == i]
49 |
50 | clustering = DBSCAN(eps=eps, min_samples=1, algorithm="kd_tree").fit(
51 | tmp[["imagerow", "imagecol"]]
52 | )
53 |
54 | labels = clustering.labels_
55 |
56 | sublabels = []
57 | for label in labels:
58 | sublabels.append(str(i) + "_" + str(label))
59 | tmp["sub_labels"] = sublabels
60 | subclusters_list.append(tmp["sub_labels"])
61 |
62 | subclusters = pd.concat(subclusters_list)
63 | pd.reset_option("mode.chained_assignment")
64 |
65 | adata.obs = pd.merge(
66 | adata.obs,
67 | pd.DataFrame({"sub_cluster_labels": subclusters}),
68 | left_index=True,
69 | right_index=True,
70 | )
71 |
72 | # Convert to numeric
73 | converted = dict(enumerate(adata.obs["sub_cluster_labels"].unique()))
74 | inv_map = {v: str(k) for k, v in converted.items()}
75 | adata.obs["sub_cluster_labels"] = adata.obs["sub_cluster_labels"].replace(inv_map)
76 |
77 | adata.obs["sub_cluster_labels"] = pd.Categorical(
78 | values=np.array(adata.obs["sub_cluster_labels"]).astype("U"),
79 | categories=natsorted(
80 | np.unique(np.array(adata.obs["sub_cluster_labels"])).astype("U")
81 | ),
82 | )
83 |
84 | labels_cat = adata.obs[use_label].cat.categories
85 | cat_ind = {labels_cat[i]: i for i in range(len(labels_cat))}
86 | adata.uns[use_label + "_index_dict"] = cat_ind
87 |
88 | return adata if copy else None
89 |
--------------------------------------------------------------------------------
/stlearn/spatials/morphology/__init__.py:
--------------------------------------------------------------------------------
1 | from .adjust import adjust
2 |
--------------------------------------------------------------------------------
/stlearn/spatials/smooth/__init__.py:
--------------------------------------------------------------------------------
1 | from .disk import disk
2 |
--------------------------------------------------------------------------------
/stlearn/spatials/smooth/disk.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | import numpy as np
3 | from anndata import AnnData
4 | import logging as logg
5 | import scipy.spatial as spatial
6 |
7 |
8 | def disk(
9 | adata: AnnData,
10 | use_data: str = "X_umap",
11 | radius: float = 10.0,
12 | rates: int = 1,
13 | method: str = "mean",
14 | copy: bool = False,
15 | ) -> Optional[AnnData]:
16 |
17 | coor = adata.obs[["imagecol", "imagerow"]]
18 | count_embed = adata.obsm[use_data]
19 | point_tree = spatial.cKDTree(coor)
20 |
21 | lag_coor = []
22 | tmp = []
23 |
24 | for i in range(len(coor)):
25 | current_neightbor = point_tree.query_ball_point(
26 | coor.values[i], radius
27 | ) # Spatial weight
28 | # print(coor.values[i])
29 | tmp.append(current_neightbor)
30 | # print(coor.values[current_neightbor])
31 | main = count_embed[current_neightbor]
32 | current_neightbor.remove(i)
33 | addition = count_embed[current_neightbor]
34 |
35 | for i in range(0, rates):
36 | main = np.append(main, addition, axis=0)
37 | if method == "mean":
38 | # New umap based on SW
39 | lag_coor.append(list(np.mean(main, axis=0)))
40 | elif method == "median":
41 | # New umap based on SW
42 | lag_coor.append(list(np.median(main, axis=0)))
43 | else:
44 | raise ValueError("Only 'median' and 'mean' are aceptable")
45 |
46 | new_embed = use_data + "_disk"
47 |
48 | adata.obsm[new_embed] = np.array(lag_coor)
49 |
50 | print(
51 | 'Disk smoothing function is applied! The new data are stored in adata.obsm["X_diffmap_disk"]'
52 | )
53 |
54 | return adata if copy else None
55 |
--------------------------------------------------------------------------------
/stlearn/spatials/trajectory/__init__.py:
--------------------------------------------------------------------------------
1 | from .global_level import global_level
2 | from .local_level import local_level
3 | from .pseudotime import pseudotime
4 | from .weight_optimization import weight_optimizing_global, weight_optimizing_local
5 | from .utils import lambda_dist, resistance_distance
6 | from .pseudotimespace import pseudotimespace_global, pseudotimespace_local
7 | from .detect_transition_markers import (
8 | detect_transition_markers_clades,
9 | detect_transition_markers_branches,
10 | )
11 | from .compare_transitions import compare_transitions
12 |
13 | from .set_root import set_root
14 | from .shortest_path_spatial_PAGA import shortest_path_spatial_PAGA
15 |
--------------------------------------------------------------------------------
/stlearn/spatials/trajectory/compare_transitions.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 |
4 | def compare_transitions(adata, trajectories):
5 | """\
6 | Compare transition markers between two clades
7 |
8 | Parameters
9 | ----------
10 | adata
11 | Annotated data matrix.
12 | trajectories
13 | List of clades names user want to compare.
14 | Returns
15 | -------
16 | Anndata
17 | """
18 |
19 | pos_1 = list(
20 | adata.uns[trajectories[0]][adata.uns[trajectories[0]]["score"] >= 0]["gene"]
21 | )
22 | pos_2 = list(
23 | adata.uns[trajectories[1]][adata.uns[trajectories[1]]["score"] >= 0]["gene"]
24 | )
25 | compare_pos_1 = np.setdiff1d(pos_1, pos_2, assume_unique=True)
26 | compare_pos_2 = np.setdiff1d(pos_2, pos_1, assume_unique=True)
27 |
28 | neg_1 = list(
29 | adata.uns[trajectories[0]][adata.uns[trajectories[0]]["score"] < 0]["gene"]
30 | )
31 | neg_2 = list(
32 | adata.uns[trajectories[1]][adata.uns[trajectories[1]]["score"] < 0]["gene"]
33 | )
34 | compare_neg_1 = np.setdiff1d(neg_1, neg_2, assume_unique=True)
35 | compare_neg_2 = np.setdiff1d(neg_2, neg_1, assume_unique=True)
36 |
37 | compare_result = {}
38 | compare_result["pos_1"] = compare_pos_1
39 | compare_result["pos_2"] = compare_pos_2
40 | compare_result["neg_1"] = compare_neg_1
41 | compare_result["neg_2"] = compare_neg_2
42 |
43 | compare_result["trajectories"] = trajectories
44 |
45 | adata.uns["compare_result"] = compare_result
46 | print(
47 | "The result of comparison between "
48 | + trajectories[0]
49 | + " and "
50 | + trajectories[1]
51 | + " stored in 'adata.uns['compare_result']'"
52 | )
53 |
--------------------------------------------------------------------------------
/stlearn/spatials/trajectory/local_level.py:
--------------------------------------------------------------------------------
1 | from anndata import AnnData
2 | from typing import Optional, Union
3 | import numpy as np
4 | from stlearn.em import run_pca, run_diffmap
5 | from stlearn.pp import neighbors
6 | from scipy.spatial.distance import cdist
7 |
8 |
9 | def local_level(
10 | adata: AnnData,
11 | use_label: str = "louvain",
12 | cluster: int = 9,
13 | w: float = 0.5,
14 | return_matrix: bool = False,
15 | verbose: bool = True,
16 | copy: bool = False,
17 | ) -> Optional[AnnData]:
18 |
19 | """\
20 | Perform local sptial trajectory inference (required run pseudotime first).
21 |
22 | Parameters
23 | ----------
24 | adata
25 | Annotated data matrix.
26 | use_label
27 | Use label result of cluster method.
28 | cluster
29 | Choose cluster to perform local spatial trajectory inference.
30 | threshold
31 | Threshold to find the significant connection for PAGA graph.
32 | w
33 | Pseudo-spatio-temporal distance weight (balance between spatial effect and DPT)
34 | return_matrix
35 | Return PTS matrix for local level
36 | copy
37 | Return a copy instead of writing to adata.
38 | Returns
39 | -------
40 | Anndata
41 | """
42 | if verbose:
43 | print("Start construct trajectory for subcluster " + str(cluster))
44 |
45 | tmp = adata.obs[adata.obs[use_label] == str(cluster)]
46 | cluster_data = adata[list(tmp.index)]
47 |
48 | list_cluster = cluster_data.obs["sub_cluster_labels"].unique()
49 | dpt = []
50 | sd = []
51 | centroid_dict = cluster_data.uns["centroid_dict"]
52 | centroid_dict = {int(key): centroid_dict[key] for key in centroid_dict}
53 | for i in list_cluster:
54 | if (
55 | len(adata.obs[adata.obs["sub_cluster_labels"] == str(i)])
56 | > adata.uns["threshold_spots"]
57 | ):
58 | dpt.append(
59 | cluster_data.obs[cluster_data.obs["sub_cluster_labels"] == i][
60 | "dpt_pseudotime"
61 | ].max()
62 | )
63 | sd.append(centroid_dict[int(i)])
64 | dm = cdist(
65 | np.array(dpt).reshape(-1, 1),
66 | np.array(dpt).reshape(-1, 1),
67 | lambda u, v: np.abs(u - v),
68 | )
69 |
70 | non_abs_dm = cdist(
71 | np.array(dpt).reshape(-1, 1), np.array(dpt).reshape(-1, 1), lambda u, v: u - v
72 | )
73 | adata.uns["nonabs_dpt_distance_matrix"] = non_abs_dm
74 |
75 | scale_dm = dm / np.max(dm)
76 | sdm = cdist(np.array(sd), np.array(sd), "euclidean")
77 | scale_sdm = sdm / np.max(sdm)
78 |
79 | stdm = scale_dm * w + scale_sdm * (1 - w)
80 | adata.uns["ST_distance_matrix"] = stdm
81 |
82 | if return_matrix:
83 | return stdm
84 |
85 | return adata if copy else None
86 |
--------------------------------------------------------------------------------
/stlearn/spatials/trajectory/pseudotimespace.py:
--------------------------------------------------------------------------------
1 | from anndata import AnnData
2 | from typing import Optional, Union
3 | from .weight_optimization import weight_optimizing_global, weight_optimizing_local
4 | from .global_level import global_level
5 | from .local_level import local_level
6 |
7 |
8 | def pseudotimespace_global(
9 | adata: AnnData,
10 | use_label: str = "louvain",
11 | use_rep: str = "X_pca",
12 | n_dims: int = 40,
13 | list_clusters: list = [],
14 | model: str = "spatial",
15 | step=0.01,
16 | k=10,
17 | ) -> Optional[AnnData]:
18 |
19 | """\
20 | Perform pseudo-time-space analysis with global level.
21 |
22 | Parameters
23 | ----------
24 | adata
25 | Annotated data matrix.
26 | use_label
27 | Use label result of cluster method.
28 | list_clusters
29 | List of cluster used to reconstruct spatial trajectory.
30 | w
31 | Weighting factor to balance between spatial data and gene expression
32 | step
33 | Step for screeing weighting factor
34 | k
35 | The number of eigenvalues to be compared
36 | Returns
37 | -------
38 | Anndata
39 | """
40 |
41 | if model == "mixed":
42 |
43 | w = weight_optimizing_global(
44 | adata, use_label=use_label, list_clusters=list_clusters, step=step, k=k
45 | )
46 | elif model == "spatial":
47 | w = 0
48 | elif model == "gene_expression":
49 | w = 1
50 | else:
51 | raise ValidationError(
52 | "Please choose the right model! Available models: 'mixed', 'spatial' and 'gene_expression' "
53 | )
54 |
55 | global_level(
56 | adata,
57 | use_label=use_label,
58 | list_clusters=list_clusters,
59 | w=w,
60 | use_rep=use_rep,
61 | n_dims=n_dims,
62 | )
63 |
64 |
65 | def pseudotimespace_local(
66 | adata: AnnData,
67 | use_label: str = "louvain",
68 | cluster: list = [],
69 | w: float = None,
70 | ) -> Optional[AnnData]:
71 |
72 | """\
73 | Perform pseudo-time-space analysis with local level.
74 |
75 | Parameters
76 | ----------
77 | adata
78 | Annotated data matrix.
79 | use_label
80 | Use label result of cluster method.
81 | cluster
82 | Cluster used to reconstruct intraregional spatial trajectory.
83 | w
84 | Weighting factor to balance between spatial data and gene expression
85 | Returns
86 | -------
87 | Anndata
88 | """
89 |
90 | if w is None:
91 | w = weight_optimizing_local(adata, use_label=use_label, cluster=cluster)
92 |
93 | local_level(adata, use_label=use_label, cluster=cluster, w=w)
94 |
--------------------------------------------------------------------------------
/stlearn/spatials/trajectory/set_root.py:
--------------------------------------------------------------------------------
1 | from anndata import AnnData
2 | from typing import Optional, Union
3 | import numpy as np
4 | from stlearn.spatials.trajectory.utils import _correlation_test_helper
5 |
6 |
7 | def set_root(adata: AnnData, use_label: str, cluster: str, use_raw: bool = False):
8 |
9 | """\
10 | Automatically set the root index.
11 |
12 | Parameters
13 | ----------
14 | adata
15 | Annotated data matrix.
16 | use_label
17 | Use label result of cluster method.
18 | cluster
19 | Choose cluster to use as root
20 | use_raw
21 | Use the raw layer
22 | Returns
23 | -------
24 | Root index
25 | """
26 |
27 | tmp_adata = adata.copy()
28 |
29 | # Subset the data based on the chosen cluster
30 |
31 | tmp_adata = tmp_adata[
32 | tmp_adata.obs[tmp_adata.obs[use_label] == str(cluster)].index, :
33 | ]
34 | if use_raw == True:
35 | tmp_adata = tmp_adata.raw.to_adata()
36 |
37 | # Borrow from Cellrank to calculate CytoTrace score
38 | num_exp_genes = np.array((tmp_adata.X > 0).sum(axis=1)).reshape(-1)
39 | gene_corr, _, _, _ = _correlation_test_helper(tmp_adata.X.T, num_exp_genes[:, None])
40 | tmp_adata.var["gene_corr"] = gene_corr
41 |
42 | # Use top 1000 genes rather than top 200 genes
43 | top_1000 = tmp_adata.var.sort_values(by="gene_corr", ascending=False).index[:1000]
44 | tmp_adata.var["correlates"] = False
45 | tmp_adata.var.loc[top_1000, "correlates"] = True
46 | corr_mask = tmp_adata.var["correlates"]
47 | imputed_exp = tmp_adata[:, corr_mask].X
48 |
49 | # Scale ct score
50 | cytotrace_score = np.mean(imputed_exp, axis=1)
51 | cytotrace_score -= np.min(cytotrace_score)
52 | cytotrace_score /= np.max(cytotrace_score)
53 |
54 | # Get the root index
55 | local_index = np.argmax(cytotrace_score)
56 | obs_name = tmp_adata.obs.iloc[local_index].name
57 |
58 | return np.where(adata.obs_names == obs_name)[0][0]
59 |
--------------------------------------------------------------------------------
/stlearn/spatials/trajectory/shortest_path_spatial_PAGA.py:
--------------------------------------------------------------------------------
1 | import networkx as nx
2 | import numpy as np
3 | from stlearn.utils import _read_graph
4 |
5 |
6 | def shortest_path_spatial_PAGA(
7 | adata,
8 | use_label,
9 | key="dpt_pseudotime",
10 | ):
11 | # Read original PAGA graph
12 | G = nx.from_numpy_array(adata.uns["paga"]["connectivities"].toarray())
13 | edge_weights = nx.get_edge_attributes(G, "weight")
14 | G.remove_edges_from((e for e, w in edge_weights.items() if w < 0))
15 | H = G.to_directed()
16 |
17 | # Get min_node and max_node
18 | min_node, max_node = find_min_max_node(adata, key, use_label)
19 |
20 | # Calculate pseudotime for each node
21 | node_pseudotime = {}
22 |
23 | for node in H.nodes:
24 | node_pseudotime[node] = adata.obs.query(use_label + " == '" + str(node) + "'")[
25 | key
26 | ].max()
27 |
28 | # Force original PAGA to directed PAGA based on pseudotime
29 | edge_to_remove = []
30 | for edge in H.edges:
31 | if node_pseudotime[edge[0]] - node_pseudotime[edge[1]] > 0:
32 | edge_to_remove.append(edge)
33 | H.remove_edges_from(edge_to_remove)
34 |
35 | # Extract all available paths
36 | all_paths = {}
37 | j = 0
38 | for source in H.nodes:
39 | for target in H.nodes:
40 | paths = nx.all_simple_paths(H, source=source, target=target)
41 | for i, path in enumerate(paths):
42 | j += 1
43 | all_paths[j] = path
44 |
45 | # Filter the target paths from min_node to max_node
46 | target_paths = []
47 | for path in list(all_paths.values()):
48 | if path[0] == min_node and path[-1] == max_node:
49 | target_paths.append(path)
50 |
51 | # Get the global graph
52 | G = _read_graph(adata, "global_graph")
53 |
54 | centroid_dict = adata.uns["centroid_dict"]
55 | centroid_dict = {int(key): centroid_dict[key] for key in centroid_dict}
56 |
57 | # Generate total length of every path. Store by dictionary
58 | dist_dict = {}
59 | for path in target_paths:
60 | path_name = ",".join(list(map(str, path)))
61 | result = []
62 | query_node = get_node(path, adata.uns["split_node"])
63 | for edge in G.edges():
64 | if (edge[0] in query_node) and (edge[1] in query_node):
65 | result.append(edge)
66 | if len(result) >= len(path):
67 | dist_dict[path_name] = calculate_total_dist(result, centroid_dict)
68 |
69 | # Find the shortest path
70 | shortest_path = min(dist_dict, key=lambda x: dist_dict[x])
71 | return shortest_path.split(",")
72 |
73 |
74 | # get name of cluster by subcluster
75 | def get_cluster(search, dictionary):
76 | for cl, sub in dictionary.items():
77 | if search in sub:
78 | return cl
79 |
80 |
81 | def get_node(node_list, split_node):
82 | result = np.array([])
83 | for node in node_list:
84 | result = np.append(result, np.array(split_node[int(node)]).astype(int))
85 | return result.astype(int)
86 |
87 |
88 | def find_min_max_node(adata, key="dpt_pseudotime", use_label="leiden"):
89 | min_cluster = int(adata.obs[adata.obs[key] == 0][use_label].values[0])
90 | max_cluster = int(adata.obs[adata.obs[key] == 1][use_label].values[0])
91 |
92 | return [min_cluster, max_cluster]
93 |
94 |
95 | def calculate_total_dist(result, centroid_dict):
96 | import math
97 |
98 | total_dist = 0
99 | for edge in result:
100 | source = centroid_dict[edge[0]]
101 | target = centroid_dict[edge[1]]
102 | dist = math.dist(source, target)
103 | total_dist += dist
104 | return total_dist
105 |
--------------------------------------------------------------------------------
/stlearn/tl.py:
--------------------------------------------------------------------------------
1 | from .tools import clustering
2 | from .tools.microenv import cci
3 | from .tools.label import label
4 |
--------------------------------------------------------------------------------
/stlearn/tools/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/tools/__init__.py
--------------------------------------------------------------------------------
/stlearn/tools/clustering/__init__.py:
--------------------------------------------------------------------------------
1 | from .kmeans import kmeans
2 | from .louvain import louvain
3 | from .annotate import annotate_interactive
4 |
--------------------------------------------------------------------------------
/stlearn/tools/clustering/annotate.py:
--------------------------------------------------------------------------------
1 | from anndata import AnnData
2 | from stlearn.plotting.classes_bokeh import Annotate
3 | from bokeh.io import output_notebook
4 | from bokeh.plotting import show
5 |
6 |
7 | def annotate_interactive(
8 | adata: AnnData,
9 | ):
10 | """\
11 | Allow user to manually define the clusters
12 |
13 | Parameters
14 | -------------------------------------
15 | adata
16 | Annotated data matrix.
17 | """
18 |
19 | bokeh_object = Annotate(adata)
20 | output_notebook()
21 | show(bokeh_object.app, notebook_handle=True)
22 |
--------------------------------------------------------------------------------
/stlearn/tools/clustering/kmeans.py:
--------------------------------------------------------------------------------
1 | from sklearn.cluster import KMeans
2 | from anndata import AnnData
3 | from typing import Optional, Union
4 | import pandas as pd
5 | import numpy as np
6 | from natsort import natsorted
7 |
8 |
9 | def kmeans(
10 | adata: AnnData,
11 | n_clusters: int = 20,
12 | use_data: str = "X_pca",
13 | init: str = "k-means++",
14 | n_init: int = 10,
15 | max_iter: int = 300,
16 | tol: float = 0.0001,
17 | random_state: str = None,
18 | copy_x: bool = True,
19 | algorithm: str = "auto",
20 | key_added: str = "kmeans",
21 | copy: bool = False,
22 | ) -> Optional[AnnData]:
23 |
24 | """\
25 | Perform kmeans cluster for spatial transcriptomics data
26 |
27 | Parameters
28 | ----------
29 | adata
30 | Annotated data matrix.
31 | n_clusters
32 | The number of clusters to form as well as the number of
33 | centroids to generate.
34 | use_data
35 | Use dimensionality reduction result.
36 | init
37 | Method for initialization, defaults to 'k-means++'
38 | max_iter
39 | Maximum number of iterations of the k-means algorithm for a
40 | single run.
41 | tol
42 | Relative tolerance with regards to inertia to declare convergence.
43 | random_state
44 | Determines random number generation for centroid initialization. Use
45 | an int to make the randomness deterministic.
46 | copy_x
47 | When pre-computing distances it is more numerically accurate to center
48 | the data first. If copy_x is True (default), then the original data is
49 | not modified, ensuring X is C-contiguous. If False, the original data
50 | is modified, and put back before the function returns, but small
51 | numerical differences may be introduced by subtracting and then adding
52 | the data mean, in this case it will also not ensure that data is
53 | C-contiguous which may cause a significant slowdown.
54 | algorithm
55 | K-means algorithm to use. The classical EM-style algorithm is "full".
56 | The "elkan" variation is more efficient by using the triangle
57 | inequality, but currently doesn't support sparse data. "auto" chooses
58 | "elkan" for dense data and "full" for sparse data.
59 | key_added
60 | Key add to adata.obs
61 | copy
62 | Return a copy instead of writing to adata.
63 | Returns
64 | -------
65 | Anndata
66 | """
67 |
68 | data = adata.obsm[use_data]
69 |
70 | print("Applying Kmeans cluster ...")
71 |
72 | kmeans = KMeans(
73 | n_clusters=n_clusters,
74 | init=init,
75 | n_init=n_init,
76 | max_iter=max_iter,
77 | tol=tol,
78 | random_state=random_state,
79 | copy_x=copy_x,
80 | algorithm=algorithm,
81 | ).fit(data)
82 |
83 | adata.obs[key_added] = pd.Categorical(
84 | values=np.array(kmeans.labels_).astype("U"),
85 | categories=natsorted(np.unique(np.array(kmeans.labels_)).astype("U")),
86 | )
87 |
88 | print('Kmeans cluster is done! The labels are stored in adata.obs["kmeans"]')
89 |
90 | return adata if copy else None
91 |
--------------------------------------------------------------------------------
/stlearn/tools/clustering/louvain.py:
--------------------------------------------------------------------------------
1 | from types import MappingProxyType
2 | from typing import Optional, Tuple, Sequence, Type, Mapping, Any, Union
3 |
4 | import numpy as np
5 | import pandas as pd
6 | from anndata import AnnData
7 | from natsort import natsorted
8 | from numpy.random.mtrand import RandomState
9 | from scipy.sparse import spmatrix
10 | from stlearn._compat import Literal
11 |
12 | try:
13 | from louvain.VertexPartition import MutableVertexPartition
14 | except ImportError:
15 |
16 | class MutableVertexPartition:
17 | pass
18 |
19 | MutableVertexPartition.__module__ = "louvain.VertexPartition"
20 | import scanpy
21 |
22 |
23 | def louvain(
24 | adata: AnnData,
25 | resolution: Optional[float] = None,
26 | random_state: Optional[Union[int, RandomState]] = 0,
27 | restrict_to: Optional[Tuple[str, Sequence[str]]] = None,
28 | key_added: str = "louvain",
29 | adjacency: Optional[spmatrix] = None,
30 | flavor: Literal["vtraag", "igraph", "rapids"] = "vtraag",
31 | directed: bool = True,
32 | use_weights: bool = False,
33 | partition_type: Optional[Type[MutableVertexPartition]] = None,
34 | partition_kwargs: Mapping[str, Any] = MappingProxyType({}),
35 | copy: bool = False,
36 | ) -> Optional[AnnData]:
37 | """\
38 | Wrap function scanpy.tl.louvain
39 | Cluster cells into subgroups [Blondel08]_ [Levine15]_ [Traag17]_.
40 | Cluster cells using the Louvain algorithm [Blondel08]_ in the implementation
41 | of [Traag17]_. The Louvain algorithm has been proposed for single-cell
42 | analysis by [Levine15]_.
43 | This requires having ran :func:`~scanpy.pp.neighbors` or
44 | :func:`~scanpy.external.pp.bbknn` first,
45 | or explicitly passing a ``adjacency`` matrix.
46 | Parameters
47 | ----------
48 | adata
49 | The annotated data matrix.
50 | resolution
51 | For the default flavor (``'vtraag'``), you can provide a resolution
52 | (higher resolution means finding more and smaller clusters),
53 | which defaults to 1.0.
54 | See “Time as a resolution parameter” in [Lambiotte09]_.
55 | random_state
56 | Change the initialization of the optimization.
57 | restrict_to
58 | Restrict the cluster to the categories within the key for sample
59 | annotation, tuple needs to contain ``(obs_key, list_of_categories)``.
60 | key_added
61 | Key under which to add the cluster labels. (default: ``'louvain'``)
62 | adjacency
63 | Sparse adjacency matrix of the graph, defaults to
64 | ``adata.uns['neighbors']['connectivities']``.
65 | flavor
66 | Choose between to packages for computing the cluster.
67 | ``'vtraag'`` is much more powerful, and the default.
68 | directed
69 | Interpret the ``adjacency`` matrix as directed graph?
70 | use_weights
71 | Use weights from knn graph.
72 | partition_type
73 | Type of partition to use.
74 | Only a valid argument if ``flavor`` is ``'vtraag'``.
75 | partition_kwargs
76 | Key word arguments to pass to partitioning,
77 | if ``vtraag`` method is being used.
78 | copy
79 | Copy adata or modify it inplace.
80 | Returns
81 | -------
82 | :obj:`None`
83 | By default (``copy=False``), updates ``adata`` with the following fields:
84 | ``adata.obs['louvain']`` (:class:`pandas.Series`, dtype ``category``)
85 | Array of dim (number of samples) that stores the subgroup id
86 | (``'0'``, ``'1'``, ...) for each cell.
87 | :class:`~anndata.AnnData`
88 | When ``copy=True`` is set, a copy of ``adata`` with those fields is returned.
89 | """
90 |
91 | scanpy.tl.louvain(
92 | adata,
93 | resolution=resolution,
94 | random_state=random_state,
95 | restrict_to=restrict_to,
96 | key_added=key_added,
97 | adjacency=adjacency,
98 | flavor=flavor,
99 | directed=directed,
100 | use_weights=use_weights,
101 | partition_type=partition_type,
102 | partition_kwargs=partition_kwargs,
103 | copy=copy,
104 | )
105 |
106 | print("Applying Louvain cluster ...")
107 | print(
108 | "Louvain cluster is done! The labels are stored in adata.obs['%s']" % key_added
109 | )
110 |
--------------------------------------------------------------------------------
/stlearn/tools/label/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/tools/label/__init__.py
--------------------------------------------------------------------------------
/stlearn/tools/label/label_transfer.R:
--------------------------------------------------------------------------------
1 | # Seurat label transfer wrapper script.
2 | # Following from here: https://satijalab.org/seurat/articles/spatial_vignette.html
3 | # See the section 'Integration with single cell data'
4 |
5 | library(Seurat)
6 | library(dplyr)
7 |
8 | label_transfer <- function(st_expr_df, sc_expr_df, sc_labels) {
9 | ###### Performs Seurat label transfer from the sc data to the st data. #######
10 |
11 | # Creating the Seurat objects #
12 | print("Creating Seurat Objects.")
13 | st <- CreateSeuratObject(st_expr_df)
14 | VariableFeatures(st) <- rownames(st@assays$RNA@data)
15 | sc <- CreateSeuratObject(sc_expr_df)
16 | sc <- AddMetaData(sc, sc_labels, col.name='cell_type')
17 | VariableFeatures(sc) <- rownames(sc@assays$RNA@data)
18 | print("Finished creating Seurat.")
19 |
20 | # Finding variable features #
21 | #st <- FindVariableFeatures(st, selection.method="vst",
22 | # nfeatures=n_highly_variable, verbose=T)
23 | #print("Finished finding variable features for ST data.")
24 | #sc <- FindVariableFeatures(sc, selection.method="vst",
25 | # nfeatures=n_highly_variable, verbose=T)
26 | #print("Finished finding variable features for SC data.")
27 |
28 | # Dim reduction #
29 | st <- ScaleData(st, verbose=T)
30 | print("Finished scaling data for ST data.")
31 | st <- RunPCA(st, verbose = T, #features=rownames(st@assays$RNA@data)
32 | )
33 | print("Finished PCA for st data.")
34 | st <- RunUMAP(st, dims = 1:30, method='uwot-learn')
35 | print("Finished UMAP for st data.")
36 |
37 | sc <- ScaleData(sc) %>% RunPCA(verbose = T,
38 | #features=rownames(sc@assays$RNA@data)
39 | ) %>% RunUMAP(dims = 1:30,
40 | method='uwot-learn')
41 | print("Finished scaling data for SC data.")
42 |
43 | # Performing the label transfer #
44 | anchors <- FindTransferAnchors(reference = sc, query = st,
45 | #features=rownames(sc@assays$RNA@data),
46 | reference.reduction = 'pca', dims=1:30,
47 | normalization.method = "LogNormalize")
48 | print("Finished finding anchors.")
49 | predictions.assay <- TransferData(anchorset = anchors,
50 | refdata = sc$cell_type, prediction.assay=T,
51 | k.weight=20,
52 | weight.reduction = st[["pca"]], dims = 1:30)
53 | print("Finished label transferring.")
54 | transfer_scores <- predictions.assay@data
55 |
56 | return( as.data.frame( transfer_scores ) )
57 | }
58 |
--------------------------------------------------------------------------------
/stlearn/tools/label/rctd.R:
--------------------------------------------------------------------------------
1 | # RCTD deconvolution wrapper script
2 |
3 | library(RCTD)
4 | library(data.table)
5 |
6 | rctd <- function(st_counts, st_coords, sc_counts, sc_labels,
7 | doublet_mode, min_cells, n_cores) {
8 | ###### Performs RCTD deconvolution of the st data from sc data #######
9 |
10 | # Making sure correct namings #
11 | colnames(st_counts) <- rownames(st_coords)
12 |
13 | # Subsetting to cell types with > X cells #
14 | label_set <- unique( sc_labels )
15 | label_counts <- as.integer( lapply(label_set,
16 | function(label) {
17 | length(which(sc_labels==label))
18 | }))
19 | new_label_set <- label_set[ label_counts > min_cells ]
20 | labels_bool <- as.logical( lapply(sc_labels,
21 | function(label) {
22 | label %in% new_label_set
23 | }))
24 | sc_counts <- sc_counts[,labels_bool]
25 | sc_labels <- as.factor( sc_labels[labels_bool] )
26 | names(sc_labels) <- colnames( sc_counts )
27 |
28 | ##############################################################################
29 | # Creating RCTD objects #
30 | ##############################################################################
31 | ## Single cell reference ##
32 | reference <- Reference(sc_counts, cell_types = sc_labels)
33 |
34 | ## Spots for deconvolution ##
35 | query <- SpatialRNA(st_coords, st_counts)
36 |
37 | ## Creating the RCTD object ##
38 | myRCTD <- RCTD::create.RCTD(query, reference,
39 | max_cores = n_cores, CELL_MIN_INSTANCE=min_cells)
40 |
41 | ##############################################################################
42 | # Running RCTD #
43 | ##############################################################################
44 | myRCTD <- run.RCTD(myRCTD, doublet_mode = doublet_mode)
45 |
46 | ### Getting & normalising the results ###
47 | results <- myRCTD@results$weights
48 | norm_weights <- sweep(results, 1, rowSums(as.matrix(results)), '/')
49 | norm_weights <- as.data.frame(as.matrix(norm_weights))
50 |
51 | return( norm_weights )
52 | }
53 |
--------------------------------------------------------------------------------
/stlearn/tools/label/singleR.R:
--------------------------------------------------------------------------------
1 | # SingleR spot annotation wrapper script.
2 |
3 | library(SingleR)
4 |
5 | singleR <- function(st_expr_df, sc_expr_df, sc_labels,
6 | n_centers, de_n, de_method) {
7 | ##### Runs SingleR spot annotation #######
8 | st_expr <- as.matrix( st_expr_df )
9 | sc_expr <- as.matrix( sc_expr_df )
10 |
11 | ##### Subsetting to genes in common between datasets #####
12 | common_genes <- intersect(rownames(sc_expr), rownames(st_expr))
13 |
14 | sc_expr <- sc_expr[common_genes,]
15 | st_expr <- st_expr[common_genes,]
16 |
17 | ###### Performs Seurat label transfer from the sc data to the st data. #######
18 | sc_aggr <- aggregateReference(sc_expr, sc_labels, ncenters=n_centers)
19 | trained <- trainSingleR(sc_aggr, sc_aggr$label, de.n=de_n, de.method=de_method)
20 |
21 | out <- classifySingleR(st_expr, trained, fine.tune=F, prune=F)
22 | scores_df <- as.data.frame( out$scores )
23 | scores_df[,'labels'] <- out$labels
24 | rownames(scores_df) <- out@rownames
25 |
26 | return( scores_df )
27 | }
28 |
--------------------------------------------------------------------------------
/stlearn/tools/microenv/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/tools/microenv/__init__.py
--------------------------------------------------------------------------------
/stlearn/tools/microenv/cci/__init__.py:
--------------------------------------------------------------------------------
1 | # from .base import lr
2 | # from .base_grouping import get_hotspots
3 | # from . import het
4 | # from .het import edge_core, get_between_spot_edge_array
5 | # from .merge import merge
6 | # from .permutation import get_rand_pairs
7 | from .analysis import load_lrs, grid, run, adj_pvals, run_lr_go, run_cci
8 |
--------------------------------------------------------------------------------
/stlearn/tools/microenv/cci/databases/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/tools/microenv/cci/databases/__init__.py
--------------------------------------------------------------------------------
/stlearn/tools/microenv/cci/go.R:
--------------------------------------------------------------------------------
1 | # R script that runs the LR GO analysis #
2 |
3 | library(clusterProfiler)
4 | library(org.Mm.eg.db)
5 | library(org.Hs.eg.db)
6 | #library(enrichplot)
7 | #library(ggplot2)
8 |
9 | GO_analyse <- function(genes, bg_genes, species,
10 | p_cutoff, q_cutoff, onts) {
11 | #p_cutoff=.01, q_cutoff=0.5, onts='BP') {
12 | # Main function for performing the GO analysis #
13 |
14 | # Selecting correct species database #
15 | if (species == 'human') {db <- org.Hs.eg.db
16 | } else {db <- org.Mm.eg.db}
17 |
18 | # Performing the enrichment #
19 | em <- enrichGO(genes, db, ont=onts, keyType='SYMBOL',
20 | pvalueCutoff=p_cutoff, qvalueCutoff=q_cutoff, universe=bg_genes)
21 |
22 | result <- em@result
23 | sig_results <- result[,'p.adjust'] AnnData:
12 | """Merge results from cell type heterogeneity and L-R cluster
13 | Parameters
14 | ----------
15 | adata: AnnData The data object including the cell types to count
16 | use_lr: str CCI LR scores
17 | use_het: str CCI HET scores
18 |
19 | Returns
20 | -------
21 | adata: AnnData With merged result stored in adata.uns['merged']
22 | """
23 |
24 | adata.obsm["merged"] = np.multiply(adata.obsm[use_het], adata.obsm[use_lr])
25 |
26 | if verbose:
27 | print(
28 | "Results of spatial interaction analysis has been written to adata.uns['merged']"
29 | )
30 |
31 | return adata
32 |
--------------------------------------------------------------------------------
/stlearn/tools/microenv/cci/r_helpers.py:
--------------------------------------------------------------------------------
1 | """
2 | Helper functions for porting R code into python/stLearn.
3 | """
4 |
5 | import os
6 |
7 | ro = None
8 | pandas2ri = None
9 | localconverter = None
10 |
11 |
12 | def rpy2_setup(r_path):
13 | """Sets up rpy2."""
14 | os.environ["R_HOME"] = r_path
15 |
16 | import rpy2.robjects as robjects_
17 | from rpy2.robjects import pandas2ri as pandas2ri_
18 | from rpy2.robjects.conversion import localconverter as localconverter_
19 |
20 | global ro, pandas2ri, localconverter
21 | ro = robjects_
22 | pandas2ri = pandas2ri_
23 | localconverter = localconverter_
24 |
--------------------------------------------------------------------------------
/stlearn/utils.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 | import io
4 | from PIL import Image
5 | import matplotlib
6 | from anndata import AnnData
7 | import networkx as nx
8 |
9 | from typing import Optional, Union, Mapping # Special
10 | from typing import Sequence, Iterable # ABCs
11 | from typing import Tuple # Classes
12 |
13 | from textwrap import dedent
14 |
15 | from enum import Enum
16 |
17 |
18 | class Empty(Enum):
19 | token = 0
20 |
21 |
22 | _empty = Empty.token
23 |
24 | from matplotlib import rcParams, ticker, gridspec, axes
25 | from matplotlib.axes import Axes
26 | from abc import ABC
27 |
28 |
29 | class _AxesSubplot(Axes, axes.SubplotBase):
30 | """Intersection between Axes and SubplotBase: Has methods of both"""
31 |
32 |
33 | def _check_spot_size(
34 | spatial_data: Optional[Mapping], spot_size: Optional[float]
35 | ) -> float:
36 | """
37 | Resolve spot_size value.
38 | This is a required argument for spatial plots.
39 | """
40 | if spatial_data is None and spot_size is None:
41 | raise ValueError(
42 | "When .uns['spatial'][library_id] does not exist, spot_size must be "
43 | "provided directly."
44 | )
45 | elif spot_size is None:
46 | return spatial_data["scalefactors"]["spot_diameter_fullres"]
47 | else:
48 | return spot_size
49 |
50 |
51 | def _check_scale_factor(
52 | spatial_data: Optional[Mapping],
53 | img_key: Optional[str],
54 | scale_factor: Optional[float],
55 | ) -> float:
56 | """Resolve scale_factor, defaults to 1."""
57 | if scale_factor is not None:
58 | return scale_factor
59 | elif spatial_data is not None and img_key is not None:
60 | return spatial_data["scalefactors"][f"tissue_{img_key}_scalef"]
61 | else:
62 | return 1.0
63 |
64 |
65 | def _check_spatial_data(
66 | uns: Mapping, library_id: Union[Empty, None, str]
67 | ) -> Tuple[Optional[str], Optional[Mapping]]:
68 | """
69 | Given a mapping, try and extract a library id/ mapping with spatial data.
70 | Assumes this is `.uns` from how we parse visium data.
71 | """
72 | spatial_mapping = uns.get("spatial", {})
73 | if library_id is _empty:
74 | if len(spatial_mapping) > 1:
75 | raise ValueError(
76 | "Found multiple possible libraries in `.uns['spatial']. Please specify."
77 | f" Options are:\n\t{list(spatial_mapping.keys())}"
78 | )
79 | elif len(spatial_mapping) == 1:
80 | library_id = list(spatial_mapping.keys())[0]
81 | else:
82 | library_id = None
83 | if library_id is not None:
84 | spatial_data = spatial_mapping[library_id]
85 | else:
86 | spatial_data = None
87 | return library_id, spatial_data
88 |
89 |
90 | def _check_img(
91 | spatial_data: Optional[Mapping],
92 | img: Optional[np.ndarray],
93 | img_key: Union[None, str, Empty],
94 | bw: bool = False,
95 | ) -> Tuple[Optional[np.ndarray], Optional[str]]:
96 | """
97 | Resolve image for spatial plots.
98 | """
99 | if img is None and spatial_data is not None and img_key is _empty:
100 | img_key = next(
101 | (k for k in ["hires", "lowres", "fulres"] if k in spatial_data["images"]),
102 | ) # Throws StopIteration Error if keys not present
103 | if img is None and spatial_data is not None and img_key is not None:
104 | img = spatial_data["images"][img_key]
105 | if bw:
106 | img = np.dot(img[..., :3], [0.2989, 0.5870, 0.1140])
107 | return img, img_key
108 |
109 |
110 | def _check_coords(
111 | obsm: Optional[Mapping], scale_factor: Optional[float]
112 | ) -> Tuple[Optional[np.ndarray], Optional[np.ndarray]]:
113 |
114 | image_coor = obsm["spatial"] * scale_factor
115 | imagecol = image_coor[:, 0]
116 | imagerow = image_coor[:, 1]
117 |
118 | return [imagecol, imagerow]
119 |
120 |
121 | def _read_graph(adata: AnnData, graph_type: Optional[str]):
122 |
123 | if graph_type == "PTS_graph":
124 | graph = nx.from_scipy_sparse_array(
125 | adata.uns[graph_type]["graph"], create_using=nx.DiGraph
126 | )
127 | else:
128 | graph = nx.from_scipy_sparse_array(adata.uns[graph_type]["graph"])
129 | node_dict = adata.uns[graph_type]["node_dict"]
130 | node_dict = {int(k): int(v) for k, v in node_dict.items()}
131 |
132 | relabel_graph = nx.relabel_nodes(graph, node_dict)
133 |
134 | return relabel_graph
135 |
136 |
137 | def _docs_params(**kwds):
138 | """\
139 | Docstrings should start with "\" in the first line for proper formatting.
140 | """
141 |
142 | def dec(obj):
143 | obj.__orig_doc__ = obj.__doc__
144 | obj.__doc__ = dedent(obj.__doc__).format_map(kwds)
145 | return obj
146 |
147 | return dec
148 |
--------------------------------------------------------------------------------
/stlearn/wrapper/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/stlearn/wrapper/__init__.py
--------------------------------------------------------------------------------
/stlearn/wrapper/concatenate_spatial_adata.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from skimage.transform import resize
3 |
4 |
5 | def transform_spatial(coordinates, original, resized):
6 | # obs transform
7 | x = coordinates[:, 0]
8 | y = coordinates[:, 1]
9 | x1p = x / original[1]
10 | y1p = y / original[0]
11 | x1 = x1p * resized[1]
12 | y1 = y1p * resized[0]
13 |
14 | return np.vstack([x1, y1]).transpose()
15 |
16 |
17 | def correct_size(adata, fixed_size):
18 |
19 | image = adata.uns["spatial"][list(adata.uns["spatial"].keys())[0]]["images"][
20 | "hires"
21 | ]
22 | image_size = image.shape[:2]
23 | if image_size != fixed_size:
24 | adata.obs[["imagerow", "imagecol"]] = transform_spatial(
25 | adata.obs[["imagerow", "imagecol"]].values, image_size, fixed_size
26 | )
27 | adata.obsm["spatial"] = transform_spatial(
28 | adata.obsm["spatial"], image_size, fixed_size
29 | )
30 | image_resized = resize(image, fixed_size)
31 | adata.uns["spatial"][list(adata.uns["spatial"].keys())[0]]["images"][
32 | "hires"
33 | ] = image_resized
34 |
35 | return adata
36 |
37 |
38 | def concatenate_spatial_adata(adata_list, ncols=2, fixed_size=(2000, 2000)):
39 | """\
40 | Concatnate multiple anndata for visualization of spatial transcriptomics
41 |
42 | Parameters
43 | ----------
44 | adata_list
45 | A list of anndata objet.
46 | ncols
47 | Number of columns
48 | fixed_size
49 | The size that fixed for every spatial transcriptomics data
50 | Returns
51 | -------
52 | Returns adata.
53 | """
54 |
55 | use_adata_list = []
56 | for adata in adata_list:
57 | use_adata_list.append(adata.copy())
58 |
59 | import math
60 |
61 | # check valid
62 | n_adata = len(use_adata_list)
63 | nrows = math.ceil(n_adata / ncols)
64 | if ncols > n_adata:
65 | raise ValueError("Number of column is out of bound")
66 |
67 | # Correct size
68 | for adata in use_adata_list:
69 | correct_size(adata, fixed_size=fixed_size)
70 |
71 | # Transform
72 | n = 0
73 | break_out_flag = False
74 | scale = use_adata_list[0].uns["spatial"][
75 | list(use_adata_list[0].uns["spatial"].keys())[0]
76 | ]["scalefactors"]["tissue_hires_scalef"]
77 | for i in range(0, nrows):
78 | for j in range(0, ncols):
79 | obs_spatial = use_adata_list[n].obs[["imagerow", "imagecol"]].values
80 | obsm_spatial = use_adata_list[n].obsm["spatial"]
81 | obs_spatial = np.vstack(
82 | (
83 | obs_spatial[:, 0] + fixed_size[0] * i,
84 | obs_spatial[:, 1] + fixed_size[1] * j,
85 | )
86 | ).transpose()
87 | obsm_spatial = np.vstack(
88 | (
89 | obsm_spatial[:, 0] + fixed_size[0] / scale * i,
90 | obsm_spatial[:, 1] + fixed_size[1] / scale * j,
91 | )
92 | ).transpose()
93 | use_adata_list[n].obs[["imagerow", "imagecol"]] = obs_spatial
94 | use_adata_list[n].obsm["spatial"] = obsm_spatial
95 | if n == len(use_adata_list) - 1:
96 | break_out_flag = True
97 | break
98 | n += 1
99 | if break_out_flag:
100 | break
101 |
102 | # Combine images
103 | imgs = []
104 | for i, adata in enumerate(use_adata_list):
105 | imgs.append(
106 | adata.uns["spatial"][list(adata.uns["spatial"].keys())[0]]["images"][
107 | "hires"
108 | ]
109 | )
110 |
111 | from PIL import Image
112 |
113 | if (nrows * ncols - len(use_adata_list)) > 0:
114 | for i in range(0, (nrows * ncols - len(use_adata_list))):
115 | image = Image.new("RGB", fixed_size, (255, 255, 255, 255))
116 | imgs.append(np.array(image))
117 |
118 | print(len(imgs))
119 |
120 | img_rows = []
121 | for min_id in range(0, len(use_adata_list), ncols):
122 | img_row = np.hstack(imgs[min_id : min_id + ncols])
123 | img_rows.append(img_row)
124 | imgs_comb = np.vstack((i for i in img_rows))
125 |
126 | adata_concat = use_adata_list[0].concatenate(use_adata_list[1:])
127 | adata_concat.uns["spatial"] = use_adata_list[0].uns["spatial"]
128 |
129 | adata_concat.uns["spatial"][list(adata_concat.uns["spatial"].keys())[0]]["images"][
130 | "hires"
131 | ] = imgs_comb
132 |
133 | return adata_concat
134 |
--------------------------------------------------------------------------------
/stlearn/wrapper/convert_scanpy.py:
--------------------------------------------------------------------------------
1 | from typing import Optional, Union
2 | from anndata import AnnData
3 | from matplotlib import pyplot as plt
4 | from pathlib import Path
5 | import os
6 |
7 |
8 | def convert_scanpy(
9 | adata: AnnData,
10 | use_quality: str = "hires",
11 | ) -> Optional[AnnData]:
12 |
13 | adata.var_names_make_unique()
14 |
15 | library_id = list(adata.uns["spatial"].keys())[0]
16 |
17 | if use_quality == "fulres":
18 | image_coor = adata.obsm["spatial"]
19 | else:
20 | scale = adata.uns["spatial"][library_id]["scalefactors"][
21 | "tissue_" + use_quality + "_scalef"
22 | ]
23 | image_coor = adata.obsm["spatial"] * scale
24 |
25 | adata.obs["imagecol"] = image_coor[:, 0]
26 | adata.obs["imagerow"] = image_coor[:, 1]
27 | adata.uns["spatial"][library_id]["use_quality"] = use_quality
28 |
29 | return adata
30 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | """Unit test package for stlearn."""
2 |
--------------------------------------------------------------------------------
/tests/test_PSTS.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Tests for `stlearn` package."""
4 |
5 |
6 | import unittest
7 |
8 | import stlearn as st
9 | import scanpy as sc
10 | from .utils import read_test_data
11 | import numpy as np
12 |
13 | global adata
14 | adata = read_test_data()
15 |
16 |
17 | class TestPSTS(unittest.TestCase):
18 | """Tests for `stlearn` package."""
19 |
20 | def test_PSTS(self):
21 | sc.pp.pca(adata)
22 | print("Done PCA!")
23 | sc.pp.neighbors(adata)
24 | print("Done KNN!")
25 | sc.tl.leiden(adata, resolution=0.6)
26 | print("Done leiden!")
27 | # sc.tl.louvain(adata)
28 |
29 | adata.uns["iroot"] = np.flatnonzero(adata.obs["leiden"] == "0")[0]
30 | st.spatial.trajectory.pseudotime(
31 | adata, eps=100, use_rep="X_pca", use_sme=False, use_label="leiden"
32 | )
33 | st.spatial.trajectory.pseudotimespace_global(
34 | adata, use_label="leiden", list_clusters=[0, 1]
35 | )
36 | st.spatial.trajectory.detect_transition_markers_clades(
37 | adata, clade=0, use_raw_count=False, cutoff_spearman=0.3
38 | )
39 | print("Done PSTS!")
40 |
--------------------------------------------------------------------------------
/tests/test_SME.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """Tests for `stlearn` package."""
4 |
5 |
6 | import unittest
7 |
8 | import stlearn as st
9 | import scanpy as sc
10 | from .utils import read_test_data
11 |
12 | global adata
13 | adata = read_test_data()
14 |
15 |
16 | class TestSME(unittest.TestCase):
17 | """Tests for `stlearn` package."""
18 |
19 | def test_SME(self):
20 | sc.pp.pca(adata)
21 | st.pp.tiling(adata, "./tiling")
22 | st.pp.extract_feature(adata)
23 | import shutil
24 |
25 | shutil.rmtree("./tiling")
26 | data_SME = adata.copy()
27 | # apply stSME to normalise log transformed data
28 | st.spatial.SME.SME_normalize(data_SME, use_data="raw")
29 |
--------------------------------------------------------------------------------
/tests/test_data/test_data.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/tests/test_data/test_data.h5
--------------------------------------------------------------------------------
/tests/test_data/test_image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiomedicalMachineLearning/stLearn/439692ba35b0ecb3df952f72cc5af05b96b7f600/tests/test_data/test_image.jpg
--------------------------------------------------------------------------------
/tests/test_install.py:
--------------------------------------------------------------------------------
1 | """
2 | Tests that everything is installed correctly.
3 | """
4 |
5 | import unittest
6 |
7 |
8 | class TestCCI(unittest.TestCase):
9 | """Tests for `stlearn` importability, i.e. correct installation."""
10 |
11 | def test_SME(self):
12 | import stlearn.spatials.SME.normalize as sme_normalise
13 |
14 | def test_cci(self):
15 | """Tests CCI can be imported."""
16 | import stlearn.tools.microenv.cci.analysis as an
17 |
--------------------------------------------------------------------------------
/tests/utils.py:
--------------------------------------------------------------------------------
1 | import os
2 | import scanpy as sc
3 | from PIL import Image
4 | import numpy as np
5 |
6 |
7 | def read_test_data():
8 | """Reads in test data to run unit tests."""
9 | # Determining path of this file #
10 | path = os.path.dirname(os.path.realpath(__file__))
11 | adata = sc.read_h5ad(f"{path}/test_data/test_data.h5")
12 | im = Image.open(f"{path}/test_data/test_image.jpg")
13 | adata.uns["spatial"]["V1_Breast_Cancer_Block_A_Section_1"]["images"][
14 | "hires"
15 | ] = np.array(im)
16 | return adata
17 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = py35, py36, py37, py38, flake8
3 |
4 | [travis]
5 | python =
6 | 3.8: py38
7 | 3.7: py37
8 | 3.6: py36
9 | 3.5: py35
10 |
11 | [testenv:flake8]
12 | basepython = python
13 | deps = flake8
14 | commands = flake8 stlearn
15 |
16 | [testenv]
17 | setenv =
18 | PYTHONPATH = {toxinidir}
19 |
20 | commands = python setup.py test
21 |
--------------------------------------------------------------------------------