exprmat 0.1.49__tar.gz → 0.1.50__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 (244) hide show
  1. {exprmat-0.1.49 → exprmat-0.1.50}/PKG-INFO +5 -5
  2. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/__init__.py +29 -1
  3. exprmat-0.1.50/exprmat/data/icnet.py +74 -0
  4. exprmat-0.1.50/exprmat/lr/icnet/__init__.py +100 -0
  5. exprmat-0.1.50/exprmat/lr/icnet/construction.py +270 -0
  6. exprmat-0.1.50/exprmat/lr/icnet/importance.py +159 -0
  7. exprmat-0.1.50/exprmat/lr/icnet/ligand.py +333 -0
  8. exprmat-0.1.50/exprmat/lr/icnet/metrics.py +90 -0
  9. exprmat-0.1.50/exprmat/lr/icnet/pagerank.py +124 -0
  10. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/expression.py +4 -4
  11. exprmat-0.1.50/exprmat/plotting/icnet.py +28 -0
  12. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/utils.py +2 -2
  13. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/velocity.py +2 -1
  14. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reader/experiment.py +16 -30
  15. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reader/static.py +20 -2
  16. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/utils.py +4 -0
  17. exprmat-0.1.50/license +674 -0
  18. {exprmat-0.1.49 → exprmat-0.1.50}/pyproject.toml +2 -2
  19. {exprmat-0.1.49 → exprmat-0.1.50}/readme.md +3 -3
  20. exprmat-0.1.49/license +0 -0
  21. {exprmat-0.1.49 → exprmat-0.1.50}/Cargo.lock +0 -0
  22. {exprmat-0.1.49 → exprmat-0.1.50}/Cargo.toml +0 -0
  23. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/ansi.py +0 -0
  24. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/__init__.py +0 -0
  25. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/cnmf.py +0 -0
  26. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/dbscan.py +0 -0
  27. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/gating.py +0 -0
  28. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/kmeans.py +0 -0
  29. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/leiden.py +0 -0
  30. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/nmf.py +0 -0
  31. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/rogue.py +0 -0
  32. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/sc3.py +0 -0
  33. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/seriation.py +0 -0
  34. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/spectral.py +0 -0
  35. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/clustering/utils.py +0 -0
  36. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/cnv/__init__.py +0 -0
  37. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/cnv/cnvscore.py +0 -0
  38. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/cnv/infercnv.py +0 -0
  39. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/configuration.py +0 -0
  40. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/__init__.py +0 -0
  41. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/cistarget.py +0 -0
  42. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/cre.py +0 -0
  43. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/finders.py +0 -0
  44. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/geneset.py +0 -0
  45. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/io.py +0 -0
  46. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/lr.py +0 -0
  47. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/orthologs.py +0 -0
  48. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/presets.py +0 -0
  49. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/signature.py +0 -0
  50. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/data/tf.py +0 -0
  51. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/deconv/__init__.py +0 -0
  52. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/deconv/deconv.py +0 -0
  53. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/deconv/simulation.py +0 -0
  54. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/descriptive/__init__.py +0 -0
  55. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/descriptive/aggregate.py +0 -0
  56. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/descriptive/atac.py +0 -0
  57. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/descriptive/aucell.py +0 -0
  58. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/descriptive/de.py +0 -0
  59. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/descriptive/gse.py +0 -0
  60. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/descriptive/kde.py +0 -0
  61. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/descriptive/recovery.py +0 -0
  62. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/descriptive/summary.py +0 -0
  63. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/descriptive/tcr.py +0 -0
  64. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/deseq/dataset.py +0 -0
  65. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/deseq/gridsearch.py +0 -0
  66. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/deseq/inference.py +0 -0
  67. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/deseq/preprocessing.py +0 -0
  68. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/deseq/stats.py +0 -0
  69. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/deseq/utils.py +0 -0
  70. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/__init__.py +0 -0
  71. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/generank.py +0 -0
  72. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/linreg.py +0 -0
  73. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/moments.py +0 -0
  74. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/optimization.py +0 -0
  75. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/parallel.py +0 -0
  76. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/preprocess.py +0 -0
  77. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/pseudotime.py +0 -0
  78. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/transition.py +0 -0
  79. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/utils.py +0 -0
  80. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/dynamics/velocity.py +0 -0
  81. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/grn/__init__.py +0 -0
  82. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/grn/infergrn.py +0 -0
  83. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/grn/modules.py +0 -0
  84. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/grn/prune.py +0 -0
  85. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/grn/regressors.py +0 -0
  86. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/grn/utils.py +0 -0
  87. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/image/__init__.py +0 -0
  88. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/image/align.py +0 -0
  89. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/__init__.py +0 -0
  90. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/aggregate.py +0 -0
  91. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/method.py +0 -0
  92. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/methods/__init__.py +0 -0
  93. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/methods/cellchat.py +0 -0
  94. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/methods/cellphonedb.py +0 -0
  95. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/methods/connectome.py +0 -0
  96. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/methods/geomean.py +0 -0
  97. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/methods/logfc.py +0 -0
  98. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/methods/natmi.py +0 -0
  99. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/methods/rank_aggregate.py +0 -0
  100. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/methods/scseqcomm.py +0 -0
  101. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/methods/singlecellsignalr.py +0 -0
  102. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/pipeline.py +0 -0
  103. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/preprocess.py +0 -0
  104. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/resources.py +0 -0
  105. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/lr/utils.py +0 -0
  106. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/metacell/__init__.py +0 -0
  107. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/metacell/engine.py +0 -0
  108. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/metacell/model.py +0 -0
  109. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/metacell/utils.py +0 -0
  110. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/__init__.py +0 -0
  111. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/callpeak.py +0 -0
  112. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/common.py +0 -0
  113. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/coverage.py +0 -0
  114. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/footprint.py +0 -0
  115. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/idr/__init__.py +0 -0
  116. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/idr/constants.py +0 -0
  117. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/idr/idr.py +0 -0
  118. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/idr/invcdf.pyx +0 -0
  119. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/idr/optimization.py +0 -0
  120. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/idr/utils.py +0 -0
  121. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/linkage.py +0 -0
  122. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/motif.py +0 -0
  123. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/peaks/sequence.py +0 -0
  124. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/__init__.py +0 -0
  125. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/atac.py +0 -0
  126. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/cnmf.py +0 -0
  127. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/cnv.py +0 -0
  128. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/A.pk +0 -0
  129. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/B.pk +0 -0
  130. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/C.pk +0 -0
  131. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/D.pk +0 -0
  132. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/E.pk +0 -0
  133. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/F.pk +0 -0
  134. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/G.pk +0 -0
  135. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/H.pk +0 -0
  136. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/I.pk +0 -0
  137. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/J.pk +0 -0
  138. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/K.pk +0 -0
  139. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/L.pk +0 -0
  140. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/M.pk +0 -0
  141. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/N.pk +0 -0
  142. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/O.pk +0 -0
  143. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/P.pk +0 -0
  144. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/Q.pk +0 -0
  145. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/R.pk +0 -0
  146. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/S.pk +0 -0
  147. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/T.pk +0 -0
  148. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/U.pk +0 -0
  149. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/V.pk +0 -0
  150. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/W.pk +0 -0
  151. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/X.pk +0 -0
  152. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/Y.pk +0 -0
  153. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/data/Z.pk +0 -0
  154. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/de.py +0 -0
  155. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/gse.py +0 -0
  156. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/lr.py +0 -0
  157. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/milestone.py +0 -0
  158. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/palettes.py +0 -0
  159. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/sankey.py +0 -0
  160. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/sequence.py +0 -0
  161. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/summary.py +0 -0
  162. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/track.py +0 -0
  163. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/plotting/trajectory.py +0 -0
  164. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/__init__.py +0 -0
  165. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/doublets/__init__.py +0 -0
  166. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/doublets/composite.py +0 -0
  167. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/doublets/scrublet.py +0 -0
  168. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/emptydrops.py +0 -0
  169. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/filter.py +0 -0
  170. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/impute/__init__.py +0 -0
  171. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/impute/magic.py +0 -0
  172. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/integrate.py +0 -0
  173. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/linear.py +0 -0
  174. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/normal.py +0 -0
  175. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/plot.py +0 -0
  176. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/qc.py +0 -0
  177. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/sctransform/__init__.py +0 -0
  178. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/sctransform/estimate.py +0 -0
  179. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/sctransform/ksmooth.py +0 -0
  180. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/sctransform/residual.py +0 -0
  181. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/sctransform/transform.py +0 -0
  182. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/sparse.py +0 -0
  183. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/preprocessing/uniform.py +0 -0
  184. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reader/__init__.py +0 -0
  185. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reader/conversions.py +0 -0
  186. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reader/matcher.py +0 -0
  187. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reader/metadata.py +0 -0
  188. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reader/spatial.py +0 -0
  189. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reader/updater.py +0 -0
  190. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/__init__.py +0 -0
  191. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/diffmap.py +0 -0
  192. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/forceatlas.py +0 -0
  193. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/mde.py +0 -0
  194. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/nn.py +0 -0
  195. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/outliers.py +0 -0
  196. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/pca.py +0 -0
  197. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/plot.py +0 -0
  198. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/scvi.py +0 -0
  199. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/spectral.py +0 -0
  200. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/tsne.py +0 -0
  201. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/reduction/umap.py +0 -0
  202. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/trajectory/__init__.py +0 -0
  203. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/trajectory/cytotrace.py +0 -0
  204. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/trajectory/elpi.py +0 -0
  205. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/trajectory/pcurve.py +0 -0
  206. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/trajectory/pseudotime.py +0 -0
  207. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/trajectory/root.py +0 -0
  208. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/trajectory/trace.py +0 -0
  209. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/transfer/__init__.py +0 -0
  210. {exprmat-0.1.49 → exprmat-0.1.50}/exprmat/transfer/atlas.py +0 -0
  211. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/Cargo.toml +0 -0
  212. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/license +0 -0
  213. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/readme +0 -0
  214. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/src/call_peaks.rs +0 -0
  215. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/src/embedding.rs +0 -0
  216. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/src/export.rs +0 -0
  217. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/src/knn.rs +0 -0
  218. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/src/lib.rs +0 -0
  219. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/src/motif.rs +0 -0
  220. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/src/network.rs +0 -0
  221. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/src/preprocessing.rs +0 -0
  222. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/src/utils/anndata.rs +0 -0
  223. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2/src/utils.rs +0 -0
  224. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/Cargo.toml +0 -0
  225. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/embedding.rs +0 -0
  226. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/export.rs +0 -0
  227. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/feature_count/counter.rs +0 -0
  228. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/feature_count/data_iter.rs +0 -0
  229. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/feature_count/matrix.rs +0 -0
  230. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/feature_count/mod.rs +0 -0
  231. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/genome.rs +0 -0
  232. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/lib.rs +0 -0
  233. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/motif.rs +0 -0
  234. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/network.rs +0 -0
  235. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/preprocessing/bam/flagstat.rs +0 -0
  236. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/preprocessing/bam/header.rs +0 -0
  237. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/preprocessing/bam/mark_duplicates.rs +0 -0
  238. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/preprocessing/bam.rs +0 -0
  239. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/preprocessing/import.rs +0 -0
  240. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/preprocessing/mod.rs +0 -0
  241. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/preprocessing/qc.rs +0 -0
  242. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/utils/knn.rs +0 -0
  243. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/utils/mod.rs +0 -0
  244. {exprmat-0.1.49 → exprmat-0.1.50}/snapatac2-core/src/utils/similarity.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: exprmat
