bonesistools 1.2.9__tar.gz → 1.3.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 (196) hide show
  1. {bonesistools-1.2.9 → bonesistools-1.3.0}/PKG-INFO +1 -1
  2. {bonesistools-1.2.9 → bonesistools-1.3.0}/pyproject.toml +1 -1
  3. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/preprocessing/_hvg.py +365 -35
  4. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/preprocessing/test_hvg.py +330 -0
  5. {bonesistools-1.2.9 → bonesistools-1.3.0}/.gitignore +0 -0
  6. {bonesistools-1.2.9 → bonesistools-1.3.0}/LICENSE +0 -0
  7. {bonesistools-1.2.9 → bonesistools-1.3.0}/README.md +0 -0
  8. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/__init__.py +0 -0
  9. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/_compat.py +0 -0
  10. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/_metadata.py +0 -0
  11. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/_typing.py +0 -0
  12. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/_validation.py +0 -0
  13. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/_warnings.py +0 -0
  14. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/__init__.py +0 -0
  15. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_algebra/__init__.py +0 -0
  16. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_algebra/_algebra.py +0 -0
  17. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_algebra/_boolean.py +0 -0
  18. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_algebra/_hypercube.py +0 -0
  19. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_algebra/_kleene.py +0 -0
  20. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_algebra/_parser.py +0 -0
  21. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_algebra/_representation.py +0 -0
  22. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_algebra/_structure.py +0 -0
  23. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_algebra/_typing.py +0 -0
  24. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_network/__init__.py +0 -0
  25. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_network/_network.py +0 -0
  26. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_network/_parser.py +0 -0
  27. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/boolean_network/_typing.py +0 -0
  28. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/influence_graph/__init__.py +0 -0
  29. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/influence_graph/_algorithms.py +0 -0
  30. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/influence_graph/_distances.py +0 -0
  31. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/influence_graph/_influence_graph.py +0 -0
  32. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/influence_graph/_parser.py +0 -0
  33. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/influence_graph/_scoring.py +0 -0
  34. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/influence_graph/_typing.py +0 -0
  35. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/plotting/__init__.py +0 -0
  36. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/plotting/_graphviz.py +0 -0
  37. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/plotting/_styles.py +0 -0
  38. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/boolpy/plotting/_svg.py +0 -0
  39. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/__init__.py +0 -0
  40. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/__init__.py +0 -0
  41. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/_orthologs.py +0 -0
  42. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_anole_lizard_hcop.tsv.gz +0 -0
  43. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_c.elegans_hcop.tsv.gz +0 -0
  44. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_cat_hcop.tsv.gz +0 -0
  45. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_cattle_hcop.tsv.gz +0 -0
  46. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_chicken_hcop.tsv.gz +0 -0
  47. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_chimpanzee_hcop.tsv.gz +0 -0
  48. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_dog_hcop.tsv.gz +0 -0
  49. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_fruitfly_hcop.tsv.gz +0 -0
  50. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_horse_hcop.tsv.gz +0 -0
  51. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_macaque_hcop.tsv.gz +0 -0
  52. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_mouse_hcop.tsv.gz +0 -0
  53. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_opossum_hcop.tsv.gz +0 -0
  54. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_pig_hcop.tsv.gz +0 -0
  55. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_platypus_hcop.tsv.gz +0 -0
  56. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_rat_hcop.tsv.gz +0 -0
  57. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_s.cerevisiae_hcop.tsv.gz +0 -0
  58. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_s.pombe_hcop.tsv.gz +0 -0
  59. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_xenopus_hcop.tsv.gz +0 -0
  60. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/hcop/data/human_zebrafish_hcop.tsv.gz +0 -0
  61. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/ncbi/__init__.py +0 -0
  62. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/ncbi/_genesyn.py +0 -0
  63. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/ncbi/_typing.py +0 -0
  64. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/ncbi/data/gi/escherichia_coli_gene_info.tsv.gz +0 -0
  65. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/ncbi/data/gi/homo_sapiens_gene_info.tsv.gz +0 -0
  66. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/ncbi/data/gi/mus_musculus_gene_info.tsv.gz +0 -0
  67. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/omnipath/__init__.py +0 -0
  68. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/omnipath/_archive.py +0 -0
  69. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/omnipath/_collectri.py +0 -0
  70. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/databases/omnipath/_dorothea.py +0 -0
  71. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/py.typed +0 -0
  72. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/__init__.py +0 -0
  73. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/_dependencies.py +0 -0
  74. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/_metadata.py +0 -0
  75. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/_stats.py +0 -0
  76. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/_typing.py +0 -0
  77. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/_validation.py +0 -0
  78. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/datasets/__init__.py +0 -0
  79. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/datasets/_geo.py +0 -0
  80. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/datasets/_metadata.py +0 -0
  81. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/datasets/_nestorowa.py +0 -0
  82. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/datasets/_pbmc3k.py +0 -0
  83. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/datasets/_registry.py +0 -0
  84. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/datasets/datasets.json +0 -0
  85. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/plotting/__init__.py +0 -0
  86. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/plotting/_barplot.py +0 -0
  87. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/plotting/_colors.py +0 -0
  88. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/plotting/_density.py +0 -0
  89. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/plotting/_distribution.py +0 -0
  90. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/plotting/_figure.py +0 -0
  91. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/plotting/_graph.py +0 -0
  92. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/plotting/_scatterplot.py +0 -0
  93. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/plotting/_typing.py +0 -0
  94. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/plotting/_utils.py +0 -0
  95. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/preprocessing/__init__.py +0 -0
  96. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/preprocessing/_classification.py +0 -0
  97. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/preprocessing/_duplicates.py +0 -0
  98. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/preprocessing/_filter.py +0 -0
  99. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/preprocessing/_genename.py +0 -0
  100. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/preprocessing/_qc.py +0 -0
  101. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/preprocessing/_simple.py +0 -0
  102. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/preprocessing/_transfer.py +0 -0
  103. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/preprocessing/_transform.py +0 -0
  104. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/__init__.py +0 -0
  105. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_binarize.py +0 -0
  106. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_classification.py +0 -0
  107. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_clustering.py +0 -0
  108. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_conversion.py +0 -0
  109. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_embedding.py +0 -0
  110. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_graph.py +0 -0
  111. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_markers.py +0 -0
  112. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_maths.py +0 -0
  113. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_neighbors.py +0 -0
  114. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_regress.py +0 -0
  115. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_stats.py +0 -0
  116. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_utils.py +0 -0
  117. {bonesistools-1.2.9 → bonesistools-1.3.0}/src/bonesistools/sctools/tools/_write.py +0 -0
  118. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/.placeholder +0 -0
  119. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/__init__.py +0 -0
  120. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/LICENSE.txt +0 -0
  121. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/README.md +0 -0
  122. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/__init__.py +0 -0
  123. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/_workflow.py +0 -0
  124. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/conftest.py +0 -0
  125. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/expected/hvg_binning.npz +0 -0
  126. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/expected/hvg_loess.npz +0 -0
  127. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/expected/neighbors.npz +0 -0
  128. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/expected/pca.npz +0 -0
  129. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/expected/qc.npz +0 -0
  130. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/expected/spectral.npz +0 -0
  131. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/expected/tsne.npz +0 -0
  132. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/expected/umap.npz +0 -0
  133. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/generate_expected.py +0 -0
  134. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/pbmc3k.h5ad +0 -0
  135. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/test_golden_workflow.py +0 -0
  136. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/golden/test_pbmc3k.py +0 -0
  137. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/__init__.py +0 -0
  138. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/conftest.py +0 -0
  139. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_aggregated_influence_graph.py +0 -0
  140. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_boolean_algebra.py +0 -0
  141. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_boolean_network.py +0 -0
  142. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_boolean_network_ensemble.py +0 -0
  143. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_hypercube.py +0 -0
  144. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_hypercube_collection.py +0 -0
  145. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_influence_graph.py +0 -0
  146. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_influence_graph_distances.py +0 -0
  147. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_influence_graph_parser.py +0 -0
  148. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_influence_graph_scoring.py +0 -0
  149. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_partial_boolean.py +0 -0
  150. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/bpy/test_plotting_styles.py +0 -0
  151. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/dbs/test_hcop.py +0 -0
  152. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/dbs/test_ncbi.py +0 -0
  153. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/dbs/test_omnipath.py +0 -0
  154. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/__init__.py +0 -0
  155. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/conftest.py +0 -0
  156. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/datasets/test_geo.py +0 -0
  157. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/datasets/test_nestorowa.py +0 -0
  158. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/datasets/test_registry.py +0 -0
  159. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/plotting/test_barplot.py +0 -0
  160. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/plotting/test_colors.py +0 -0
  161. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/plotting/test_density.py +0 -0
  162. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/plotting/test_distribution.py +0 -0
  163. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/plotting/test_figure.py +0 -0
  164. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/plotting/test_graph.py +0 -0
  165. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/plotting/test_plotting_utils.py +0 -0
  166. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/plotting/test_scatterplot.py +0 -0
  167. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/preprocessing/test_classification.py +0 -0
  168. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/preprocessing/test_duplicates.py +0 -0
  169. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/preprocessing/test_genename.py +0 -0
  170. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/preprocessing/test_qc.py +0 -0
  171. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/preprocessing/test_simple.py +0 -0
  172. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/preprocessing/test_transfer_obs.py +0 -0
  173. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/preprocessing/test_transform.py +0 -0
  174. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/test_typing.py +0 -0
  175. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_binarize.py +0 -0
  176. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_clustering.py +0 -0
  177. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_conversion.py +0 -0
  178. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_embedding.py +0 -0
  179. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_knnsc.py +0 -0
  180. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_markers.py +0 -0
  181. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_maths.py +0 -0
  182. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_neighbors.py +0 -0
  183. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_paga.py +0 -0
  184. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_regress.py +0 -0
  185. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_stats.py +0 -0
  186. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_utils.py +0 -0
  187. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/tools/test_write.py +0 -0
  188. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/sct/toy_data.py +0 -0
  189. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/test_import.py +0 -0
  190. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/regression/test_validation.py +0 -0
  191. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/reproducibility/__init__.py +0 -0
  192. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/reproducibility/dorothea_current_mouse_A.sha256 +0 -0
  193. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/reproducibility/dorothea_legacy_mouse.sha256 +0 -0
  194. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/reproducibility/test_reproducibility_omnipath.py +0 -0
  195. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/reproducibility/test_reproducibility_stats.py +0 -0
  196. {bonesistools-1.2.9 → bonesistools-1.3.0}/tests/reproducibility/test_reproducibility_workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bonesistools
