pertpy 1.0.0__tar.gz → 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/release-drafter.yml +2 -2
- pertpy-1.0.1/.github/workflows/test_tutorials.yml +94 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.pre-commit-config.yaml +4 -4
- {pertpy-1.0.0 → pertpy-1.0.1}/PKG-INFO +3 -3
- pertpy-1.0.1/biome.jsonc +34 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/api/tools_index.md +0 -2
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/changelog.md +12 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/__init__.py +1 -1
- pertpy-1.0.1/pertpy/data/_dataloader.py +117 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/__init__.py +18 -27
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_coda/_base_coda.py +10 -4
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_coda/_sccoda.py +42 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_dialogue.py +3 -3
- pertpy-1.0.1/pertpy/tools/_differential_gene_expression/__init__.py +60 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_differential_gene_expression/_base.py +2 -1
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_differential_gene_expression/_edger.py +9 -12
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_differential_gene_expression/_pydeseq2.py +0 -2
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_distances/_distance_tests.py +2 -2
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_distances/_distances.py +33 -8
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_milo.py +3 -1
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_perturbation_space/_discriminator_classifiers.py +16 -25
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_perturbation_space/_simple.py +8 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pyproject.toml +6 -4
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_differential_gene_expression/conftest.py +14 -1
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_differential_gene_expression/test_base.py +5 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_differential_gene_expression/test_compare_groups.py +6 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_differential_gene_expression/test_edger.py +8 -1
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_differential_gene_expression/test_input_checks.py +8 -1
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_differential_gene_expression/test_pydeseq2.py +9 -1
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_differential_gene_expression/test_simple_tests.py +6 -0
- pertpy-1.0.1/tests/tools/_differential_gene_expression/test_statsmodels.py +24 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_distances/test_distances.py +2 -2
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/test_milo.py +7 -7
- pertpy-1.0.0/biome.jsonc +0 -18
- pertpy-1.0.0/pertpy/data/_dataloader.py +0 -114
- pertpy-1.0.0/pertpy/tools/_differential_gene_expression/__init__.py +0 -19
- pertpy-1.0.0/tests/tools/_differential_gene_expression/test_statsmodels.py +0 -30
- {pertpy-1.0.0 → pertpy-1.0.1}/.editorconfig +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.gitattributes +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/labels.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/pull_request_template.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/workflows/build.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/workflows/labeler.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/workflows/release.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/workflows/release_drafter.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.github/workflows/test.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.gitignore +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.gitmodules +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/.readthedocs.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/LICENSE +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/README.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/codecov.yml +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/Makefile +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_ext/edit_on_github.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_ext/typed_returns.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/SCVI_LICENSE +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/css/overwrite.css +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/css/sphinx_gallery.css +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/augur_dp_scatter.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/augur_important_features.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/augur_lollipop.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/augur_scatterplot.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/de_fold_change.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/de_multicomparison_fc.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/de_paired_expression.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/de_volcano.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/dialogue_pairplot.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/dialogue_violin.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/enrichment_dotplot.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/enrichment_gsea.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/milo_da_beeswarm.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/milo_nhood.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/milo_nhood_graph.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/mixscape_barplot.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/mixscape_heatmap.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/mixscape_lda.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/mixscape_perturbscore.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/mixscape_violin.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/pseudobulk_samples.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/sccoda_boxplots.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/sccoda_effects_barplot.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/sccoda_rel_abundance_dispersion_plot.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/sccoda_stacked_barplot.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/scgen_reg_mean.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/tasccoda_draw_effects.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/tasccoda_draw_tree.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/docstring_previews/tasccoda_effects_umap.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/icons/code-24px.svg +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/icons/computer-24px.svg +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/icons/library_books-24px.svg +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/icons/play_circle_outline-24px.svg +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/pertpy_logo.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/pertpy_logo.svg +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/placeholder.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/augur.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/cinemaot.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/dge.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/dialogue.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/distances.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/distances_tests.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/enrichment.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/guide_rna_assignment.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/mcfarland.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/metadata.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/milo.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/mixscape.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/norman.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/ontology.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/perturbation_space.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/placeholder.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/sccoda.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/sccoda_extended.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/scgen_perturbation_prediction.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/tasccoda.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_static/tutorials/zhang.png +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/_templates/autosummary/class.rst +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/about/background.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/about/cite.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/api/datasets_index.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/api/metadata_index.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/api/preprocessing_index.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/api.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/conf.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/contributing.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/index.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/installation.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/make.bat +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/references.bib +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/references.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/tutorials/metadata.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/tutorials/preprocessing.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/tutorials/tools.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/tutorials.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/usecases.md +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/docs/utils.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/_doc.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/_types.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/data/__init__.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/data/_datasets.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/metadata/__init__.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/metadata/_cell_line.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/metadata/_compound.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/metadata/_drug.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/metadata/_look_up.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/metadata/_metadata.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/metadata/_moa.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/plot/__init__.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/preprocessing/__init__.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/preprocessing/_guide_rna.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/preprocessing/_guide_rna_mixture.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/py.typed +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_augur.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_cinemaot.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_coda/__init__.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_coda/_tasccoda.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_differential_gene_expression/_checks.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_differential_gene_expression/_dge_comparison.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_differential_gene_expression/_simple_tests.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_differential_gene_expression/_statsmodels.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_distances/__init__.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_enrichment.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_mixscape.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_perturbation_space/__init__.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_perturbation_space/_clustering.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_perturbation_space/_comparison.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_perturbation_space/_metrics.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_perturbation_space/_perturbation_space.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_scgen/__init__.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_scgen/_base_components.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_scgen/_scgen.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_scgen/_scgenvae.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/_scgen/_utils.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/decoupler_LICENSE +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/pertpy/tools/transferlearning_MMD_LICENSE +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/conftest.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/metadata/test_cell_line.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/metadata/test_compound.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/metadata/test_drug.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/metadata/test_moa.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/preprocessing/test_grna_assignment.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_coda/test_sccoda.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_coda/test_tasccoda.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_differential_gene_expression/__init__.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_differential_gene_expression/test_dge.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_distances/test_distance_tests.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_perturbation_space/test_comparison.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_perturbation_space/test_discriminator_classifiers.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_perturbation_space/test_simple_cluster_space.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/_perturbation_space/test_simple_perturbation_space.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/test_augur.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/test_cinemaot.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/test_dialogue.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/test_enrichment.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/test_mixscape.py +0 -0
- {pertpy-1.0.0 → pertpy-1.0.1}/tests/tools/test_scgen.py +0 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
name: Test tutorials
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [main]
|
6
|
+
pull_request:
|
7
|
+
branches: [main]
|
8
|
+
|
9
|
+
concurrency:
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
11
|
+
cancel-in-progress: true
|
12
|
+
|
13
|
+
jobs:
|
14
|
+
test:
|
15
|
+
runs-on: ubuntu-latest
|
16
|
+
defaults:
|
17
|
+
run:
|
18
|
+
# to fail on error in multiline statements (-e), in pipes (-o pipefail), and on unset variables (-u).
|
19
|
+
shell: bash -euo pipefail {0}
|
20
|
+
|
21
|
+
env:
|
22
|
+
NOTEBOOK_PATH: docs/tutorials/notebooks
|
23
|
+
|
24
|
+
strategy:
|
25
|
+
fail-fast: false
|
26
|
+
matrix:
|
27
|
+
notebook: [
|
28
|
+
"augur.ipynb",
|
29
|
+
"cinemaot.ipynb",
|
30
|
+
"differential_gene_expression.ipynb",
|
31
|
+
"distances.ipynb",
|
32
|
+
"distance_tests.ipynb",
|
33
|
+
"enrichment.ipynb",
|
34
|
+
"guide_rna_assignment.ipynb",
|
35
|
+
"milo.ipynb",
|
36
|
+
"mixscape.ipynb",
|
37
|
+
"perturbation_space.ipynb",
|
38
|
+
"sccoda.ipynb",
|
39
|
+
# "dialogue.ipynb", takes too long
|
40
|
+
# "tasccoda.ipynb", a pain to get running because of the required QT dependency. The QT action leads to a dead kernel
|
41
|
+
# also no use cases yet
|
42
|
+
]
|
43
|
+
|
44
|
+
steps:
|
45
|
+
- uses: actions/checkout@v4
|
46
|
+
with:
|
47
|
+
filter: blob:none
|
48
|
+
fetch-depth: 0
|
49
|
+
submodules: "true"
|
50
|
+
|
51
|
+
- name: Cache .pertpy_cache
|
52
|
+
uses: actions/cache@v4
|
53
|
+
with:
|
54
|
+
path: cache
|
55
|
+
key: ${{ runner.os }}-pertpy-cache-${{ hashFiles('pertpy/metadata/**') }}
|
56
|
+
restore-keys: |
|
57
|
+
${{ runner.os }}-pertpy-cache
|
58
|
+
|
59
|
+
- name: Set up Python
|
60
|
+
uses: actions/setup-python@v5
|
61
|
+
with:
|
62
|
+
python-version: "3.13"
|
63
|
+
- name: Install R
|
64
|
+
uses: r-lib/actions/setup-r@v2
|
65
|
+
with:
|
66
|
+
r-version: "4.4.3"
|
67
|
+
|
68
|
+
- name: Cache R packages
|
69
|
+
id: r-cache
|
70
|
+
uses: actions/cache@v3
|
71
|
+
with:
|
72
|
+
path: ${{ env.R_LIBS_USER }}
|
73
|
+
key: ${{ runner.os }}-r-${{ hashFiles('**/pertpy/tools/_milo.py') }}
|
74
|
+
restore-keys: ${{ runner.os }}-r-
|
75
|
+
|
76
|
+
- name: Install R dependencies
|
77
|
+
if: steps.r-cache.outputs.cache-hit != 'true'
|
78
|
+
run: |
|
79
|
+
mkdir -p ${{ env.R_LIBS_USER }}
|
80
|
+
Rscript --vanilla -e "install.packages(c('BiocManager', 'statmod'), repos='https://cran.r-project.org'); BiocManager::install('edgeR', lib='${{ env.R_LIBS_USER }}')"
|
81
|
+
|
82
|
+
- name: Install uv
|
83
|
+
uses: astral-sh/setup-uv@v6
|
84
|
+
with:
|
85
|
+
enable-cache: true
|
86
|
+
cache-dependency-glob: pyproject.toml
|
87
|
+
- name: Install dependencies
|
88
|
+
run: |
|
89
|
+
uv pip install --system rpy2 decoupler muon
|
90
|
+
uv pip install --system ${{ matrix.pip-flags }} ".[dev,test,tcoda,de]"
|
91
|
+
uv pip install --system nbconvert ipykernel
|
92
|
+
|
93
|
+
- name: Run ${{ matrix.notebook }} Notebook
|
94
|
+
run: jupyter nbconvert --to notebook --execute ${{ env.NOTEBOOK_PATH }}/${{ matrix.notebook }}
|
@@ -7,13 +7,13 @@ default_stages:
|
|
7
7
|
minimum_pre_commit_version: 2.16.0
|
8
8
|
repos:
|
9
9
|
- repo: https://github.com/biomejs/pre-commit
|
10
|
-
rev:
|
10
|
+
rev: v2.1.1
|
11
11
|
hooks:
|
12
12
|
- id: biome-format
|
13
13
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
14
|
-
rev: v0.
|
14
|
+
rev: v0.12.3
|
15
15
|
hooks:
|
16
|
-
- id: ruff
|
16
|
+
- id: ruff-check
|
17
17
|
args: [--fix, --exit-non-zero-on-fix, --unsafe-fixes]
|
18
18
|
- id: ruff-format
|
19
19
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
@@ -33,7 +33,7 @@ repos:
|
|
33
33
|
- id: no-commit-to-branch
|
34
34
|
args: ["--branch=main"]
|
35
35
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
36
|
-
rev: v1.
|
36
|
+
rev: v1.16.1
|
37
37
|
hooks:
|
38
38
|
- id: mypy
|
39
39
|
args: [--no-strict-optional, --ignore-missing-imports]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pertpy
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.1
|
4
4
|
Summary: Perturbation Analysis in the scverse ecosystem.
|
5
5
|
Project-URL: Documentation, https://pertpy.readthedocs.io
|
6
6
|
Project-URL: Source, https://github.com/scverse/pertpy
|
@@ -49,7 +49,7 @@ Requires-Python: <3.14,>=3.11
|
|
49
49
|
Requires-Dist: adjusttext
|
50
50
|
Requires-Dist: arviz
|
51
51
|
Requires-Dist: blitzgsea
|
52
|
-
Requires-Dist: fast-array-utils
|
52
|
+
Requires-Dist: fast-array-utils[accel,sparse]
|
53
53
|
Requires-Dist: lamin-utils
|
54
54
|
Requires-Dist: mudata
|
55
55
|
Requires-Dist: openpyxl
|
@@ -93,7 +93,7 @@ Requires-Dist: sphinxext-opengraph; extra == 'doc'
|
|
93
93
|
Provides-Extra: tcoda
|
94
94
|
Requires-Dist: ete4; extra == 'tcoda'
|
95
95
|
Requires-Dist: pyqt6; extra == 'tcoda'
|
96
|
-
Requires-Dist: toytree; extra == 'tcoda'
|
96
|
+
Requires-Dist: toytree>=3.0; extra == 'tcoda'
|
97
97
|
Provides-Extra: test
|
98
98
|
Requires-Dist: coverage; extra == 'test'
|
99
99
|
Requires-Dist: leidenalg; extra == 'test'
|
pertpy-1.0.1/biome.jsonc
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.0.5/schema.json",
|
3
|
+
"formatter": { "useEditorconfig": true },
|
4
|
+
"overrides": [
|
5
|
+
{
|
6
|
+
"includes": [".vscode/**/*.json", "**/*.jsonc", "**/asv.conf.json"],
|
7
|
+
"json": {
|
8
|
+
"formatter": {
|
9
|
+
"trailingCommas": "all",
|
10
|
+
},
|
11
|
+
"parser": {
|
12
|
+
"allowComments": true,
|
13
|
+
"allowTrailingCommas": true,
|
14
|
+
},
|
15
|
+
},
|
16
|
+
},
|
17
|
+
],
|
18
|
+
"linter": {
|
19
|
+
"rules": {
|
20
|
+
"style": {
|
21
|
+
"noParameterAssign": "error",
|
22
|
+
"useAsConstAssertion": "error",
|
23
|
+
"useDefaultParameterLast": "error",
|
24
|
+
"useEnumInitializers": "error",
|
25
|
+
"useSelfClosingElements": "error",
|
26
|
+
"useSingleVarDeclarator": "error",
|
27
|
+
"noUnusedTemplateLiteral": "error",
|
28
|
+
"useNumberNamespace": "error",
|
29
|
+
"noInferrableTypes": "error",
|
30
|
+
"noUselessElse": "error",
|
31
|
+
},
|
32
|
+
},
|
33
|
+
},
|
34
|
+
}
|
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## v1.0.1
|
9
|
+
|
10
|
+
|
11
|
+
### 🚀 Features
|
12
|
+
|
13
|
+
* Add support for gamma parameter in MMD distance ([#825](https://github.com/scverse/pertpy/pull/825)) @Zethson
|
14
|
+
* Run notebooks in CI ([#815](https://github.com/scverse/pertpy/pull/815)) @Zethson
|
15
|
+
|
16
|
+
## 🐛 Bug Fixes
|
17
|
+
|
18
|
+
* Fix milo output writing ([#821](https://github.com/scverse/pertpy/pull/821)) @Zethson
|
19
|
+
|
8
20
|
## v1.0.0
|
9
21
|
|
10
22
|
### 🚀 Features
|
@@ -0,0 +1,117 @@
|
|
1
|
+
import shutil
|
2
|
+
import tempfile
|
3
|
+
import time
|
4
|
+
from pathlib import Path
|
5
|
+
from random import choice
|
6
|
+
from string import ascii_lowercase
|
7
|
+
from zipfile import ZipFile
|
8
|
+
|
9
|
+
import requests
|
10
|
+
from filelock import FileLock
|
11
|
+
from lamin_utils import logger
|
12
|
+
from requests.exceptions import RequestException
|
13
|
+
from rich.progress import Progress
|
14
|
+
|
15
|
+
|
16
|
+
def _download( # pragma: no cover
|
17
|
+
url: str,
|
18
|
+
output_file_name: str | None = None,
|
19
|
+
output_path: str | Path | None = None,
|
20
|
+
block_size: int = 1024,
|
21
|
+
overwrite: bool = False,
|
22
|
+
is_zip: bool = False,
|
23
|
+
timeout: int = 30,
|
24
|
+
max_retries: int = 3,
|
25
|
+
retry_delay: int = 5,
|
26
|
+
) -> Path:
|
27
|
+
"""Downloads a dataset irrespective of the format.
|
28
|
+
|
29
|
+
Args:
|
30
|
+
url: URL to download
|
31
|
+
output_file_name: Name of the downloaded file
|
32
|
+
output_path: Path to download/extract the files to.
|
33
|
+
block_size: Block size for downloads in bytes.
|
34
|
+
overwrite: Whether to overwrite existing files.
|
35
|
+
is_zip: Whether the downloaded file needs to be unzipped.
|
36
|
+
timeout: Request timeout in seconds.
|
37
|
+
max_retries: Maximum number of retry attempts.
|
38
|
+
retry_delay: Delay between retries in seconds.
|
39
|
+
"""
|
40
|
+
if output_file_name is None:
|
41
|
+
letters = ascii_lowercase
|
42
|
+
output_file_name = f"pertpy_tmp_{''.join(choice(letters) for _ in range(10))}"
|
43
|
+
|
44
|
+
if output_path is None:
|
45
|
+
output_path = tempfile.gettempdir()
|
46
|
+
|
47
|
+
download_to_path = Path(output_path) / output_file_name
|
48
|
+
|
49
|
+
Path(output_path).mkdir(parents=True, exist_ok=True)
|
50
|
+
lock_path = Path(output_path) / f"{output_file_name}.lock"
|
51
|
+
|
52
|
+
try:
|
53
|
+
with FileLock(lock_path, timeout=300):
|
54
|
+
if Path(download_to_path).exists() and not overwrite:
|
55
|
+
logger.warning(f"File {download_to_path} already exists!")
|
56
|
+
return download_to_path
|
57
|
+
|
58
|
+
temp_file_name = Path(f"{download_to_path}.part")
|
59
|
+
|
60
|
+
retry_count = 0
|
61
|
+
while retry_count <= max_retries:
|
62
|
+
try:
|
63
|
+
head_response = requests.head(url, timeout=timeout)
|
64
|
+
head_response.raise_for_status()
|
65
|
+
content_length = int(head_response.headers.get("content-length", 0))
|
66
|
+
|
67
|
+
free_space = shutil.disk_usage(output_path).free
|
68
|
+
if content_length > free_space:
|
69
|
+
raise OSError(
|
70
|
+
f"Insufficient disk space. Need {content_length} bytes, but only {free_space} available."
|
71
|
+
)
|
72
|
+
|
73
|
+
response = requests.get(url, stream=True)
|
74
|
+
response.raise_for_status()
|
75
|
+
total = int(response.headers.get("content-length", 0))
|
76
|
+
|
77
|
+
with Progress(refresh_per_second=5) as progress:
|
78
|
+
task = progress.add_task("[red]Downloading...", total=total)
|
79
|
+
with Path(temp_file_name).open("wb") as file:
|
80
|
+
for data in response.iter_content(block_size):
|
81
|
+
file.write(data)
|
82
|
+
progress.update(task, advance=len(data))
|
83
|
+
progress.update(task, completed=total, refresh=True)
|
84
|
+
|
85
|
+
Path(temp_file_name).replace(download_to_path)
|
86
|
+
|
87
|
+
if is_zip:
|
88
|
+
with ZipFile(download_to_path, "r") as zip_obj:
|
89
|
+
zip_obj.extractall(path=output_path)
|
90
|
+
return Path(output_path)
|
91
|
+
|
92
|
+
return download_to_path
|
93
|
+
except (OSError, RequestException) as e:
|
94
|
+
retry_count += 1
|
95
|
+
if retry_count <= max_retries:
|
96
|
+
logger.warning(
|
97
|
+
f"Download attempt {retry_count}/{max_retries} failed: {str(e)}. Retrying in {retry_delay} seconds..."
|
98
|
+
)
|
99
|
+
time.sleep(retry_delay)
|
100
|
+
else:
|
101
|
+
logger.error(f"Download failed after {max_retries} attempts: {str(e)}")
|
102
|
+
if Path(temp_file_name).exists():
|
103
|
+
Path(temp_file_name).unlink(missing_ok=True)
|
104
|
+
raise
|
105
|
+
|
106
|
+
except Exception as e:
|
107
|
+
logger.error(f"Download failed: {str(e)}")
|
108
|
+
if Path(temp_file_name).exists():
|
109
|
+
Path(temp_file_name).unlink(missing_ok=True)
|
110
|
+
raise
|
111
|
+
finally:
|
112
|
+
if Path(temp_file_name).exists():
|
113
|
+
Path(temp_file_name).unlink(missing_ok=True)
|
114
|
+
finally:
|
115
|
+
lock_path.unlink(missing_ok=True)
|
116
|
+
|
117
|
+
return Path(download_to_path)
|
@@ -1,24 +1,5 @@
|
|
1
1
|
from importlib import import_module
|
2
2
|
|
3
|
-
|
4
|
-
def lazy_import(module_path: str, class_name: str, extras: list[str]):
|
5
|
-
try:
|
6
|
-
for extra in extras:
|
7
|
-
import_module(extra)
|
8
|
-
module = import_module(module_path)
|
9
|
-
return getattr(module, class_name)
|
10
|
-
except ImportError:
|
11
|
-
|
12
|
-
class Placeholder:
|
13
|
-
def __init__(self, *args, **kwargs):
|
14
|
-
raise ImportError(
|
15
|
-
f"Extra dependencies required: {', '.join(extras)}. "
|
16
|
-
f"Please install with: pip install {' '.join(extras)}"
|
17
|
-
)
|
18
|
-
|
19
|
-
return Placeholder
|
20
|
-
|
21
|
-
|
22
3
|
from pertpy.tools._augur import Augur
|
23
4
|
from pertpy.tools._cinemaot import Cinemaot
|
24
5
|
from pertpy.tools._coda._sccoda import Sccoda
|
@@ -42,15 +23,25 @@ from pertpy.tools._perturbation_space._simple import (
|
|
42
23
|
)
|
43
24
|
from pertpy.tools._scgen import Scgen
|
44
25
|
|
45
|
-
CODA_EXTRAS = ["toytree", "ete4"] # also "pyqt6" but it cannot be imported
|
46
|
-
Tasccoda = lazy_import("pertpy.tools._coda._tasccoda", "Tasccoda", CODA_EXTRAS)
|
47
26
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
27
|
+
def __getattr__(name: str):
|
28
|
+
if name == "Tasccoda":
|
29
|
+
try:
|
30
|
+
for extra in ["toytree", "ete4"]:
|
31
|
+
import_module(extra)
|
32
|
+
module = import_module("pertpy.tools._coda._tasccoda")
|
33
|
+
return module.Tasccoda
|
34
|
+
except ImportError:
|
35
|
+
raise ImportError(
|
36
|
+
"Extra dependencies required: toytree, ete4. Please install with: pip install toytree ete4"
|
37
|
+
) from None
|
38
|
+
|
39
|
+
elif name in ["EdgeR", "PyDESeq2", "Statsmodels", "TTest", "WilcoxonTest"]:
|
40
|
+
module = import_module("pertpy.tools._differential_gene_expression")
|
41
|
+
return getattr(module, name)
|
42
|
+
|
43
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
44
|
+
|
54
45
|
|
55
46
|
__all__ = [
|
56
47
|
"Augur",
|
@@ -1181,7 +1181,7 @@ class CompositionalModel2(ABC):
|
|
1181
1181
|
r,
|
1182
1182
|
bars,
|
1183
1183
|
bottom=cum_bars,
|
1184
|
-
color=palette(n % palette.N),
|
1184
|
+
color=palette(n % palette.N), # type: ignore
|
1185
1185
|
width=barwidth,
|
1186
1186
|
label=type_names[n],
|
1187
1187
|
linewidth=0,
|
@@ -1377,6 +1377,7 @@ class CompositionalModel2(ABC):
|
|
1377
1377
|
plot_df.columns = covariate_names
|
1378
1378
|
plot_df = pd.melt(plot_df, ignore_index=False, var_name="Covariate")
|
1379
1379
|
|
1380
|
+
plot_df.index.name = "Cell Type"
|
1380
1381
|
plot_df = plot_df.reset_index()
|
1381
1382
|
|
1382
1383
|
if len(covariate_names_zero) != 0 and plot_facets and plot_zero_covariate and not plot_zero_cell_type:
|
@@ -1472,6 +1473,7 @@ class CompositionalModel2(ABC):
|
|
1472
1473
|
if return_fig and not plot_facets:
|
1473
1474
|
return plt.gcf()
|
1474
1475
|
plt.show()
|
1476
|
+
|
1475
1477
|
return None
|
1476
1478
|
|
1477
1479
|
@_doc_params(common_plot_args=doc_common_plot_args)
|
@@ -1823,6 +1825,7 @@ class CompositionalModel2(ABC):
|
|
1823
1825
|
if return_fig:
|
1824
1826
|
return plt.gcf()
|
1825
1827
|
plt.show()
|
1828
|
+
|
1826
1829
|
return None
|
1827
1830
|
|
1828
1831
|
@_doc_params(common_plot_args=doc_common_plot_args)
|
@@ -1881,7 +1884,7 @@ class CompositionalModel2(ABC):
|
|
1881
1884
|
from ete4.treeview import CircleFace, NodeStyle, TextFace, TreeStyle, faces
|
1882
1885
|
except ImportError:
|
1883
1886
|
raise ImportError(
|
1884
|
-
"To use tasccoda please install additional dependencies
|
1887
|
+
"To use tasccoda please install additional dependencies: `pip install pertpy[coda]`"
|
1885
1888
|
) from None
|
1886
1889
|
|
1887
1890
|
if isinstance(data, MuData):
|
@@ -1902,8 +1905,8 @@ class CompositionalModel2(ABC):
|
|
1902
1905
|
tree.render(save, tree_style=tree_style, units=units, w=figsize[0], h=figsize[1], dpi=dpi) # type: ignore
|
1903
1906
|
if return_fig:
|
1904
1907
|
return tree, tree_style
|
1908
|
+
|
1905
1909
|
return tree.render("%%inline", tree_style=tree_style, units=units, w=figsize[0], h=figsize[1], dpi=dpi) # type: ignore
|
1906
|
-
return None
|
1907
1910
|
|
1908
1911
|
@_doc_params(common_plot_args=doc_common_plot_args)
|
1909
1912
|
def plot_draw_effects( # pragma: no cover # noqa: D417
|
@@ -1969,7 +1972,7 @@ class CompositionalModel2(ABC):
|
|
1969
1972
|
from ete4.treeview import CircleFace, NodeStyle, TextFace, TreeStyle, faces
|
1970
1973
|
except ImportError:
|
1971
1974
|
raise ImportError(
|
1972
|
-
"To use tasccoda please install additional dependencies
|
1975
|
+
"To use tasccoda please install additional dependencies: `pip install pertpy[coda]`"
|
1973
1976
|
) from None
|
1974
1977
|
|
1975
1978
|
if isinstance(data, MuData):
|
@@ -2207,6 +2210,7 @@ class CompositionalModel2(ABC):
|
|
2207
2210
|
if return_fig:
|
2208
2211
|
return fig
|
2209
2212
|
plt.show()
|
2213
|
+
|
2210
2214
|
return None
|
2211
2215
|
|
2212
2216
|
|
@@ -2325,6 +2329,7 @@ def df2newick(df: pd.DataFrame, levels: list[str], inner_label: bool = True) ->
|
|
2325
2329
|
strs = [traverse(df_tax, a, 0, inner_label) for a in alevel]
|
2326
2330
|
|
2327
2331
|
newick = f"({','.join(strs)});"
|
2332
|
+
|
2328
2333
|
return newick
|
2329
2334
|
|
2330
2335
|
|
@@ -2562,6 +2567,7 @@ def from_scanpy(
|
|
2562
2567
|
covariate_obs = list(set(covariate_obs or []) | set(sample_identifier))
|
2563
2568
|
|
2564
2569
|
if isinstance(sample_identifier, list):
|
2570
|
+
adata.obs = adata.obs.copy()
|
2565
2571
|
adata.obs["scCODA_sample_id"] = adata.obs[sample_identifier].agg("-".join, axis=1)
|
2566
2572
|
sample_identifier = "scCODA_sample_id"
|
2567
2573
|
|
@@ -409,6 +409,48 @@ class Sccoda(CompositionalModel2):
|
|
409
409
|
import arviz as az
|
410
410
|
|
411
411
|
# Create arviz object
|
412
|
+
if use_posterior_predictive:
|
413
|
+
posterior_predictive = Predictive(self.model, self.mcmc.get_samples())(
|
414
|
+
rng_key,
|
415
|
+
counts=None,
|
416
|
+
covariates=numpyro_covariates,
|
417
|
+
n_total=numpyro_n_total,
|
418
|
+
ref_index=ref_index,
|
419
|
+
sample_adata=sample_adata,
|
420
|
+
)
|
421
|
+
# Remove problematic posterior predictive arrays with wrong dimensions
|
422
|
+
if posterior_predictive and "counts" in posterior_predictive:
|
423
|
+
counts_shape = posterior_predictive["counts"].shape
|
424
|
+
expected_dims = 2 # ['sample', 'cell_type']
|
425
|
+
if len(counts_shape) != expected_dims:
|
426
|
+
posterior_predictive = {k: v for k, v in posterior_predictive.items() if k != "counts"}
|
427
|
+
logger.warning(
|
428
|
+
f"Removed 'counts' from posterior_predictive due to dimension mismatch: got {len(counts_shape)}D, expected {expected_dims}D"
|
429
|
+
)
|
430
|
+
else:
|
431
|
+
posterior_predictive = None
|
432
|
+
|
433
|
+
if num_prior_samples > 0:
|
434
|
+
prior = Predictive(self.model, num_samples=num_prior_samples)(
|
435
|
+
rng_key,
|
436
|
+
counts=None,
|
437
|
+
covariates=numpyro_covariates,
|
438
|
+
n_total=numpyro_n_total,
|
439
|
+
ref_index=ref_index,
|
440
|
+
sample_adata=sample_adata,
|
441
|
+
)
|
442
|
+
# Remove problematic prior arrays with wrong dimensions
|
443
|
+
if prior and "counts" in prior:
|
444
|
+
counts_shape = prior["counts"].shape
|
445
|
+
expected_dims = 2 # ['sample', 'cell_type']
|
446
|
+
if len(counts_shape) != expected_dims:
|
447
|
+
prior = {k: v for k, v in prior.items() if k != "counts"}
|
448
|
+
logger.warning(
|
449
|
+
f"Removed 'counts' from prior due to dimension mismatch: got {len(counts_shape)}D, expected {expected_dims}D"
|
450
|
+
)
|
451
|
+
else:
|
452
|
+
prior = None
|
453
|
+
|
412
454
|
arviz_data = az.from_numpyro(
|
413
455
|
self.mcmc, prior=prior, posterior_predictive=posterior_predictive, dims=dims, coords=coords
|
414
456
|
)
|
@@ -882,9 +882,9 @@ class Dialogue:
|
|
882
882
|
if len(conditions_compare) != 2:
|
883
883
|
raise ValueError("Please specify conditions to compare or supply an object with only 2 conditions")
|
884
884
|
|
885
|
-
pvals = pd.DataFrame(1, adata.obs[celltype_label].unique(), ["mcp_" + str(n) for n in range(n_mcps)])
|
886
|
-
tstats = pd.DataFrame(1, adata.obs[celltype_label].unique(), ["mcp_" + str(n) for n in range(n_mcps)])
|
887
|
-
pvals_adj = pd.DataFrame(1, adata.obs[celltype_label].unique(), ["mcp_" + str(n) for n in range(n_mcps)])
|
885
|
+
pvals = pd.DataFrame(1.0, adata.obs[celltype_label].unique(), ["mcp_" + str(n) for n in range(n_mcps)])
|
886
|
+
tstats = pd.DataFrame(1.0, adata.obs[celltype_label].unique(), ["mcp_" + str(n) for n in range(n_mcps)])
|
887
|
+
pvals_adj = pd.DataFrame(1.0, adata.obs[celltype_label].unique(), ["mcp_" + str(n) for n in range(n_mcps)])
|
888
888
|
|
889
889
|
response = adata.obs.groupby(sample_label)[condition_label].agg(pd.Series.mode)
|
890
890
|
for celltype in adata.obs[celltype_label].unique():
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import contextlib
|
2
|
+
from importlib import import_module
|
3
|
+
from importlib.util import find_spec
|
4
|
+
|
5
|
+
from ._base import LinearModelBase, MethodBase
|
6
|
+
from ._dge_comparison import DGEEVAL
|
7
|
+
from ._edger import EdgeR
|
8
|
+
from ._simple_tests import SimpleComparisonBase, TTest, WilcoxonTest
|
9
|
+
|
10
|
+
|
11
|
+
def __getattr__(name: str):
|
12
|
+
deps = {
|
13
|
+
"PyDESeq2": ["pydeseq2", "formulaic_contrasts", "formulaic"],
|
14
|
+
"EdgeR": ["rpy2", "formulaic_contrasts", "formulaic"],
|
15
|
+
"Statsmodels": ["formulaic_contrasts", "formulaic"],
|
16
|
+
}
|
17
|
+
|
18
|
+
if name in deps:
|
19
|
+
for dep in deps[name]:
|
20
|
+
if find_spec(dep) is None:
|
21
|
+
raise ImportError(f"{dep} is required but not installed")
|
22
|
+
|
23
|
+
module_map = {
|
24
|
+
"PyDESeq2": "pertpy.tools._differential_gene_expression._pydeseq2",
|
25
|
+
"EdgeR": "pertpy.tools._differential_gene_expression._edger",
|
26
|
+
"Statsmodels": "pertpy.tools._differential_gene_expression._statsmodels",
|
27
|
+
}
|
28
|
+
|
29
|
+
module = import_module(module_map[name])
|
30
|
+
return getattr(module, name)
|
31
|
+
|
32
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
33
|
+
|
34
|
+
|
35
|
+
def _get_available_methods():
|
36
|
+
methods = [WilcoxonTest, TTest]
|
37
|
+
from importlib.util import find_spec
|
38
|
+
|
39
|
+
for name in ["Statsmodels", "PyDESeq2", "EdgeR"]:
|
40
|
+
with contextlib.suppress(ImportError):
|
41
|
+
methods.append(__getattr__(name))
|
42
|
+
|
43
|
+
return methods
|
44
|
+
|
45
|
+
|
46
|
+
AVAILABLE_METHODS = _get_available_methods()
|
47
|
+
|
48
|
+
|
49
|
+
AVAILABLE_METHODS = _get_available_methods()
|
50
|
+
|
51
|
+
__all__ = [
|
52
|
+
"MethodBase",
|
53
|
+
"LinearModelBase",
|
54
|
+
"EdgeR",
|
55
|
+
"PyDESeq2",
|
56
|
+
"Statsmodels",
|
57
|
+
"SimpleComparisonBase",
|
58
|
+
"WilcoxonTest",
|
59
|
+
"TTest",
|
60
|
+
]
|
@@ -12,7 +12,6 @@ import matplotlib.pyplot as plt
|
|
12
12
|
import numpy as np
|
13
13
|
import pandas as pd
|
14
14
|
import seaborn as sns
|
15
|
-
from formulaic_contrasts import FormulaicContrasts
|
16
15
|
from lamin_utils import logger
|
17
16
|
from matplotlib.pyplot import Figure
|
18
17
|
from matplotlib.ticker import MaxNLocator
|
@@ -881,6 +880,8 @@ class LinearModelBase(MethodBase):
|
|
881
880
|
super().__init__(adata, mask=mask, layer=layer)
|
882
881
|
self._check_counts()
|
883
882
|
|
883
|
+
from formulaic_contrasts import FormulaicContrasts
|
884
|
+
|
884
885
|
self.formulaic_contrasts = None
|
885
886
|
if isinstance(design, str):
|
886
887
|
self.formulaic_contrasts = FormulaicContrasts(adata.obs, design)
|