3
- Version: 0.1.49
3
+ Version: 0.1.50
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -101,7 +101,7 @@ Provides-Extra: cuda12
101
101
  License-File: license
102
102
  Summary: exprmat: Routines for expression matrices
103
103
  Author-email: Zheng Yang <xornent@outlook.com>
104
- Requires-Python: >=3.9, <3.13
104
+ Requires-Python: >=3.10, <3.13
105
105
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
106
106
  Project-URL: Repository, https://github.com/yang-z-03/exprmat
107
107
 
@@ -150,18 +150,18 @@ options:
150
150
  --version VERSION The version to fetch from remote.
151
151
  ```
152
152
 
153
- Suppose you are installing the database version `0.1.25` to `~/database`.
153
+ Suppose you are installing the database version `0.1.50` to `~/database`.
154
154
 
155
155
  ```bash
156
156
  # enter the intended path of installation
157
157
  cd ~/database
158
158
 
159
- # download the version 0.1.25 of database distribution
159
+ # download the version 0.1.50 of database distribution
160
160
  # you must download the same version of the database with the package. the database
161
161
  # and package content are published strictly synchronically.
162
162
  bsync-fetch --id <your-id> --secret <your-api-secret> \
163
163
  --bucket exprmat-data --endpoint oss-cn-wuhan-lr.aliyuncs.com \
164
- --version 0.1.25
164
+ --version 0.1.50
165
165
  ```
166
166
 
167
167
  The authentication tokens passed to `--id` and `--secret` is provided by the
@@ -82,7 +82,7 @@ due to the extensive size of the reference data. You need to setup the database
82
82
  and configure it properly with configuration file `.exprmatrc` under your
83
83
  user root or current working directory
84
84
 
85
- For more guide on how to setup the database folder, and more information about
85
+ For more guide on how to install the database, and more information about
86
86
  what the database includes, see <https://github.com/yang-z-03/exprmat>
87
87
  """
88
88
 
@@ -192,6 +192,22 @@ def memory():
192
192
  info(f'virtual memory: {format_file_size(virtual)}')
193
193
 
194
194
 
195
+ def license():
196
+ print(f'''
197
+ exprmat {ver_string} - Routines to manipulate expression matrices
198
+ Copyright (C) 2025 - 2026 Zheng Yang (杨政) <xornent@outlook.com>
199
+
200
+ exprmat is free software and comes with ABSOLUTELY NO WARRANTY.
201
+ You are welcome to redistribute it under certain conditions.
202
+ You should have received a copy of the GNU General Public License
203
+ version 3 along with this program. If not, see <http://www.gnu.org/licenses/>.
204
+
205
+ The GNU General Public License does not permit incorporating
206
+ your program into proprietary programs.
207
+ ''')
208
+
209
+
210
+
195
211
  setwd = os.chdir
196
212
  getwd = os.getcwd
197
213
 
@@ -200,6 +216,17 @@ import tqdm
200
216
  tqdm.tqdm(disable = True, total = 0)
201
217
 
202
218
 
219
+ # show version info after any install or update of the database.
220
+ # this always synchronizes with the package update.
221
+
222
+ try:
223
+ fd = os.open(os.path.join(basepath, '.license'), os.O_CREAT | os.O_EXCL | os.O_WRONLY)
224
+ with os.fdopen(fd, "w") as f: f.write("shown")
225
+ license()
226
+
227
+ except FileExistsError: pass
228
+
229
+
203
230
  __all__ = [
204
231
  # exposed external namespace
205
232
  'np', 'mu', 'ad', 'sc', 'pd',
@@ -219,6 +246,7 @@ __all__ = [
219
246
  'version_db'
220
247
  'cuda',
221
248
  'memory',
249
+ 'license',
222
250
  'setwd',
223
251
  'getwd',
224
252
  'pprog',
@@ -0,0 +1,74 @@
1
+
2
+ from exprmat import basepath
3
+ import pandas as pd
4
+ import os
5
+
6
+
7
+ def get_gene_regulatory_network(taxa):
8
+ return pd.read_feather(os.path.join(basepath, taxa, 'icnet', 'gene-regulatory.feather'))
9
+
10
+ def get_lr_network(taxa):
11
+ return pd.read_feather(os.path.join(basepath, taxa, 'icnet', 'ligand-receptors.feather'))
12
+
13
+ def get_signaling_network(taxa):
14
+ return pd.read_feather(os.path.join(basepath, taxa, 'icnet', 'signaling.feather'))
15
+
16
+ def get_gene_regulatory_weights(taxa, version = 'v2'):
17
+ return pd.read_feather(os.path.join(basepath, taxa, 'icnet', version, 'gene-regulatory.feather'))
18
+
19
+ def get_lr_weights(taxa, version = 'v2'):
20
+ return pd.read_feather(os.path.join(basepath, taxa, 'icnet', version, 'lr-significance.feather'))
21
+
22
+ def get_ligand_target_matrix(taxa, version = 'v2'):
23
+ return pd.read_feather(os.path.join(basepath, taxa, 'icnet', version, 'ligand-target.feather'))
24
+
25
+ def get_ligand_tf_matrix(taxa, version = 'v2'):
26
+ return pd.read_feather(os.path.join(basepath, taxa, 'icnet', version, 'ligand-tf.feather'))
27
+
28
+
29
+ def get_weighted_ligand_target_links(ligand, geneset, ligand_target_matrix, n = 250):
30
+ import numpy as np
31
+ ltm_series = ligand_target_matrix[ligand]
32
+ data = np.array(ltm_series.values)
33
+ flat = data.flatten('C')
34
+ indices = np.argsort(flat)[-n:]
35
+
36
+ # retrieve indices
37
+ # rows are targets and columns are ligands.
38
+ ligs = []
39
+ targs = []
40
+ weights = []
41
+ for i in indices:
42
+ row = i // len(ligand)
43
+ col = i % len(ligand)
44
+ target = ligand_target_matrix.index[row]
45
+ if target in geneset:
46
+ ligs.append(ligand[col])
47
+ targs.append(ligand_target_matrix.index[row])
48
+ weights.append(flat[i])
49
+
50
+ return pd.DataFrame({
51
+ 'ligand': ligs,
52
+ 'target': targs,
53
+ 'weight': weights
54
+ })
55
+
56
+
57
+ def get_weighted_ligand_receptor_links(
58
+ best_upstream_ligands, expressed_receptors,
59
+ lr_network, weighted_networks_lr_sig
60
+ ):
61
+ lr_network = lr_network.drop_duplicates(subset = ['from', 'to'])
62
+ weighted_networks_lr = pd.merge(weighted_networks_lr_sig, lr_network, on = ['from', 'to'])
63
+
64
+ lr_network_top = lr_network[
65
+ (lr_network['from'].isin(best_upstream_ligands)) &
66
+ (lr_network['to'].isin(expressed_receptors))
67
+ ].drop_duplicates(subset = ['from','to'])
68
+ best_upstream_receptors = lr_network_top['to'].unique()
69
+
70
+ lr_network_top_df_long = weighted_networks_lr[
71
+ (weighted_networks_lr['from'].isin(best_upstream_ligands)) &
72
+ (weighted_networks_lr['to'].isin(best_upstream_receptors))]
73
+
74
+ return lr_network_top_df_long
@@ -0,0 +1,100 @@
1
+
2
+ from exprmat.data.icnet import (
3
+ get_gene_regulatory_network,
4
+ get_gene_regulatory_weights,
5
+ get_ligand_target_matrix,
6
+ get_ligand_tf_matrix,
7
+ get_lr_network,
8
+ get_lr_weights,
9
+ get_signaling_network,
10
+ get_weighted_ligand_receptor_links,
11
+ get_weighted_ligand_target_links
12
+ )
13
+
14
+ from exprmat.lr.icnet.importance import predict_ligand_activities
15
+ from exprmat import info, error
16
+ import numpy as np
17
+
18
+
19
+ def nichenet(
20
+ adata,
21
+ taxa,
22
+ receiver, # you must specify the receiver cells
23
+ sender = None,
24
+ identity = 'cell.type',
25
+ foreground = None,
26
+ background = None,
27
+ expression_threshold = 0.001,
28
+ ncpus = 1,
29
+ key_added = 'nichenet'
30
+ ):
31
+ ltm = get_ligand_target_matrix(taxa)
32
+
33
+ if background:
34
+ background = list(set(background))
35
+ info(f'using user-specified background gene set of size {len(background)}')
36
+
37
+ else: background = adata.var['gene'].tolist()
38
+ background = list(set(background).intersection(set(ltm.index.tolist())))
39
+ info(f'background gene set constructed with size {len(background)}')
40
+
41
+ if foreground:
42
+ foreground = list(set(foreground))
43
+ info(f'using user-specified foreground gene set of size {len(foreground)}')
44
+ else: error('foreground gene set must be specified')
45
+
46
+ expressed_genes = adata.var['gene'].loc[
47
+ np.array((adata.X.sum(0) / adata.X.shape[0]) > expression_threshold)[0]].tolist()
48
+ rec = adata[[x in receiver for x in adata.obs[identity]], :]
49
+ target_expressed_genes = rec.var['gene'].loc[np.array(
50
+ (rec.X.sum(0) / rec.X.shape[0]) > expression_threshold)[0]].tolist()
51
+
52
+ lr_network = get_lr_network(taxa)
53
+ all_receptors = lr_network['to'].unique().tolist()
54
+ expressed_receptors = list(set(all_receptors).intersection(set(target_expressed_genes)))
55
+ potential_ligands = [x for x, y in zip(lr_network['from'], lr_network['to']) if y in expressed_genes]
56
+
57
+ if sender:
58
+ send = adata[[x in sender for x in adata.obs[identity]], :]
59
+ sender_expressed_genes = send.var['gene'].loc[np.array(
60
+ (send.X.sum(0) / send.X.shape[0]) > expression_threshold)[0]].tolist()
61
+ potential_ligands = list(set(potential_ligands).intersection(set(sender_expressed_genes)))
62
+ info(f'{len(potential_ligands)} potential ligands filtered by sender cells expression')
63
+ else:
64
+ potential_ligands = list(set(potential_ligands))
65
+ info(f'using {len(potential_ligands)}(all) potential ligands')
66
+
67
+ info(f'using {len(expressed_receptors)} expressed receptors in receivers')
68
+
69
+ ligact = predict_ligand_activities(
70
+ geneset = foreground,
71
+ background_expressed_genes = background,
72
+ ligand_target_matrix = ltm.values,
73
+ ligand_names = ltm.columns.tolist(),
74
+ target_names = ltm.index.tolist(),
75
+ potential_ligands = potential_ligands,
76
+ ncpus = ncpus
77
+ )
78
+
79
+ adata.uns[key_added] = {
80
+ 'foreground': foreground,
81
+ 'background': background,
82
+ 'taxa': taxa,
83
+ 'activities': ligact.sort_values(['aupr.adj'], ascending = False)
84
+ }
85
+
86
+ pass
87
+
88
+
89
+ def nichenet_infer_targets(adata, key_nichenet, ligands = 10, n_targets = 250):
90
+
91
+ nnet = adata.uns[key_nichenet]
92
+ ltm = get_ligand_target_matrix(nnet['taxa'])
93
+ ltl = get_weighted_ligand_target_links(
94
+ ligand = ligands if isinstance(ligands, list) else nnet['activities'].head(ligands)['ligand'].tolist(),
95
+ geneset = nnet['foreground'],
96
+ ligand_target_matrix = ltm,
97
+ n = n_targets
98
+ )
99
+
100
+ adata.uns[key_nichenet]['ligand_targets'] = ltl
@@ -0,0 +1,270 @@
1
+ """
2
+ Network construction functions: weighted networks and hub corrections
3
+ """
4
+
5
+ import pandas as pd
6
+ import numpy as np
7
+ from typing import Dict, List, Tuple, Optional
8
+
9
+
10
+ def construct_weighted_networks(
11
+ lr_network: pd.DataFrame,
12
+ sig_network: pd.DataFrame,
13
+ gr_network: pd.DataFrame,
14
+ source_weights_df: pd.DataFrame,
15
+ n_output_networks: int = 2
16
+ ) -> Dict[str, pd.DataFrame]:
17
+ """
18
+ Construct layer-specific weighted integrated networks from input source networks
19
+ via weighted aggregation.
20
+
21
+ Parameters:
22
+ -----------
23
+ lr_network : pd.DataFrame
24
+ Ligand-receptor interactions (required columns: from, to, source)
25
+ sig_network : pd.DataFrame
26
+ Signaling interactions (required columns: from, to, source)
27
+ gr_network : pd.DataFrame
28
+ Gene regulatory interactions (required columns: from, to, source)
29
+ source_weights_df : pd.DataFrame
30
+ Weights associated to each data source (required columns: source, weight)
31
+ n_output_networks : int
32
+ Number of output networks: 2 (ligand-signaling and gene regulatory; default)
33
+ or 3 (ligand-receptor, signaling and gene regulatory)
34
+
35
+ Returns:
36
+ --------
37
+ dict
38
+ Dictionary containing:
39
+ - If n_output_networks=2: {'lr_sig': DataFrame, 'gr': DataFrame}
40
+ - If n_output_networks=3: {'lr': DataFrame, 'sig': DataFrame, 'gr': DataFrame}
41
+ Each DataFrame has columns: from, to, weight
42
+ """
43
+ # Input validation
44
+ if not isinstance(lr_network, pd.DataFrame):
45
+ raise TypeError("lr_network must be a pandas DataFrame")
46
+ if not isinstance(sig_network, pd.DataFrame):
47
+ raise TypeError("sig_network must be a pandas DataFrame")
48
+ if not isinstance(gr_network, pd.DataFrame):
49
+ raise TypeError("gr_network must be a pandas DataFrame")
50
+ if not isinstance(source_weights_df, pd.DataFrame):
51
+ raise TypeError("source_weights_df must be a pandas DataFrame")
52
+
53
+ required_cols_lr = ['from', 'to', 'source']
54
+ required_cols_weights = ['source', 'weight']
55
+
56
+ for col in required_cols_lr:
57
+ if col not in lr_network.columns:
58
+ raise ValueError(f"lr_network must have column '{col}'")
59
+ if col not in sig_network.columns:
60
+ raise ValueError(f"sig_network must have column '{col}'")
61
+ if col not in gr_network.columns:
62
+ raise ValueError(f"gr_network must have column '{col}'")
63
+
64
+ for col in required_cols_weights:
65
+ if col not in source_weights_df.columns:
66
+ raise ValueError(f"source_weights_df must have column '{col}'")
67
+
68
+ if (source_weights_df['weight'] > 1).any():
69
+ raise ValueError("No data source weight may be higher than 1")
70
+
71
+ if n_output_networks not in [2, 3]:
72
+ raise ValueError("n_output_networks must be 2 or 3")
73
+
74
+ # Remove data sources for which weight equals 0
75
+ source_weights_df = source_weights_df[source_weights_df['weight'] > 0].copy()
76
+
77
+ # Perform weighted network aggregation for gene regulatory network
78
+ gr_network_w = (
79
+ gr_network
80
+ .merge(source_weights_df, on='source', how='inner')
81
+ .groupby(['from', 'to'], as_index=False)
82
+ .agg({'weight': 'sum'})
83
+ )
84
+
85
+ if n_output_networks == 2:
86
+ # Combine ligand-receptor and signaling networks
87
+ ligand_signaling_w = (
88
+ pd.concat([lr_network, sig_network], ignore_index=True)
89
+ .merge(source_weights_df, on='source', how='inner')
90
+ .groupby(['from', 'to'], as_index=False)
91
+ .agg({'weight': 'sum'})
92
+ )
93
+ return {
94
+ 'lr_sig': ligand_signaling_w,
95
+ 'gr': gr_network_w
96
+ }
97
+ else: # n_output_networks == 3
98
+ lr_network_w = (
99
+ lr_network
100
+ .merge(source_weights_df, on='source', how='inner')
101
+ .groupby(['from', 'to'], as_index=False)
102
+ .agg({'weight': 'sum'})
103
+ )
104
+ sig_network_w = (
105
+ sig_network
106
+ .merge(source_weights_df, on='source', how='inner')
107
+ .groupby(['from', 'to'], as_index=False)
108
+ .agg({'weight': 'sum'})
109
+ )
110
+ return {
111
+ 'lr': lr_network_w,
112
+ 'sig': sig_network_w,
113
+ 'gr': gr_network_w
114
+ }
115
+
116
+
117
+ def apply_hub_corrections(
118
+ weighted_networks: Dict[str, pd.DataFrame],
119
+ lr_sig_hub: float,
120
+ gr_hub: float
121
+ ) -> Dict[str, pd.DataFrame]:
122
+ """
123
+ Apply hub corrections to the weighted integrated ligand-signaling and gene
124
+ regulatory network. Downweighs the importance of nodes with a lot of incoming links.
125
+
126
+ Hub correction method: W_cor = W * D^(-h)
127
+ where D is the indegree matrix and h is the correction factor.
128
+
129
+ Parameters:
130
+ -----------
131
+ weighted_networks : dict
132
+ Dictionary with keys 'lr_sig' and 'gr', each containing a DataFrame
133
+ with columns: from, to, weight
134
+ lr_sig_hub : float
135
+ Hub correction factor for ligand-signaling network (0-1).
136
+ 0: no correction, 1: maximal correction
137
+ gr_hub : float
138
+ Hub correction factor for gene regulatory network (0-1).
139
+ 0: no correction, 1: maximal correction
140
+
141
+ Returns:
142
+ --------
143
+ dict
144
+ Dictionary with hub-corrected networks: {'lr_sig': DataFrame, 'gr': DataFrame}
145
+ """
146
+ # Input validation
147
+ if not isinstance(weighted_networks, dict):
148
+ raise TypeError("weighted_networks must be a dictionary")
149
+ if 'lr_sig' not in weighted_networks:
150
+ raise ValueError("weighted_networks must contain 'lr_sig' key")
151
+ if 'gr' not in weighted_networks:
152
+ raise ValueError("weighted_networks must contain 'gr' key")
153
+
154
+ if not isinstance(weighted_networks['lr_sig'], pd.DataFrame):
155
+ raise TypeError("weighted_networks['lr_sig'] must be a pandas DataFrame")
156
+ if not isinstance(weighted_networks['gr'], pd.DataFrame):
157
+ raise TypeError("weighted_networks['gr'] must be a pandas DataFrame")
158
+
159
+ if 'weight' not in weighted_networks['lr_sig'].columns:
160
+ raise ValueError("lr_sig must contain a column named 'weight'")
161
+ if 'weight' not in weighted_networks['gr'].columns:
162
+ raise ValueError("gr must contain a column named 'weight'")
163
+
164
+ if not (0 <= lr_sig_hub <= 1):
165
+ raise ValueError("lr_sig_hub must be between 0 and 1 (inclusive)")
166
+ if not (0 <= gr_hub <= 1):
167
+ raise ValueError("gr_hub must be between 0 and 1 (inclusive)")
168
+
169
+ ligand_signaling_network = weighted_networks['lr_sig'].copy()
170
+ regulatory_network = weighted_networks['gr'].copy()
171
+
172
+ # Apply hub correction to ligand-signaling network
173
+ if lr_sig_hub > 0:
174
+ # Count incoming edges (indegree) for each node
175
+ indegree = ligand_signaling_network.groupby('to', as_index=False).size()
176
+ indegree.columns = ['to', 'n']
177
+
178
+ # Merge indegree counts and apply correction
179
+ ligand_signaling_network = (
180
+ ligand_signaling_network
181
+ .merge(indegree, on='to', how='left')
182
+ .assign(weight=lambda x: x['weight'] / (x['n'] ** lr_sig_hub))
183
+ .drop(columns=['n'])
184
+ )
185
+
186
+ # Apply hub correction to gene regulatory network
187
+ if gr_hub > 0:
188
+ # Count incoming edges (indegree) for each node
189
+ indegree = regulatory_network.groupby('to', as_index=False).size()
190
+ indegree.columns = ['to', 'n']
191
+
192
+ # Merge indegree counts and apply correction
193
+ regulatory_network = (
194
+ regulatory_network
195
+ .merge(indegree, on='to', how='left')
196
+ .assign(weight=lambda x: x['weight'] / (x['n'] ** gr_hub))
197
+ .drop(columns=['n'])
198
+ )
199
+
200
+ return {
201
+ 'lr_sig': ligand_signaling_network,
202
+ 'gr': regulatory_network
203
+ }
204
+
205
+
206
+ def add_new_datasource(
207
+ new_source: pd.DataFrame,
208
+ network: Optional[pd.DataFrame],
209
+ new_weight: float,
210
+ source_weights_df: pd.DataFrame
211
+ ) -> Tuple[pd.DataFrame, pd.DataFrame]:
212
+ """
213
+ Add a new data source to one of the ligand-receptor, signaling or gene
214
+ regulatory data sources.
215
+
216
+ Parameters:
217
+ -----------
218
+ new_source : pd.DataFrame
219
+ Novel interactions (required columns: from, to, source)
220
+ network : pd.DataFrame or None
221
+ Base network to which to add the new data source (required columns: from, to, source)
222
+ If None, creates a new network
223
+ new_weight : float
224
+ Weight value between 0 and 1 to assign to the new data source
225
+ source_weights_df : pd.DataFrame
226
+ Weights associated to each already included data source (required columns: source, weight)
227
+
228
+ Returns:
229
+ --------
230
+ tuple
231
+ (updated_network, updated_source_weights_df)
232
+ """
233
+ # Input validation
234
+ if not isinstance(new_source, pd.DataFrame):
235
+ raise TypeError("new_source must be a pandas DataFrame")
236
+ if network is not None and not isinstance(network, pd.DataFrame):
237
+ raise TypeError("network must be a pandas DataFrame or None")
238
+ if not isinstance(source_weights_df, pd.DataFrame):
239
+ raise TypeError("source_weights_df must be a pandas DataFrame")
240
+
241
+ if not (0 <= new_weight <= 1):
242
+ raise ValueError("new_weight must be between 0 and 1")
243
+
244
+ if (source_weights_df['weight'] > 1).any() or new_weight > 1:
245
+ raise ValueError("No data source weight may be higher than 1")
246
+
247
+ # Get unique source name(s) from new_source
248
+ new_source_names = new_source['source'].unique()
249
+
250
+ if network is None:
251
+ # Create new network
252
+ updated_network = new_source.copy()
253
+ updated_source_weights_df = pd.DataFrame({
254
+ 'source': new_source_names,
255
+ 'weight': [new_weight] * len(new_source_names)
256
+ })
257
+ else:
258
+ # Add to existing network
259
+ updated_network = pd.concat([network, new_source], ignore_index=True)
260
+ new_weights = pd.DataFrame({
261
+ 'source': new_source_names,
262
+ 'weight': [new_weight] * len(new_source_names)
263
+ })
264
+ updated_source_weights_df = pd.concat(
265
+ [source_weights_df, new_weights],
266
+ ignore_index=True
267
+ )
268
+
269
+ return updated_network, updated_source_weights_df
270
+
@@ -0,0 +1,159 @@
1
+ """
2
+ Ligand activity prediction functions
3
+ """
4
+
5
+ import numpy as np
6
+ import pandas as pd
7
+ from typing import List, Union, Dict
8
+ import functools
9
+ from .metrics import calculate_auroc, calculate_aupr, classification_evaluation_continuous_pred
10
+
11
+
12
+ def get_single_ligand_importances(
13
+ test_ligand: str,
14
+ ligand_target_matrix: np.ndarray,
15
+ ligand_names: List[str],
16
+ target_names: List[str],
17
+ geneset: List[str],
18
+ background_expressed_genes: List[str],
19
+ known: bool = False
20
+ ) -> Dict[str, float]:
21
+ """
22
+ Calculate importance scores for a single ligand.
23
+
24
+ Parameters:
25
+ -----------
26
+ ligand_target_matrix : np.ndarray
27
+ Matrix of ligand-target scores (ligands as columns, targets as rows)
28
+ ligand_names : list of str
29
+ Names of ligands (column names)
30
+ target_names : list of str
31
+ Names of target genes (row names)
32
+ geneset : list of str
33
+ Genes of interest (potentially affected by ligands)
34
+ background_expressed_genes : list of str
35
+ Background genes
36
+ test_ligand : str
37
+ Ligand to test
38
+ known : bool
39
+ Whether this is a known ligand (default False)
40
+
41
+ Returns:
42
+ --------
43
+ dict
44
+ Dictionary with metrics: test_ligand, auroc, aupr, aupr_corrected, pearson
45
+ """
46
+ # Find ligand index
47
+ if test_ligand not in ligand_names:
48
+ raise ValueError(f"Ligand {test_ligand} not found in ligand_target_matrix")
49
+
50
+ ligand_idx = ligand_names.index(test_ligand)
51
+
52
+ # Get predictions for this ligand
53
+ predictions = ligand_target_matrix[:, ligand_idx]
54
+
55
+ # Create binary labels: 1 for geneset, 0 for background
56
+ labels = np.array([1 if gene in geneset else 0 for gene in target_names])
57
+
58
+ # Filter to only background + geneset genes
59
+ valid_indices = [i for i, gene in enumerate(target_names)
60
+ if gene in geneset or gene in background_expressed_genes]
61
+
62
+ if len(valid_indices) == 0:
63
+ return {
64
+ 'ligand': test_ligand,
65
+ 'auroc': 0.5,
66
+ 'aupr': 0.0,
67
+ 'aupr.adj': 0.0,
68
+ 'pearson': 0.0
69
+ }
70
+
71
+ predictions_filtered = predictions[valid_indices]
72
+ labels_filtered = labels[valid_indices]
73
+
74
+ # Calculate metrics
75
+ auroc = calculate_auroc(predictions_filtered, labels_filtered)
76
+ aupr = calculate_aupr(predictions_filtered, labels_filtered)
77
+
78
+ # Calculate Pearson correlation
79
+ if len(predictions_filtered) > 1:
80
+ pearson = np.corrcoef(predictions_filtered, labels_filtered.astype(float))[0, 1]
81
+ if np.isnan(pearson):
82
+ pearson = 0.0
83
+ else:
84
+ pearson = 0.0
85
+
86
+ # AUPR corrected (subtract baseline AUPR)
87
+ # Baseline AUPR = fraction of positive examples
88
+ baseline_aupr = np.mean(labels_filtered)
89
+ aupr_corrected = aupr - baseline_aupr
90
+
91
+ return {
92
+ 'ligand': test_ligand,
93
+ 'auroc': auroc,
94
+ 'aupr': aupr,
95
+ 'aupr.adj': aupr_corrected,
96
+ 'pearson': pearson
97
+ }
98
+
99
+
100
+ def predict_ligand_activities(
101
+ geneset: List[str],
102
+ background_expressed_genes: List[str],
103
+ ligand_target_matrix: np.ndarray,
104
+ ligand_names: List[str],
105
+ target_names: List[str],
106
+ potential_ligands: List[str],
107
+ ncpus = 1,
108
+ ) -> pd.DataFrame:
109
+ """
110
+ Predict activities of ligands in regulating expression of a gene set of interest.
111
+
112
+ Parameters:
113
+ -----------
114
+ geneset : list of str
115
+ Gene symbols of genes potentially affected by ligands
116
+ background_expressed_genes : list of str
117
+ Background gene symbols
118
+ ligand_target_matrix : np.ndarray
119
+ Ligand-target probability matrix (ligands as columns, targets as rows)
120
+ ligand_names : list of str
121
+ Names of ligands (column names)
122
+ target_names : list of str
123
+ Names of target genes (row names)
124
+ potential_ligands : list of str
125
+ Ligands to test
126
+
127
+ Returns:
128
+ --------
129
+ pd.DataFrame
130
+ DataFrame with columns: test_ligand, auroc, aupr, aupr_corrected, pearson
131
+ """
132
+
133
+ valid_ligands = [ligand for ligand in potential_ligands if ligand in ligand_names]
134
+ from multiprocessing import Pool
135
+ from exprmat import pprog
136
+
137
+ with Pool(ncpus) as p:
138
+ results = list(
139
+ pprog(
140
+ p.imap_unordered(
141
+ functools.partial(
142
+ get_single_ligand_importances,
143
+ ligand_target_matrix = ligand_target_matrix,
144
+ ligand_names = ligand_names,
145
+ target_names = target_names,
146
+ geneset = geneset,
147
+ background_expressed_genes = background_expressed_genes,
148
+ known = False
149
+ ),
150
+ valid_ligands,
151
+ chunksize = 1,
152
+ ),
153
+ total = len(valid_ligands),
154
+ desc = 'predicting ligand activities'
155
+ )
156
+ )
157
+
158
+ return pd.DataFrame(results)
159
+