3
- Version: 1.2.9
3
+ Version: 1.3.0
4
4
  Summary: Bioinformatics toolkit for upstream and downstream analyses around the BoNesis framework
5
5
  Project-URL: Repository, https://github.com/bnediction/bonesistools
6
6
  Author: Théo Roncalli
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
  [project]
6
6
  name = "bonesistools"
7
7
  description = "Bioinformatics toolkit for upstream and downstream analyses around the BoNesis framework"
8
- version = "1.2.9"
8
+ version = "1.3.0"
9
9
  license = "CECILL-2.1"
10
10
  credits = ["BNeDiction", "PEPR Santé Numérique 2030"]
11
11
  authors = [
@@ -26,11 +26,18 @@ from ..tools._utils import get_expression
26
26
 
27
27
  HVGMethod = Literal["loess", "binning"]
28
28
  HVG_METHODS: Tuple[HVGMethod, ...] = ("loess", "binning")
29
+ HVG_BATCH_WEIGHTINGS: Tuple[Literal["equal", "cell_count"], ...] = (
30
+ "equal",
31
+ "cell_count",
32
+ )
33
+ HVG_BATCH_SELECTIONS: Tuple[Literal["consensus", "rank"], ...] = (
34
+ "consensus",
35
+ "rank",
36
+ )
29
37
  _DEFAULT_SCORE_CUTOFFS = {
30
38
  "loess": (2.0, np.inf),
31
39
  "binning": (0.5, np.inf),
32
40
  }
33
- _DEFAULT_MEAN_CUTOFF = (0.0125, 3.0)
34
41
  _NORMAL_CONSISTENCY_MAD_SCALE = 0.6744897501960817
35
42
 
36
43
 
@@ -41,6 +48,15 @@ class _HVGScore:
41
48
  scores: np.ndarray
42
49
 
43
50
 
51
+ @dataclass(frozen=True)
52
+ class _BatchHVGScore:
53
+
54
+ means: np.ndarray
55
+ scores: np.ndarray
56
+ nbatches: np.ndarray
57
+ rank_summary: np.ndarray
58
+
59
+
44
60
  @dataclass(frozen=True)
45
61
  class _HVGSelection:
46
62
 
@@ -50,6 +66,13 @@ class _HVGSelection:
50
66
  mean_cutoff: Optional[Tuple[float, float]]
51
67
 
52
68
 
69
+ @dataclass(frozen=True)
70
+ class _BatchGroups:
71
+
72
+ masks: Tuple[np.ndarray, ...]
73
+ sizes: np.ndarray
74
+
75
+
53
76
  @dataclass(frozen=True)
54
77
  class _ClippedMoments:
55
78
 
@@ -65,12 +88,15 @@ def hvg(
65
88
  adata: AnnData,
66
89
  *,
67
90
  expression: Optional[str] = None,
91
+ method: Literal["loess", "binning"] = "loess",
68
92
  n_features: Optional[int] = 2000,
69
- method: HVGMethod = "loess",
93
+ mean: Tuple[float, float] = (0.0125, 3.0),
94
+ score: Union[Literal["auto"], Tuple[float, float]] = "auto",
70
95
  span: float = 0.3,
71
96
  n_bins: int = 20,
72
- score: Union[Literal["auto"], Tuple[float, float]] = "auto",
73
- mean: Tuple[float, float] = _DEFAULT_MEAN_CUTOFF,
97
+ batch_key: Optional[str] = None,
98
+ batch_selection: Literal["consensus", "rank"] = "consensus",
99
+ batch_weighting: Literal["equal", "cell_count"] = "equal",
74
100
  key_added: str = "highly_variable",
75
101
  copy: Literal[False] = False,
76
102
  ) -> None: ...
@@ -81,12 +107,15 @@ def hvg(
81
107
  adata: AnnData,
82
108
  *,
83
109
  expression: Optional[str] = None,
110
+ method: Literal["loess", "binning"] = "loess",
84
111
  n_features: Optional[int] = 2000,
85
- method: HVGMethod = "loess",
112
+ mean: Tuple[float, float] = (0.0125, 3.0),
113
+ score: Union[Literal["auto"], Tuple[float, float]] = "auto",
86
114
  span: float = 0.3,
87
115
  n_bins: int = 20,
88
- score: Union[Literal["auto"], Tuple[float, float]] = "auto",
89
- mean: Tuple[float, float] = _DEFAULT_MEAN_CUTOFF,
116
+ batch_key: Optional[str] = None,
117
+ batch_selection: Literal["consensus", "rank"] = "consensus",
118
+ batch_weighting: Literal["equal", "cell_count"] = "equal",
90
119
  key_added: str = "highly_variable",
91
120
  copy: Literal[True],
92
121
  ) -> AnnData: ...
@@ -97,12 +126,15 @@ def hvg(
97
126
  adata: AnnData,
98
127
  *,
99
128
  expression: Optional[str] = None,
129
+ method: Literal["loess", "binning"] = "loess",
100
130
  n_features: Optional[int] = 2000,
101
- method: HVGMethod = "loess",
131
+ mean: Tuple[float, float] = (0.0125, 3.0),
132
+ score: Union[Literal["auto"], Tuple[float, float]] = "auto",
102
133
  span: float = 0.3,
103
134
  n_bins: int = 20,
104
- score: Union[Literal["auto"], Tuple[float, float]] = "auto",
105
- mean: Tuple[float, float] = _DEFAULT_MEAN_CUTOFF,
135
+ batch_key: Optional[str] = None,
136
+ batch_selection: Literal["consensus", "rank"] = "consensus",
137
+ batch_weighting: Literal["equal", "cell_count"] = "equal",
106
138
  key_added: str = "highly_variable",
107
139
  copy: bool = False,
108
140
  ) -> Optional[AnnData]: ...
@@ -113,12 +145,15 @@ def hvg(
113
145
  adata: AnnData,
114
146
  *,
115
147
  expression: Optional[str] = None,
148
+ method: Literal["loess", "binning"] = "loess",
116
149
  n_features: Optional[int] = 2000,
117
- method: HVGMethod = "loess",
150
+ mean: Tuple[float, float] = (0.0125, 3.0),
151
+ score: Union[Literal["auto"], Tuple[float, float]] = "auto",
118
152
  span: float = 0.3,
119
153
  n_bins: int = 20,
120
- score: Union[Literal["auto"], Tuple[float, float]] = "auto",
121
- mean: Tuple[float, float] = _DEFAULT_MEAN_CUTOFF,
154
+ batch_key: Optional[str] = None,
155
+ batch_selection: Literal["consensus", "rank"] = "consensus",
156
+ batch_weighting: Literal["equal", "cell_count"] = "equal",
122
157
  key_added: str = "highly_variable",
123
158
  copy: bool = False,
124
159
  ) -> Optional[AnnData]:
@@ -134,9 +169,6 @@ def hvg(
134
169
  `adata.X`; otherwise, use `adata.layers[expression]`. Use raw counts
135
170
  for `method='loess'` and log-normalized expression values for
136
171
  `method='binning'`.
137
- n_features: int or None (default: 2000)
138
- Number of highly variable features to select. If None, features are
139
- selected using `score` and `mean` cutoffs instead.
140
172
  method: {'loess', 'binning'} (default: 'loess')
141
173
  Method used to score highly variable features.
142
174
 
@@ -151,18 +183,9 @@ def hvg(
151
183
  grouped by mean expression, dispersions are normalized within
152
184
  each bin using the median and median absolute deviation, and
153
185
  features are ranked by normalized dispersion scores [2, 3].
154
- span: float (default: 0.3)
155
- LOESS smoothing span. Must be greater than 0 and smaller than or equal
156
- to 1. Used by `method='loess'`.
157
- n_bins: int (default: 20)
158
- Number of mean-expression bins used by `method='binning'`.
159
- score: {'auto'} or tuple of float (default: 'auto')
160
- Score interval used when `n_features=None`. Features are selected when
161
- `score[0] < feature_score < score[1]`. If 'auto', use
162
- method-specific defaults: `(2.0, np.inf)` for `method='loess'` and
163
- `(0.5, np.inf)` for `method='binning'`. For `method='loess'`, scores
164
- are normalized variance scores. For `method='binning'`, scores are
165
- normalized dispersion scores.
186
+ n_features: int or None (default: 2000)
187
+ Number of highly variable features to select. If None, features are
188
+ selected using `score` and `mean` cutoffs instead.
166
189
  mean: tuple of float (default: (0.0125, 3.0))
167
190
  Mean-expression interval used when `n_features=None`. Features are
168
191
  selected when `mean[0] < feature_mean < mean[1]`. For
@@ -170,6 +193,34 @@ def hvg(
170
193
  library-size-normalized counts with target sum 1e4. For
171
194
  `method='binning'`, the interval is applied to the mean of the
172
195
  provided expression matrix.
196
+ score: {'auto'} or tuple of float (default: 'auto')
197
+ Score interval used when `n_features=None`. Features are selected when
198
+ `score[0] < feature_score < score[1]`. If 'auto', use
199
+ method-specific defaults: `(2.0, np.inf)` for `method='loess'` and
200
+ `(0.5, np.inf)` for `method='binning'`. For `method='loess'`, scores
201
+ are normalized variance scores. For `method='binning'`, scores are
202
+ normalized dispersion scores.
203
+ span: float (default: 0.3)
204
+ LOESS smoothing span. Must be greater than 0 and smaller than or equal
205
+ to 1. Used by `method='loess'`.
206
+ n_bins: int (default: 20)
207
+ Number of mean-expression bins used by `method='binning'`.
208
+ batch_key: str, optional
209
+ Column in `adata.obs` defining batches. If provided, features are
210
+ scored independently in each batch and scores are averaged across
211
+ batches.
212
+ batch_selection: {'consensus', 'rank'} (default: 'consensus')
213
+ Batch-aware top-feature selection strategy used when both `batch_key`
214
+ and `n_features` are provided. If 'consensus', prioritize features
215
+ selected in the largest number of batches. If 'rank', prioritize
216
+ features with the best summarized within-batch rank.
217
+ batch_weighting: {'equal', 'cell_count'} (default: 'equal')
218
+ Batch score aggregation strategy. If 'equal', each batch has the same
219
+ weight. If 'cell_count', batches are weighted by their number of
220
+ observations. When `n_features` is provided, features selected in more
221
+ batches are prioritized before applying method-specific tie-breaks. If
222
+ `n_features` is None, cutoffs are applied to the aggregated scores and
223
+ means. Ignored when `batch_key` is None.
173
224
  key_added: str (default: 'highly_variable')
174
225
  Column in `adata.var` where the selected feature mask is stored.
175
226
  copy: bool (default: False)
@@ -208,6 +259,23 @@ def hvg(
208
259
  else _as_positive_integer(n_features, "n_features")
209
260
  )
210
261
  method = cast(HVGMethod, _as_literal(method, choices=HVG_METHODS, name="method"))
262
+ batch_key = None if batch_key is None else _as_string(batch_key, "batch_key")
263
+ batch_weighting = cast(
264
+ Literal["equal", "cell_count"],
265
+ _as_literal(
266
+ batch_weighting,
267
+ choices=HVG_BATCH_WEIGHTINGS,
268
+ name="batch_weighting",
269
+ ),
270
+ )
271
+ batch_selection = cast(
272
+ Literal["consensus", "rank"],
273
+ _as_literal(
274
+ batch_selection,
275
+ choices=HVG_BATCH_SELECTIONS,
276
+ name="batch_selection",
277
+ ),
278
+ )
211
279
  span = _as_positive_number(span, "span")
212
280
  if span > 1:
213
281
  raise ValueError(
@@ -224,7 +292,7 @@ def hvg(
224
292
  n_features is not None
225
293
  and (
226
294
  score_cutoff is not None
227
- or mean_cutoff != _DEFAULT_MEAN_CUTOFF
295
+ or mean_cutoff != (0.0125, 3.0)
228
296
  )
229
297
  ):
230
298
  warnings.warn(
@@ -244,18 +312,41 @@ def hvg(
244
312
  if len(expression_mtx.shape) != 2:
245
313
  raise ValueError("invalid expression matrix: expected a two-dimensional matrix")
246
314
 
247
- scoring = _score_hvg_features(
248
- expression_mtx,
249
- method=method,
250
- span=span,
251
- n_bins=n_bins,
315
+ batch_groups = _resolve_batch_groups(adata, batch_key)
316
+ scoring = (
317
+ _score_hvg_features(
318
+ expression_mtx,
319
+ method=method,
320
+ span=span,
321
+ n_bins=n_bins,
322
+ )
323
+ if batch_groups is None
324
+ else _score_hvg_features_by_batch(
325
+ expression_mtx,
326
+ batch_groups=batch_groups,
327
+ batch_weighting=batch_weighting,
328
+ n_features=n_features,
329
+ method=method,
330
+ span=span,
331
+ n_bins=n_bins,
332
+ )
333
+ )
334
+ ordered_indices = (
335
+ _order_by_score(scoring.scores)
336
+ if batch_groups is None or n_features is None
337
+ else _order_batch_hvg_features(
338
+ cast(_BatchHVGScore, scoring),
339
+ method=method,
340
+ batch_selection=batch_selection,
341
+ )
252
342
  )
253
- ordered_indices = _order_by_score(scoring.scores)
254
343
  selection_means = (
255
344
  _selection_means(
256
345
  expression_mtx,
257
346
  method=method,
258
347
  scoring_means=scoring.means,
348
+ batch_groups=batch_groups,
349
+ batch_weighting=batch_weighting,
259
350
  )
260
351
  if n_features is None
261
352
  else scoring.means
@@ -285,6 +376,9 @@ def hvg(
285
376
  n_bins=n_bins,
286
377
  n_features=n_features,
287
378
  selection=selection,
379
+ batch_key=batch_key,
380
+ batch_weighting=batch_weighting,
381
+ batch_selection=batch_selection,
288
382
  ),
289
383
  }
290
384
 
@@ -313,6 +407,62 @@ def _score_hvg_features(
313
407
  raise ValueError(f"unsupported HVG method: {method!r}")
314
408
 
315
409
 
410
+ def _score_hvg_features_by_batch(
411
+ matrix: Matrix,
412
+ *,
413
+ batch_groups: _BatchGroups,
414
+ batch_weighting: Literal["equal", "cell_count"],
415
+ n_features: Optional[int],
416
+ method: HVGMethod,
417
+ span: float,
418
+ n_bins: int,
419
+ ) -> _BatchHVGScore:
420
+
421
+ batch_means = []
422
+ batch_scores = []
423
+ batch_ranks = []
424
+ nbatches = np.zeros(matrix.shape[1], dtype=int)
425
+ for mask in batch_groups.masks:
426
+ batch_matrix = _subset_obs_matrix(matrix, mask)
427
+ if int(mask.sum()) < 2:
428
+ batch_means.append(_compute_mean(batch_matrix))
429
+ batch_scores.append(np.full(matrix.shape[1], np.nan, dtype=np.float64))
430
+ batch_ranks.append(np.full(matrix.shape[1], np.nan, dtype=np.float64))
431
+ continue
432
+
433
+ scoring = _score_hvg_features(
434
+ batch_matrix,
435
+ method=method,
436
+ span=span,
437
+ n_bins=n_bins,
438
+ )
439
+ batch_means.append(scoring.means)
440
+ batch_scores.append(scoring.scores)
441
+ batch_rank = np.full(matrix.shape[1], np.nan, dtype=np.float64)
442
+ if n_features is not None:
443
+ selected_indices = _order_by_score(scoring.scores)[:n_features]
444
+ nbatches[selected_indices] += 1
445
+ batch_rank[selected_indices] = np.arange(
446
+ 1,
447
+ selected_indices.size + 1,
448
+ dtype=np.float64,
449
+ )
450
+ batch_ranks.append(batch_rank)
451
+
452
+ weights = _batch_weights(batch_groups, batch_weighting=batch_weighting)
453
+
454
+ return _BatchHVGScore(
455
+ means=_weighted_nanmean(np.vstack(batch_means), weights),
456
+ scores=_weighted_nanmean(np.vstack(batch_scores), weights),
457
+ nbatches=nbatches,
458
+ rank_summary=_batch_rank_summary(
459
+ np.vstack(batch_ranks),
460
+ weights,
461
+ batch_weighting=batch_weighting,
462
+ ),
463
+ )
464
+
465
+
316
466
  def _hvg_params(
317
467
  *,
318
468
  method: HVGMethod,
@@ -320,12 +470,18 @@ def _hvg_params(
320
470
  n_bins: int,
321
471
  n_features: Optional[int],
322
472
  selection: _HVGSelection,
473
+ batch_key: Optional[str],
474
+ batch_weighting: Literal["equal", "cell_count"],
475
+ batch_selection: Literal["consensus", "rank"],
323
476
  ) -> dict:
324
477
 
325
478
  params = {
326
479
  "selection": "top_n" if n_features is not None else "cutoff",
327
480
  "score_cutoff": selection.score_cutoff,
328
481
  "mean_cutoff": selection.mean_cutoff,
482
+ "batch_key": batch_key,
483
+ "batch_weighting": batch_weighting,
484
+ "batch_selection": batch_selection,
329
485
  }
330
486
  if method == "loess":
331
487
  return {
@@ -407,9 +563,17 @@ def _selection_means(
407
563
  *,
408
564
  method: HVGMethod,
409
565
  scoring_means: np.ndarray,
566
+ batch_groups: Optional[_BatchGroups],
567
+ batch_weighting: Literal["equal", "cell_count"],
410
568
  ) -> np.ndarray:
411
569
 
412
570
  if method == "loess":
571
+ if batch_groups is not None:
572
+ return _compute_log_normalized_mean_by_batch(
573
+ matrix,
574
+ batch_groups=batch_groups,
575
+ batch_weighting=batch_weighting,
576
+ )
413
577
  return _compute_log_normalized_mean(matrix)
414
578
  return scoring_means
415
579
 
@@ -463,6 +627,22 @@ def _compute_log_normalized_mean(
463
627
  return np.asarray(normalized.mean(axis=0, dtype=np.float64)).ravel()
464
628
 
465
629
 
630
+ def _compute_log_normalized_mean_by_batch(
631
+ matrix: Matrix,
632
+ *,
633
+ batch_groups: _BatchGroups,
634
+ batch_weighting: Literal["equal", "cell_count"],
635
+ ) -> np.ndarray:
636
+
637
+ batch_means = [
638
+ _compute_log_normalized_mean(_subset_obs_matrix(matrix, mask))
639
+ for mask in batch_groups.masks
640
+ ]
641
+ weights = _batch_weights(batch_groups, batch_weighting=batch_weighting)
642
+
643
+ return _weighted_nanmean(np.vstack(batch_means), weights)
644
+
645
+
466
646
  def _compute_variance(
467
647
  matrix: Matrix,
468
648
  mean: Optional[np.ndarray] = None,
@@ -673,6 +853,156 @@ def _order_by_score(scores: np.ndarray) -> np.ndarray:
673
853
  return eligible[np.argsort(-scores[eligible], kind="mergesort")]
674
854
 
675
855
 
856
+ def _order_batch_hvg_features(
857
+ scoring: _BatchHVGScore,
858
+ *,
859
+ method: HVGMethod,
860
+ batch_selection: Literal["consensus", "rank"],
861
+ ) -> np.ndarray:
862
+
863
+ eligible = np.flatnonzero(np.isfinite(scoring.scores))
864
+ ranks = np.where(
865
+ np.isnan(scoring.rank_summary),
866
+ np.inf,
867
+ scoring.rank_summary,
868
+ )
869
+ if batch_selection == "rank":
870
+ return eligible[
871
+ np.lexsort(
872
+ (
873
+ -scoring.scores[eligible],
874
+ -scoring.nbatches[eligible],
875
+ ranks[eligible],
876
+ )
877
+ )
878
+ ]
879
+
880
+ if batch_selection != "consensus":
881
+ raise ValueError(f"unsupported batch selection: {batch_selection!r}")
882
+
883
+ if method == "loess":
884
+ return eligible[
885
+ np.lexsort(
886
+ (
887
+ -scoring.scores[eligible],
888
+ ranks[eligible],
889
+ -scoring.nbatches[eligible],
890
+ )
891
+ )
892
+ ]
893
+
894
+ if method == "binning":
895
+ return eligible[
896
+ np.lexsort(
897
+ (
898
+ -scoring.scores[eligible],
899
+ -scoring.nbatches[eligible],
900
+ )
901
+ )
902
+ ]
903
+
904
+ raise ValueError(f"unsupported HVG method: {method!r}")
905
+
906
+
907
+ def _resolve_batch_groups(
908
+ adata: AnnData,
909
+ batch_key: Optional[str],
910
+ ) -> Optional[_BatchGroups]:
911
+
912
+ if batch_key is None:
913
+ return None
914
+ if batch_key not in adata.obs:
915
+ raise KeyError(f"column {batch_key!r} not found in adata.obs")
916
+
917
+ labels = cast(Any, adata.obs[batch_key])
918
+ valid_mask = ~np.asarray(labels.isna(), dtype=bool)
919
+ values = list(labels[valid_mask].unique())
920
+ masks = tuple(
921
+ np.asarray((labels == value) & valid_mask, dtype=bool)
922
+ for value in values
923
+ )
924
+ masks = tuple(mask for mask in masks if np.any(mask))
925
+ if not masks:
926
+ raise ValueError(
927
+ f"invalid observation batches in adata.obs[{batch_key!r}]: "
928
+ "expected at least one non-missing batch"
929
+ )
930
+
931
+ return _BatchGroups(
932
+ masks=masks,
933
+ sizes=np.asarray([mask.sum() for mask in masks], dtype=np.float64),
934
+ )
935
+
936
+
937
+ def _subset_obs_matrix(matrix: Matrix, obs_mask: np.ndarray) -> Matrix:
938
+
939
+ return cast(Matrix, cast(Any, matrix)[obs_mask, :])
940
+
941
+
942
+ def _batch_weights(
943
+ batch_groups: _BatchGroups,
944
+ *,
945
+ batch_weighting: Literal["equal", "cell_count"],
946
+ ) -> np.ndarray:
947
+
948
+ if batch_weighting == "equal":
949
+ return np.ones(batch_groups.sizes.shape[0], dtype=np.float64)
950
+ if batch_weighting == "cell_count":
951
+ return batch_groups.sizes.astype(np.float64, copy=False)
952
+
953
+ raise ValueError(f"unsupported batch weighting: {batch_weighting!r}")
954
+
955
+
956
+ def _weighted_nanmean(values: np.ndarray, weights: np.ndarray) -> np.ndarray:
957
+
958
+ valid = ~np.isnan(values)
959
+ weighted_values = np.where(valid, values, 0.0) * weights.reshape(-1, 1)
960
+ denominators = np.sum(valid * weights.reshape(-1, 1), axis=0)
961
+
962
+ return np.divide(
963
+ weighted_values.sum(axis=0),
964
+ denominators,
965
+ out=np.full(values.shape[1], np.nan, dtype=np.float64),
966
+ where=denominators != 0,
967
+ )
968
+
969
+
970
+ def _batch_rank_summary(
971
+ ranks: np.ndarray,
972
+ weights: np.ndarray,
973
+ *,
974
+ batch_weighting: Literal["equal", "cell_count"],
975
+ ) -> np.ndarray:
976
+
977
+ if batch_weighting == "equal":
978
+ return cast(
979
+ np.ndarray,
980
+ np.ma.median(np.ma.masked_invalid(ranks), axis=0).filled(np.nan),
981
+ )
982
+
983
+ return _weighted_nanmedian(ranks, weights)
984
+
985
+
986
+ def _weighted_nanmedian(values: np.ndarray, weights: np.ndarray) -> np.ndarray:
987
+
988
+ medians = np.full(values.shape[1], np.nan, dtype=np.float64)
989
+ for index in range(values.shape[1]):
990
+ valid = ~np.isnan(values[:, index])
991
+ if not np.any(valid):
992
+ continue
993
+
994
+ valid_values = values[valid, index]
995
+ valid_weights = weights[valid]
996
+ order = np.argsort(valid_values, kind="mergesort")
997
+ sorted_values = valid_values[order]
998
+ cumulative_weights = np.cumsum(valid_weights[order])
999
+ cutoff = 0.5 * cumulative_weights[-1]
1000
+ median_index = np.searchsorted(cumulative_weights, cutoff, side="left")
1001
+ medians[index] = sorted_values[median_index]
1002
+
1003
+ return medians
1004
+
1005
+
676
1006
  def _as_cutoff_interval(
677
1007
  value: Tuple[float, float],
678
1008
  name: str,