pertpy 0.11.5__tar.gz → 1.0.0__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.
Files changed (193) hide show
  1. {pertpy-0.11.5 → pertpy-1.0.0}/.github/release-drafter.yml +2 -2
  2. {pertpy-0.11.5 → pertpy-1.0.0}/PKG-INFO +8 -2
  3. {pertpy-0.11.5 → pertpy-1.0.0}/README.md +7 -1
  4. {pertpy-0.11.5 → pertpy-1.0.0}/docs/changelog.md +23 -2
  5. {pertpy-0.11.5 → pertpy-1.0.0}/docs/index.md +3 -3
  6. {pertpy-0.11.5 → pertpy-1.0.0}/docs/installation.md +7 -1
  7. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/__init__.py +4 -1
  8. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_milo.py +77 -24
  9. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_perturbation_space/_perturbation_space.py +1 -1
  10. {pertpy-0.11.5 → pertpy-1.0.0}/pyproject.toml +2 -2
  11. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/test_milo.py +34 -6
  12. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/test_scgen.py +6 -2
  13. {pertpy-0.11.5 → pertpy-1.0.0}/.editorconfig +0 -0
  14. {pertpy-0.11.5 → pertpy-1.0.0}/.gitattributes +0 -0
  15. {pertpy-0.11.5 → pertpy-1.0.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  16. {pertpy-0.11.5 → pertpy-1.0.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  17. {pertpy-0.11.5 → pertpy-1.0.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  18. {pertpy-0.11.5 → pertpy-1.0.0}/.github/labels.yml +0 -0
  19. {pertpy-0.11.5 → pertpy-1.0.0}/.github/pull_request_template.md +0 -0
  20. {pertpy-0.11.5 → pertpy-1.0.0}/.github/workflows/build.yml +0 -0
  21. {pertpy-0.11.5 → pertpy-1.0.0}/.github/workflows/labeler.yml +0 -0
  22. {pertpy-0.11.5 → pertpy-1.0.0}/.github/workflows/release.yml +0 -0
  23. {pertpy-0.11.5 → pertpy-1.0.0}/.github/workflows/release_drafter.yml +0 -0
  24. {pertpy-0.11.5 → pertpy-1.0.0}/.github/workflows/test.yml +0 -0
  25. {pertpy-0.11.5 → pertpy-1.0.0}/.gitignore +0 -0
  26. {pertpy-0.11.5 → pertpy-1.0.0}/.gitmodules +0 -0
  27. {pertpy-0.11.5 → pertpy-1.0.0}/.pre-commit-config.yaml +0 -0
  28. {pertpy-0.11.5 → pertpy-1.0.0}/.readthedocs.yml +0 -0
  29. {pertpy-0.11.5 → pertpy-1.0.0}/LICENSE +0 -0
  30. {pertpy-0.11.5 → pertpy-1.0.0}/biome.jsonc +0 -0
  31. {pertpy-0.11.5 → pertpy-1.0.0}/codecov.yml +0 -0
  32. {pertpy-0.11.5 → pertpy-1.0.0}/docs/Makefile +0 -0
  33. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_ext/edit_on_github.py +0 -0
  34. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_ext/typed_returns.py +0 -0
  35. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/SCVI_LICENSE +0 -0
  36. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/css/overwrite.css +0 -0
  37. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/css/sphinx_gallery.css +0 -0
  38. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/augur_dp_scatter.png +0 -0
  39. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/augur_important_features.png +0 -0
  40. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/augur_lollipop.png +0 -0
  41. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/augur_scatterplot.png +0 -0
  42. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/de_fold_change.png +0 -0
  43. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/de_multicomparison_fc.png +0 -0
  44. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/de_paired_expression.png +0 -0
  45. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/de_volcano.png +0 -0
  46. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/dialogue_pairplot.png +0 -0
  47. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/dialogue_violin.png +0 -0
  48. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/enrichment_dotplot.png +0 -0
  49. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/enrichment_gsea.png +0 -0
  50. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/milo_da_beeswarm.png +0 -0
  51. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/milo_nhood.png +0 -0
  52. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/milo_nhood_graph.png +0 -0
  53. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/mixscape_barplot.png +0 -0
  54. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/mixscape_heatmap.png +0 -0
  55. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/mixscape_lda.png +0 -0
  56. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/mixscape_perturbscore.png +0 -0
  57. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/mixscape_violin.png +0 -0
  58. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/pseudobulk_samples.png +0 -0
  59. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/sccoda_boxplots.png +0 -0
  60. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/sccoda_effects_barplot.png +0 -0
  61. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/sccoda_rel_abundance_dispersion_plot.png +0 -0
  62. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/sccoda_stacked_barplot.png +0 -0
  63. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/scgen_reg_mean.png +0 -0
  64. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/tasccoda_draw_effects.png +0 -0
  65. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/tasccoda_draw_tree.png +0 -0
  66. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/docstring_previews/tasccoda_effects_umap.png +0 -0
  67. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/icons/code-24px.svg +0 -0
  68. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/icons/computer-24px.svg +0 -0
  69. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/icons/library_books-24px.svg +0 -0
  70. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/icons/play_circle_outline-24px.svg +0 -0
  71. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/pertpy_logo.png +0 -0
  72. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/pertpy_logo.svg +0 -0
  73. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/placeholder.png +0 -0
  74. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/augur.png +0 -0
  75. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/cinemaot.png +0 -0
  76. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/dge.png +0 -0
  77. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/dialogue.png +0 -0
  78. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/distances.png +0 -0
  79. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/distances_tests.png +0 -0
  80. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/enrichment.png +0 -0
  81. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/guide_rna_assignment.png +0 -0
  82. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/mcfarland.png +0 -0
  83. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/metadata.png +0 -0
  84. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/milo.png +0 -0
  85. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/mixscape.png +0 -0
  86. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/norman.png +0 -0
  87. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/ontology.png +0 -0
  88. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/perturbation_space.png +0 -0
  89. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/placeholder.png +0 -0
  90. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/sccoda.png +0 -0
  91. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/sccoda_extended.png +0 -0
  92. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/scgen_perturbation_prediction.png +0 -0
  93. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/tasccoda.png +0 -0
  94. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_static/tutorials/zhang.png +0 -0
  95. {pertpy-0.11.5 → pertpy-1.0.0}/docs/_templates/autosummary/class.rst +0 -0
  96. {pertpy-0.11.5 → pertpy-1.0.0}/docs/about/background.md +0 -0
  97. {pertpy-0.11.5 → pertpy-1.0.0}/docs/about/cite.md +0 -0
  98. {pertpy-0.11.5 → pertpy-1.0.0}/docs/api/datasets_index.md +0 -0
  99. {pertpy-0.11.5 → pertpy-1.0.0}/docs/api/metadata_index.md +0 -0
  100. {pertpy-0.11.5 → pertpy-1.0.0}/docs/api/preprocessing_index.md +0 -0
  101. {pertpy-0.11.5 → pertpy-1.0.0}/docs/api/tools_index.md +0 -0
  102. {pertpy-0.11.5 → pertpy-1.0.0}/docs/api.md +0 -0
  103. {pertpy-0.11.5 → pertpy-1.0.0}/docs/conf.py +0 -0
  104. {pertpy-0.11.5 → pertpy-1.0.0}/docs/contributing.md +0 -0
  105. {pertpy-0.11.5 → pertpy-1.0.0}/docs/make.bat +0 -0
  106. {pertpy-0.11.5 → pertpy-1.0.0}/docs/references.bib +0 -0
  107. {pertpy-0.11.5 → pertpy-1.0.0}/docs/references.md +0 -0
  108. {pertpy-0.11.5 → pertpy-1.0.0}/docs/tutorials/metadata.md +0 -0
  109. {pertpy-0.11.5 → pertpy-1.0.0}/docs/tutorials/preprocessing.md +0 -0
  110. {pertpy-0.11.5 → pertpy-1.0.0}/docs/tutorials/tools.md +0 -0
  111. {pertpy-0.11.5 → pertpy-1.0.0}/docs/tutorials.md +0 -0
  112. {pertpy-0.11.5 → pertpy-1.0.0}/docs/usecases.md +0 -0
  113. {pertpy-0.11.5 → pertpy-1.0.0}/docs/utils.py +0 -0
  114. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/_doc.py +0 -0
  115. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/_types.py +0 -0
  116. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/data/__init__.py +0 -0
  117. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/data/_dataloader.py +0 -0
  118. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/data/_datasets.py +0 -0
  119. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/metadata/__init__.py +0 -0
  120. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/metadata/_cell_line.py +0 -0
  121. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/metadata/_compound.py +0 -0
  122. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/metadata/_drug.py +0 -0
  123. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/metadata/_look_up.py +0 -0
  124. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/metadata/_metadata.py +0 -0
  125. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/metadata/_moa.py +0 -0
  126. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/plot/__init__.py +0 -0
  127. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/preprocessing/__init__.py +0 -0
  128. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/preprocessing/_guide_rna.py +0 -0
  129. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/preprocessing/_guide_rna_mixture.py +0 -0
  130. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/py.typed +0 -0
  131. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/__init__.py +0 -0
  132. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_augur.py +0 -0
  133. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_cinemaot.py +0 -0
  134. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_coda/__init__.py +0 -0
  135. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_coda/_base_coda.py +0 -0
  136. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_coda/_sccoda.py +0 -0
  137. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_coda/_tasccoda.py +0 -0
  138. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_dialogue.py +0 -0
  139. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_differential_gene_expression/__init__.py +0 -0
  140. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_differential_gene_expression/_base.py +0 -0
  141. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_differential_gene_expression/_checks.py +0 -0
  142. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_differential_gene_expression/_dge_comparison.py +0 -0
  143. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_differential_gene_expression/_edger.py +0 -0
  144. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_differential_gene_expression/_pydeseq2.py +0 -0
  145. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_differential_gene_expression/_simple_tests.py +0 -0
  146. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_differential_gene_expression/_statsmodels.py +0 -0
  147. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_distances/__init__.py +0 -0
  148. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_distances/_distance_tests.py +0 -0
  149. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_distances/_distances.py +0 -0
  150. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_enrichment.py +0 -0
  151. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_mixscape.py +0 -0
  152. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_perturbation_space/__init__.py +0 -0
  153. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_perturbation_space/_clustering.py +0 -0
  154. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_perturbation_space/_comparison.py +0 -0
  155. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_perturbation_space/_discriminator_classifiers.py +0 -0
  156. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_perturbation_space/_metrics.py +0 -0
  157. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_perturbation_space/_simple.py +0 -0
  158. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_scgen/__init__.py +0 -0
  159. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_scgen/_base_components.py +0 -0
  160. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_scgen/_scgen.py +0 -0
  161. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_scgen/_scgenvae.py +0 -0
  162. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/_scgen/_utils.py +0 -0
  163. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/decoupler_LICENSE +0 -0
  164. {pertpy-0.11.5 → pertpy-1.0.0}/pertpy/tools/transferlearning_MMD_LICENSE +0 -0
  165. {pertpy-0.11.5 → pertpy-1.0.0}/tests/conftest.py +0 -0
  166. {pertpy-0.11.5 → pertpy-1.0.0}/tests/metadata/test_cell_line.py +0 -0
  167. {pertpy-0.11.5 → pertpy-1.0.0}/tests/metadata/test_compound.py +0 -0
  168. {pertpy-0.11.5 → pertpy-1.0.0}/tests/metadata/test_drug.py +0 -0
  169. {pertpy-0.11.5 → pertpy-1.0.0}/tests/metadata/test_moa.py +0 -0
  170. {pertpy-0.11.5 → pertpy-1.0.0}/tests/preprocessing/test_grna_assignment.py +0 -0
  171. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_coda/test_sccoda.py +0 -0
  172. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_coda/test_tasccoda.py +0 -0
  173. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_differential_gene_expression/__init__.py +0 -0
  174. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_differential_gene_expression/conftest.py +0 -0
  175. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_differential_gene_expression/test_base.py +0 -0
  176. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_differential_gene_expression/test_compare_groups.py +0 -0
  177. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_differential_gene_expression/test_dge.py +0 -0
  178. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_differential_gene_expression/test_edger.py +0 -0
  179. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_differential_gene_expression/test_input_checks.py +0 -0
  180. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_differential_gene_expression/test_pydeseq2.py +0 -0
  181. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_differential_gene_expression/test_simple_tests.py +0 -0
  182. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_differential_gene_expression/test_statsmodels.py +0 -0
  183. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_distances/test_distance_tests.py +0 -0
  184. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_distances/test_distances.py +0 -0
  185. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_perturbation_space/test_comparison.py +0 -0
  186. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_perturbation_space/test_discriminator_classifiers.py +0 -0
  187. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_perturbation_space/test_simple_cluster_space.py +0 -0
  188. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/_perturbation_space/test_simple_perturbation_space.py +0 -0
  189. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/test_augur.py +0 -0
  190. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/test_cinemaot.py +0 -0
  191. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/test_dialogue.py +0 -0
  192. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/test_enrichment.py +0 -0
  193. {pertpy-0.11.5 → pertpy-1.0.0}/tests/tools/test_mixscape.py +0 -0
@@ -1,5 +1,5 @@
1
- name-template: "0.11.5 🌈"
2
- tag-template: 0.11.5
1
+ name-template: "1.0.0 🌈"
2
+ tag-template: 1.0.0
3
3
  exclude-labels:
4
4
  - "skip-changelog"
5
5
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pertpy
3
- Version: 0.11.5
3
+ Version: 1.0.0
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
@@ -155,7 +155,13 @@ pip install 'pertpy[tcoda]'
155
155
 
156
156
  ### milo
157
157
 
158
- milo further requires edger, statmod, and rpy2 to be installed:
158
+ milo requires either the "de" extra for the "pydeseq2" solver:
159
+
160
+ ```console
161
+ pip install 'pertpy[de]'
162
+ ```
163
+
164
+ or, edger, statmod, and rpy2 for the "edger" solver:
159
165
 
160
166
  ```R
161
167
  BiocManager::install("edgeR")
@@ -53,7 +53,13 @@ pip install 'pertpy[tcoda]'
53
53
 
54
54
  ### milo
55
55
 
56
- milo further requires edger, statmod, and rpy2 to be installed:
56
+ milo requires either the "de" extra for the "pydeseq2" solver:
57
+
58
+ ```console
59
+ pip install 'pertpy[de]'
60
+ ```
61
+
62
+ or, edger, statmod, and rpy2 for the "edger" solver:
57
63
 
58
64
  ```R
59
65
  BiocManager::install("edgeR")
@@ -5,7 +5,28 @@ 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
- ## v0.11.3
8
+ ## v1.0.0
9
+
10
+ ### 🚀 Features
11
+
12
+ * Simplify guide assignment tutorial ([#796](https://github.com/scverse/pertpy/pull/796)) @Zethson
13
+ * Add milo pydeseq2 solver ([#795](https://github.com/scverse/pertpy/pull/795)) @Zethson
14
+
15
+ ## v0.11.5
16
+
17
+ ### 🚀 Features
18
+
19
+ * Move to trusted publishing ([#790](https://github.com/scverse/pertpy/pull/790)) @Zethson
20
+ * Add conda-forge to installation instructions ([#789](https://github.com/scverse/pertpy/pull/789)) @Zethson
21
+ * Fix seaborn 0.14 compat & testing dependencies & speed up tests ([#787](https://github.com/scverse/pertpy/pull/787)) @Zethson
22
+ * Support > 2 colors in `pt.tl.Sccoda.plot_boxplots` ([#784](https://github.com/scverse/pertpy/pull/784)) @mschilli87
23
+
24
+ ### 🐛 Bug Fixes
25
+
26
+ * Fix LIL support for AnnData 0.12 ([#792](https://github.com/scverse/pertpy/pull/792)) @Zethson
27
+ * Fix compatibility with rpy 3.6.0 in milo ([#791](https://github.com/scverse/pertpy/pull/791)) @seohyonkim
28
+
29
+ ## v0.11.4
9
30
 
10
31
  ### 🧰 Maintenance
11
32
 
@@ -13,7 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13
34
 
14
35
  ## v0.11.3
15
36
 
16
- ## 🚀 Features
37
+ ### 🚀 Features
17
38
 
18
39
  * add about page ([#770](https://github.com/scverse/pertpy/pull/770)) @Zethson
19
40
  * Simplify Metadata errors ([#765](https://github.com/scverse/pertpy/pull/765)) @Zethson
@@ -48,7 +48,7 @@ It provides tools for harmonizing perturbation datasets, automating metadata ann
48
48
  ```{toctree}
49
49
  :caption: 'General'
50
50
  :hidden: true
51
- :maxdepth: 1
51
+ :maxdepth: 2
52
52
 
53
53
  installation
54
54
  api
@@ -60,7 +60,7 @@ references
60
60
  ```{toctree}
61
61
  :caption: 'Gallery'
62
62
  :hidden: true
63
- :maxdepth: 1
63
+ :maxdepth: 3
64
64
 
65
65
  tutorials
66
66
  usecases
@@ -69,7 +69,7 @@ usecases
69
69
  ```{toctree}
70
70
  :caption: 'About'
71
71
  :hidden: true
72
- :maxdepth: 1
72
+ :maxdepth: 2
73
73
 
74
74
  about/background
75
75
  about/cite
@@ -47,7 +47,13 @@ pip install rpy2
47
47
 
48
48
  #### milo
49
49
 
50
- milo further requires edger, statmod, and rpy2 to be installed:
50
+ milo requires either the "de" extra for the "pydeseq2" solver:
51
+
52
+ ```console
53
+ pip install 'pertpy[de]'
54
+ ```
55
+
56
+ or, edger, statmod, and rpy2 for the "edger" solver:
51
57
 
52
58
  ```R
53
59
  BiocManager::install("edgeR")
@@ -2,10 +2,11 @@
2
2
 
3
3
  __author__ = "Lukas Heumos"
4
4
  __email__ = "lukas.heumos@posteo.net"
5
- __version__ = "0.11.5"
5
+ __version__ = "1.0.0"
6
6
 
7
7
  import warnings
8
8
 
9
+ from anndata._core.aligned_df import ImplicitModificationWarning
9
10
  from matplotlib import MatplotlibDeprecationWarning
10
11
  from numba import NumbaDeprecationWarning
11
12
 
@@ -13,6 +14,8 @@ warnings.filterwarnings("ignore", category=NumbaDeprecationWarning)
13
14
  warnings.filterwarnings("ignore", category=MatplotlibDeprecationWarning)
14
15
  warnings.filterwarnings("ignore", category=SyntaxWarning)
15
16
  warnings.filterwarnings("ignore", category=UserWarning, module="scvi._settings")
17
+ warnings.filterwarnings("ignore", message="Environment variable.*redefined by R")
18
+ warnings.filterwarnings("ignore", message="Transforming to str index.", category=ImplicitModificationWarning)
16
19
 
17
20
  import mudata
18
21
 
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import random
4
4
  import re
5
+ from importlib.util import find_spec
5
6
  from typing import TYPE_CHECKING, Literal
6
7
 
7
8
  import matplotlib.pyplot as plt
@@ -29,18 +30,6 @@ from sklearn.metrics.pairwise import euclidean_distances
29
30
  class Milo:
30
31
  """Python implementation of Milo."""
31
32
 
32
- def __init__(self):
33
- try:
34
- from rpy2.robjects import conversion, numpy2ri, pandas2ri
35
- from rpy2.robjects.packages import STAP, PackageNotInstalledError, importr
36
- except ModuleNotFoundError:
37
- raise ImportError("milo requires rpy2 to be installed.") from None
38
-
39
- try:
40
- importr("edgeR")
41
- except ImportError as e:
42
- raise ImportError("milo requires a valid R installation with edger installed:\n") from e
43
-
44
33
  def load(
45
34
  self,
46
35
  input: AnnData,
@@ -266,7 +255,7 @@ class Milo:
266
255
  subset_samples: list[str] | None = None,
267
256
  add_intercept: bool = True,
268
257
  feature_key: str | None = "rna",
269
- solver: Literal["edger", "batchglm"] = "edger",
258
+ solver: Literal["edger", "pydeseq2"] = "edger",
270
259
  ):
271
260
  """Performs differential abundance testing on neighbourhoods using QLF test implementation as implemented in edgeR.
272
261
 
@@ -279,7 +268,9 @@ class Milo:
279
268
  subset_samples: subset of samples (obs in `milo_mdata['milo']`) to use for the test.
280
269
  add_intercept: whether to include an intercept in the model. If False, this is equivalent to adding + 0 in the design formula. When model_contrasts is specified, this is set to False by default.
281
270
  feature_key: If input data is MuData, specify key to cell-level AnnData object.
282
- solver: The solver to fit the model to. One of "edger" (requires R, rpy2 and edgeR to be installed) or "batchglm"
271
+ solver: The solver to fit the model to.
272
+ The "edger" solver requires R, rpy2 and edgeR to be installed and is the closest to the R implementation.
273
+ The "pydeseq2" requires pydeseq2 to be installed. It is still very comparable to the "edger" solver but might be a bit slower.
283
274
 
284
275
  Returns:
285
276
  None, modifies `milo_mdata['milo']` in place, adding the results of the DA test to `.var`:
@@ -298,7 +289,6 @@ class Milo:
298
289
  >>> milo.make_nhoods(mdata["rna"])
299
290
  >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident")
300
291
  >>> milo.da_nhoods(mdata, design="~label")
301
-
302
292
  """
303
293
  try:
304
294
  sample_adata = mdata["milo"]
@@ -425,13 +415,65 @@ class Milo:
425
415
  res = pd.DataFrame(res)
426
416
  # The columns of res looks like e.g. table.A, table.B, so remove the prefix
427
417
  res.columns = [col.replace("table.", "") for col in res.columns]
428
- # Save outputs
418
+ elif solver == "pydeseq2":
419
+ if find_spec("pydeseq2") is None:
420
+ raise ImportError("pydeseq2 is required but not installed. Install with: pip install pydeseq2")
421
+
422
+ from pydeseq2.dds import DeseqDataSet
423
+ from pydeseq2.ds import DeseqStats
424
+
425
+ counts_filtered = count_mat[np.ix_(keep_nhoods, keep_smp)]
426
+ design_df_filtered = design_df.iloc[keep_smp].copy()
427
+
428
+ design_df_filtered = design_df_filtered.astype(
429
+ dict.fromkeys(design_df_filtered.select_dtypes(exclude=["number"]).columns, "category")
430
+ )
431
+
432
+ design_clean = design if design.startswith("~") else f"~{design}"
433
+
434
+ dds = DeseqDataSet(
435
+ counts=pd.DataFrame(counts_filtered.T, index=design_df_filtered.index),
436
+ metadata=design_df_filtered,
437
+ design=design_clean,
438
+ refit_cooks=True,
439
+ )
440
+
441
+ dds.deseq2()
442
+
443
+ if model_contrasts is not None and "-" in model_contrasts:
444
+ if "(" in model_contrasts or "+" in model_contrasts.split("-")[1]:
445
+ raise ValueError(
446
+ f"Complex contrasts like '{model_contrasts}' are not supported by pydeseq2. "
447
+ "Use simple pairwise contrasts (e.g., 'GroupA-GroupB') or switch to solver='edger'."
448
+ )
449
+
450
+ parts = model_contrasts.split("-")
451
+ factor_name = design_clean.replace("~", "").split("+")[-1].strip()
452
+ group1 = parts[0].replace(factor_name, "").strip()
453
+ group2 = parts[1].replace(factor_name, "").strip()
454
+ stat_res = DeseqStats(dds, contrast=[factor_name, group1, group2])
455
+ else:
456
+ factor_name = design_clean.replace("~", "").split("+")[-1].strip()
457
+ if not isinstance(design_df_filtered[factor_name], pd.CategoricalDtype):
458
+ design_df_filtered[factor_name] = design_df_filtered[factor_name].astype("category")
459
+ categories = design_df_filtered[factor_name].cat.categories
460
+ stat_res = DeseqStats(dds, contrast=[factor_name, categories[-1], categories[0]])
461
+
462
+ stat_res.summary()
463
+ res = stat_res.results_df
464
+
465
+ res = res.rename(
466
+ columns={"baseMean": "logCPM", "log2FoldChange": "logFC", "pvalue": "PValue", "padj": "FDR"}
467
+ )
468
+
469
+ res = res[["logCPM", "logFC", "PValue", "FDR"]]
470
+
429
471
  res.index = sample_adata.var_names[keep_nhoods] # type: ignore
430
472
  if any(col in sample_adata.var.columns for col in res.columns):
431
473
  sample_adata.var = sample_adata.var.drop(res.columns, axis=1)
432
474
  sample_adata.var = pd.concat([sample_adata.var, res], axis=1)
433
- # Run Graph spatial FDR correction
434
- self._graph_spatial_fdr(sample_adata, neighbors_key=adata.uns["nhood_neighbors_key"])
475
+
476
+ self._graph_spatial_fdr(sample_adata)
435
477
 
436
478
  def annotate_nhoods(
437
479
  self,
@@ -674,6 +716,17 @@ class Milo:
674
716
  self,
675
717
  ):
676
718
  """Set up rpy2 to run edgeR."""
719
+ try:
720
+ from rpy2.robjects import conversion, numpy2ri, pandas2ri
721
+ from rpy2.robjects.packages import STAP, PackageNotInstalledError, importr
722
+ except ModuleNotFoundError:
723
+ raise ImportError("milo requires rpy2 to be installed.") from None
724
+
725
+ try:
726
+ importr("edgeR")
727
+ except ImportError as e:
728
+ raise ImportError("milo requires a valid R installation with edger installed.") from e
729
+
677
730
  from rpy2.robjects.packages import importr
678
731
 
679
732
  edgeR = self._try_import_bioc_library("edgeR")
@@ -685,26 +738,27 @@ class Milo:
685
738
 
686
739
  def _try_import_bioc_library(
687
740
  self,
688
- name: str,
741
+ r_package: str,
689
742
  ):
690
743
  """Import R packages.
691
744
 
692
745
  Args:
693
- name (str): R packages name
746
+ r_package: R packages name
694
747
  """
695
748
  from rpy2.robjects.packages import PackageNotInstalledError, importr
696
749
 
697
750
  try:
698
- _r_lib = importr(name)
751
+ _r_lib = importr(r_package)
699
752
  return _r_lib
700
753
  except PackageNotInstalledError:
701
- logger.error(f"Install Bioconductor library `{name!r}` first as `BiocManager::install({name!r}).`")
754
+ logger.error(
755
+ f"Install Bioconductor library `{r_package!r}` first as `BiocManager::install({r_package!r}).`"
756
+ )
702
757
  raise
703
758
 
704
759
  def _graph_spatial_fdr(
705
760
  self,
706
761
  sample_adata: AnnData,
707
- neighbors_key: str | None = None,
708
762
  ):
709
763
  """FDR correction weighted on inverse of connectivity of neighbourhoods.
710
764
 
@@ -712,7 +766,6 @@ class Milo:
712
766
 
713
767
  Args:
714
768
  sample_adata: Sample-level AnnData.
715
- neighbors_key: The key in `adata.obsp` to use as KNN graph.
716
769
  """
717
770
  # use 1/connectivity as the weighting for the weighted BH adjustment from Cydar
718
771
  w = 1 / sample_adata.var["kth_distance"]
@@ -80,7 +80,7 @@ class PerturbationSpace:
80
80
  group_masks = (
81
81
  [(adata.obs[group_col] == sample) for sample in adata.obs[group_col].unique()]
82
82
  if group_col
83
- else [[True] * adata.n_obs]
83
+ else [np.array([True] * adata.n_obs)]
84
84
  )
85
85
 
86
86
  if layer_key:
@@ -4,7 +4,7 @@ requires = ["hatchling"]
4
4
 
5
5
  [project]
6
6
  name = "pertpy"
7
- version = "0.11.5"
7
+ version = "1.0.0"
8
8
  description = "Perturbation Analysis in the scverse ecosystem."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.14"
@@ -61,7 +61,7 @@ dependencies = [
61
61
  "pubchempy",
62
62
  "pyarrow",
63
63
  "blitzgsea",
64
- "scikit-learn>=1.4", # https://github.com/scverse/pertpy/issues/700
64
+ "scikit-learn>=1.4",
65
65
  "fast-array-utils",
66
66
  "lamin_utils",
67
67
  "arviz",
@@ -1,3 +1,5 @@
1
+ from importlib.util import find_spec
2
+
1
3
  import numpy as np
2
4
  import pandas as pd
3
5
  import pertpy as pt
@@ -5,14 +7,23 @@ import pytest
5
7
  import scanpy as sc
6
8
  from mudata import MuData
7
9
 
8
- try:
9
- from rpy2.robjects.packages import importr
10
10
 
11
- r_dependency = importr("edgeR")
12
- except Exception: # noqa: BLE001
13
- r_dependency = None
11
+ @pytest.fixture(params=["edger", "pydeseq2"])
12
+ def solver(request):
13
+ solver_name = request.param
14
+
15
+ if solver_name == "edger":
16
+ try:
17
+ from rpy2.robjects.packages import importr
18
+
19
+ importr("edgeR")
20
+ except Exception: # noqa: BLE001
21
+ pytest.skip("Required R package 'edgeR' not available")
14
22
 
15
- pytestmark = pytest.mark.skipif(r_dependency is None, reason="Required R package 'edgeR' not available")
23
+ elif solver_name == "pydeseq2" and find_spec("pydeseq2") is None:
24
+ pytest.skip("pydeseq2 not available")
25
+
26
+ return solver_name
16
27
 
17
28
 
18
29
  @pytest.fixture
@@ -136,6 +147,23 @@ def da_nhoods_mdata(adata, milo):
136
147
  return milo_mdata
137
148
 
138
149
 
150
+ def test_da_nhoods_pvalues_both_solvers(da_nhoods_mdata, milo, solver):
151
+ mdata = da_nhoods_mdata.copy()
152
+ milo.da_nhoods(mdata, design="~condition", solver=solver)
153
+ sample_adata = mdata["milo"].copy()
154
+ min_p, max_p = sample_adata.var["PValue"].min(), sample_adata.var["PValue"].max()
155
+ assert (min_p >= 0) & (max_p <= 1), "P-values are not between 0 and 1"
156
+
157
+
158
+ def test_da_nhoods_fdr_both_solvers(da_nhoods_mdata, milo, solver):
159
+ mdata = da_nhoods_mdata.copy()
160
+ milo.da_nhoods(mdata, design="~condition", solver=solver)
161
+ sample_adata = mdata["milo"].copy()
162
+ assert np.all(np.round(sample_adata.var["PValue"], 10) <= np.round(sample_adata.var["SpatialFDR"], 10)), (
163
+ "FDR is higher than uncorrected P-values"
164
+ )
165
+
166
+
139
167
  def test_da_nhoods_missing_samples(adata, milo):
140
168
  with pytest.raises(KeyError):
141
169
  milo.da_nhoods(adata, design="~condition")
@@ -1,3 +1,5 @@
1
+ import warnings
2
+
1
3
  import anndata as ad
2
4
  import pertpy as pt
3
5
  import scanpy as sc
@@ -5,8 +7,10 @@ from scvi.data import synthetic_iid
5
7
 
6
8
 
7
9
  def test_scgen():
8
- adata = synthetic_iid()
9
- adata.obs_names_make_unique()
10
+ with warnings.catch_warnings():
11
+ warnings.filterwarnings("ignore", message="Observation names are not unique")
12
+ adata = synthetic_iid()
13
+ adata.obs_names_make_unique()
10
14
  pt.tl.Scgen.setup_anndata(
11
15
  adata,
12
16
  batch_key="batch",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes