peakatail 0.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 (317) hide show
  1. peakatail-0.3.0/LICENSE +21 -0
  2. peakatail-0.3.0/PKG-INFO +337 -0
  3. peakatail-0.3.0/README.md +284 -0
  4. peakatail-0.3.0/ema/__init__.py +22 -0
  5. peakatail-0.3.0/ema/__main__.py +16 -0
  6. peakatail-0.3.0/ema/annotate/__init__.py +0 -0
  7. peakatail-0.3.0/ema/annotate/annotate.py +120 -0
  8. peakatail-0.3.0/ema/annotate/find_close.py +389 -0
  9. peakatail-0.3.0/ema/annotate/gtf2isoform_utr.py +304 -0
  10. peakatail-0.3.0/ema/annotate/gtf_cache.py +390 -0
  11. peakatail-0.3.0/ema/annotate/gtftobed.py +136 -0
  12. peakatail-0.3.0/ema/benchmark/__init__.py +6 -0
  13. peakatail-0.3.0/ema/benchmark/cross_experiment.py +1215 -0
  14. peakatail-0.3.0/ema/benchmark/length_compare.py +367 -0
  15. peakatail-0.3.0/ema/benchmark/metrics.py +613 -0
  16. peakatail-0.3.0/ema/benchmark/report.py +86 -0
  17. peakatail-0.3.0/ema/benchmark/runner.py +236 -0
  18. peakatail-0.3.0/ema/benchmark/sweep_analysis.py +1377 -0
  19. peakatail-0.3.0/ema/benchmark/switch_diff_compare.py +368 -0
  20. peakatail-0.3.0/ema/benchmark/visualize.py +341 -0
  21. peakatail-0.3.0/ema/celltype/__init__.py +15 -0
  22. peakatail-0.3.0/ema/celltype/scoring.py +136 -0
  23. peakatail-0.3.0/ema/cli/__init__.py +192 -0
  24. peakatail-0.3.0/ema/cli/collapse.py +55 -0
  25. peakatail-0.3.0/ema/cli/common.py +350 -0
  26. peakatail-0.3.0/ema/cli/config_schema.py +1853 -0
  27. peakatail-0.3.0/ema/cli/defaults.py +34 -0
  28. peakatail-0.3.0/ema/cli/merge.py +55 -0
  29. peakatail-0.3.0/ema/cli/parse_gtf.py +74 -0
  30. peakatail-0.3.0/ema/cli/reannotate.py +180 -0
  31. peakatail-0.3.0/ema/cli/run.py +293 -0
  32. peakatail-0.3.0/ema/cli/switch.py +23 -0
  33. peakatail-0.3.0/ema/cli/switch_combine.py +83 -0
  34. peakatail-0.3.0/ema/cli/switch_diff.py +263 -0
  35. peakatail-0.3.0/ema/cli/switch_geneview.py +415 -0
  36. peakatail-0.3.0/ema/cli/switch_length.py +165 -0
  37. peakatail-0.3.0/ema/cli/switch_match.py +133 -0
  38. peakatail-0.3.0/ema/cli/switch_trend.py +295 -0
  39. peakatail-0.3.0/ema/cli/wizard.py +400 -0
  40. peakatail-0.3.0/ema/cli/yaml_loader.py +115 -0
  41. peakatail-0.3.0/ema/clustering/__init__.py +0 -0
  42. peakatail-0.3.0/ema/clustering/_builtins.py +26 -0
  43. peakatail-0.3.0/ema/clustering/clustering.py +259 -0
  44. peakatail-0.3.0/ema/clustering/cross_dataset/__init__.py +107 -0
  45. peakatail-0.3.0/ema/clustering/cross_dataset/base.py +82 -0
  46. peakatail-0.3.0/ema/clustering/cross_dataset/jaccard.py +234 -0
  47. peakatail-0.3.0/ema/clustering/cross_dataset/marker_overlap.py +414 -0
  48. peakatail-0.3.0/ema/clustering/cross_dataset/mnn.py +382 -0
  49. peakatail-0.3.0/ema/clustering/cross_dataset/roundtrip.py +92 -0
  50. peakatail-0.3.0/ema/clustering/evaluation.py +147 -0
  51. peakatail-0.3.0/ema/clustering/registry.py +32 -0
  52. peakatail-0.3.0/ema/clustering/strategies/__init__.py +36 -0
  53. peakatail-0.3.0/ema/clustering/strategies/base.py +57 -0
  54. peakatail-0.3.0/ema/clustering/strategies/external.py +103 -0
  55. peakatail-0.3.0/ema/clustering/strategies/leiden_libsize.py +108 -0
  56. peakatail-0.3.0/ema/clustering/strategies/leiden_tfidf.py +252 -0
  57. peakatail-0.3.0/ema/config.py +511 -0
  58. peakatail-0.3.0/ema/countmatrix/__init__.py +0 -0
  59. peakatail-0.3.0/ema/countmatrix/bam_utils.py +41 -0
  60. peakatail-0.3.0/ema/countmatrix/cb_encode.py +144 -0
  61. peakatail-0.3.0/ema/countmatrix/chrom_parallel.py +605 -0
  62. peakatail-0.3.0/ema/countmatrix/cleavage_offset.py +969 -0
  63. peakatail-0.3.0/ema/countmatrix/dynamic_threshold.py +188 -0
  64. peakatail-0.3.0/ema/countmatrix/indexing.py +273 -0
  65. peakatail-0.3.0/ema/countmatrix/models/pas_score_model_prime1.json +1 -0
  66. peakatail-0.3.0/ema/countmatrix/pas_features.py +605 -0
  67. peakatail-0.3.0/ema/countmatrix/pas_score.py +289 -0
  68. peakatail-0.3.0/ema/countmatrix/pasfind.py +1 -0
  69. peakatail-0.3.0/ema/countmatrix/paswrite.py +187 -0
  70. peakatail-0.3.0/ema/countmatrix/peackcalling.py +725 -0
  71. peakatail-0.3.0/ema/countmatrix/peak.py +207 -0
  72. peakatail-0.3.0/ema/countmatrix/peak_pipeline.py +821 -0
  73. peakatail-0.3.0/ema/countmatrix/peak_state.py +43 -0
  74. peakatail-0.3.0/ema/countmatrix/polya.py +1572 -0
  75. peakatail-0.3.0/ema/countmatrix/read.py +286 -0
  76. peakatail-0.3.0/ema/countmatrix/tile_runner.py +1192 -0
  77. peakatail-0.3.0/ema/data/__init__.py +13 -0
  78. peakatail-0.3.0/ema/data/run.py +533 -0
  79. peakatail-0.3.0/ema/datasets/__init__.py +1 -0
  80. peakatail-0.3.0/ema/datasets/atlas_annotate.py +236 -0
  81. peakatail-0.3.0/ema/datasets/atlas_snap.py +414 -0
  82. peakatail-0.3.0/ema/datasets/collapse.py +150 -0
  83. peakatail-0.3.0/ema/datasets/manager.py +131 -0
  84. peakatail-0.3.0/ema/datasets/pas_merge.py +450 -0
  85. peakatail-0.3.0/ema/downstream_runner.py +506 -0
  86. peakatail-0.3.0/ema/experimental/__init__.py +1 -0
  87. peakatail-0.3.0/ema/experimental/internal_priming.py +304 -0
  88. peakatail-0.3.0/ema/experimental/peak_filters.py +224 -0
  89. peakatail-0.3.0/ema/logging_config.py +174 -0
  90. peakatail-0.3.0/ema/main.py +2551 -0
  91. peakatail-0.3.0/ema/matrixfilter.py +557 -0
  92. peakatail-0.3.0/ema/merge_bam/__init__.py +0 -0
  93. peakatail-0.3.0/ema/merge_bam/merge.py +8 -0
  94. peakatail-0.3.0/ema/merge_bam/runner.py +32 -0
  95. peakatail-0.3.0/ema/outputs.py +783 -0
  96. peakatail-0.3.0/ema/progress.py +198 -0
  97. peakatail-0.3.0/ema/provenance.py +607 -0
  98. peakatail-0.3.0/ema/quantification/__init__.py +0 -0
  99. peakatail-0.3.0/ema/quantification/marker_selector.py +114 -0
  100. peakatail-0.3.0/ema/quantification/pas_to_isoform.py +385 -0
  101. peakatail-0.3.0/ema/quantification/pdui.py +189 -0
  102. peakatail-0.3.0/ema/quantification/strategies/__init__.py +75 -0
  103. peakatail-0.3.0/ema/quantification/strategies/base.py +88 -0
  104. peakatail-0.3.0/ema/quantification/strategies/classic.py +394 -0
  105. peakatail-0.3.0/ema/quantification/strategies/proportion.py +408 -0
  106. peakatail-0.3.0/ema/quantification/strategies/shannon.py +299 -0
  107. peakatail-0.3.0/ema/reannotate.py +751 -0
  108. peakatail-0.3.0/ema/statistics/__init__.py +2 -0
  109. peakatail-0.3.0/ema/statistics/background.py +66 -0
  110. peakatail-0.3.0/ema/statistics/significance.py +76 -0
  111. peakatail-0.3.0/ema/strategies/__init__.py +32 -0
  112. peakatail-0.3.0/ema/strategies/base.py +70 -0
  113. peakatail-0.3.0/ema/strategies/clip_seeded.py +129 -0
  114. peakatail-0.3.0/ema/strategies/lambda_gradient.py +327 -0
  115. peakatail-0.3.0/ema/strategies/lambda_poisson.py +154 -0
  116. peakatail-0.3.0/ema/strategies/original.py +24 -0
  117. peakatail-0.3.0/ema/strategies/sierra_iterative.py +132 -0
  118. peakatail-0.3.0/ema/strategies/utils.py +186 -0
  119. peakatail-0.3.0/ema/switch_test/__init__.py +0 -0
  120. peakatail-0.3.0/ema/switch_test/combine.py +159 -0
  121. peakatail-0.3.0/ema/switch_test/fishertest.py +152 -0
  122. peakatail-0.3.0/ema/switch_test/groupby.py +33 -0
  123. peakatail-0.3.0/ema/switch_test/long_output.py +453 -0
  124. peakatail-0.3.0/ema/switch_test/pair_runner.py +87 -0
  125. peakatail-0.3.0/ema/switch_test/prefilter.py +57 -0
  126. peakatail-0.3.0/ema/switch_test/runner.py +1874 -0
  127. peakatail-0.3.0/ema/switch_test/strategies/__init__.py +95 -0
  128. peakatail-0.3.0/ema/switch_test/strategies/base.py +80 -0
  129. peakatail-0.3.0/ema/switch_test/strategies/fisher.py +288 -0
  130. peakatail-0.3.0/ema/switch_test/strategies/nb_multi.py +424 -0
  131. peakatail-0.3.0/ema/switch_test/strategies/nb_pairwise.py +437 -0
  132. peakatail-0.3.0/ema/switch_test/trend.py +529 -0
  133. peakatail-0.3.0/ema/utils/__init__.py +52 -0
  134. peakatail-0.3.0/ema/utils/resource_manager.py +293 -0
  135. peakatail-0.3.0/ema/validation/__init__.py +1 -0
  136. peakatail-0.3.0/ema/validation/db_compare.py +228 -0
  137. peakatail-0.3.0/ema/validation/output_validator.py +219 -0
  138. peakatail-0.3.0/ema/validation/regression.py +252 -0
  139. peakatail-0.3.0/ema/viz/__init__.py +99 -0
  140. peakatail-0.3.0/ema/viz/_gene_track_helpers.py +675 -0
  141. peakatail-0.3.0/ema/viz/_io.py +37 -0
  142. peakatail-0.3.0/ema/viz/_meta.py +214 -0
  143. peakatail-0.3.0/ema/viz/atlas_snap_diag_matplotlib.py +118 -0
  144. peakatail-0.3.0/ema/viz/atlas_snap_diag_plotly.py +135 -0
  145. peakatail-0.3.0/ema/viz/base.py +28 -0
  146. peakatail-0.3.0/ema/viz/cluster_match_sankey_matplotlib.py +141 -0
  147. peakatail-0.3.0/ema/viz/cluster_match_sankey_plotly.py +161 -0
  148. peakatail-0.3.0/ema/viz/cluster_sizes_matplotlib.py +46 -0
  149. peakatail-0.3.0/ema/viz/cluster_sizes_plotly.py +37 -0
  150. peakatail-0.3.0/ema/viz/diff_agreement_matplotlib.py +91 -0
  151. peakatail-0.3.0/ema/viz/diff_agreement_plotly.py +98 -0
  152. peakatail-0.3.0/ema/viz/entropy_distribution_matplotlib.py +91 -0
  153. peakatail-0.3.0/ema/viz/entropy_distribution_plotly.py +71 -0
  154. peakatail-0.3.0/ema/viz/gene_track_matplotlib.py +754 -0
  155. peakatail-0.3.0/ema/viz/gene_track_plotly.py +845 -0
  156. peakatail-0.3.0/ema/viz/length_shifts_matplotlib.py +88 -0
  157. peakatail-0.3.0/ema/viz/length_shifts_plotly.py +104 -0
  158. peakatail-0.3.0/ema/viz/match_confidence_matplotlib.py +123 -0
  159. peakatail-0.3.0/ema/viz/match_confidence_plotly.py +119 -0
  160. peakatail-0.3.0/ema/viz/pas_overlap_matplotlib.py +154 -0
  161. peakatail-0.3.0/ema/viz/pas_overlap_plotly.py +125 -0
  162. peakatail-0.3.0/ema/viz/pdui_distribution_matplotlib.py +104 -0
  163. peakatail-0.3.0/ema/viz/pdui_distribution_plotly.py +100 -0
  164. peakatail-0.3.0/ema/viz/pdui_distribution_scanpy.py +91 -0
  165. peakatail-0.3.0/ema/viz/peak_qc_matplotlib.py +60 -0
  166. peakatail-0.3.0/ema/viz/peak_qc_plotly.py +45 -0
  167. peakatail-0.3.0/ema/viz/pipeline_hooks.py +1168 -0
  168. peakatail-0.3.0/ema/viz/proportion_heatmap_matplotlib.py +237 -0
  169. peakatail-0.3.0/ema/viz/proportion_heatmap_plotly.py +72 -0
  170. peakatail-0.3.0/ema/viz/resource_timeline_matplotlib.py +132 -0
  171. peakatail-0.3.0/ema/viz/resource_timeline_plotly.py +161 -0
  172. peakatail-0.3.0/ema/viz/run_report.py +376 -0
  173. peakatail-0.3.0/ema/viz/tile_timing_matplotlib.py +140 -0
  174. peakatail-0.3.0/ema/viz/tile_timing_plotly.py +137 -0
  175. peakatail-0.3.0/ema/viz/umap_matplotlib.py +53 -0
  176. peakatail-0.3.0/ema/viz/umap_plotly.py +46 -0
  177. peakatail-0.3.0/ema/viz/umap_scanpy.py +39 -0
  178. peakatail-0.3.0/ema/viz/volcano_matplotlib.py +189 -0
  179. peakatail-0.3.0/ema/viz/volcano_plotly.py +188 -0
  180. peakatail-0.3.0/peakatail.egg-info/PKG-INFO +337 -0
  181. peakatail-0.3.0/peakatail.egg-info/SOURCES.txt +315 -0
  182. peakatail-0.3.0/peakatail.egg-info/dependency_links.txt +1 -0
  183. peakatail-0.3.0/peakatail.egg-info/entry_points.txt +3 -0
  184. peakatail-0.3.0/peakatail.egg-info/requires.txt +39 -0
  185. peakatail-0.3.0/peakatail.egg-info/top_level.txt +1 -0
  186. peakatail-0.3.0/pyproject.toml +110 -0
  187. peakatail-0.3.0/setup.cfg +4 -0
  188. peakatail-0.3.0/test/test_cli.py +2 -0
  189. peakatail-0.3.0/test/test_filtermatrix.py +8 -0
  190. peakatail-0.3.0/test/test_peak.py +6 -0
  191. peakatail-0.3.0/test/test_switch_diff_cells_mode.py +255 -0
  192. peakatail-0.3.0/test/testconfig.py +0 -0
  193. peakatail-0.3.0/tests/test_annotate_runscoped_b2.py +50 -0
  194. peakatail-0.3.0/tests/test_artifact_naming_d7.py +67 -0
  195. peakatail-0.3.0/tests/test_atlas_annotate_overlay.py +275 -0
  196. peakatail-0.3.0/tests/test_atlas_snap_annotate_d9.py +168 -0
  197. peakatail-0.3.0/tests/test_atlas_snap_ledger_e3.py +67 -0
  198. peakatail-0.3.0/tests/test_atlas_snap_rate_d1.py +111 -0
  199. peakatail-0.3.0/tests/test_atlas_snap_summit.py +146 -0
  200. peakatail-0.3.0/tests/test_audit_cli_coverage.py +134 -0
  201. peakatail-0.3.0/tests/test_benchmark_point_strand.py +351 -0
  202. peakatail-0.3.0/tests/test_between_utr_report_gating_i94.py +160 -0
  203. peakatail-0.3.0/tests/test_build_count_dfs_which.py +87 -0
  204. peakatail-0.3.0/tests/test_canonical_roundtrip_b6.py +84 -0
  205. peakatail-0.3.0/tests/test_cb_encode.py +267 -0
  206. peakatail-0.3.0/tests/test_cellranger_input_compat.py +385 -0
  207. peakatail-0.3.0/tests/test_celltype_scoring_a1.py +131 -0
  208. peakatail-0.3.0/tests/test_changelog_section.py +267 -0
  209. peakatail-0.3.0/tests/test_chrom_parallel_identity.py +488 -0
  210. peakatail-0.3.0/tests/test_classic_pdui_vectorized.py +145 -0
  211. peakatail-0.3.0/tests/test_cleavage_offset_i72.py +380 -0
  212. peakatail-0.3.0/tests/test_cleavage_offset_prime.py +356 -0
  213. peakatail-0.3.0/tests/test_cleavage_offset_skips_clip_supported.py +53 -0
  214. peakatail-0.3.0/tests/test_cli_merge_parse_gtf.py +32 -0
  215. peakatail-0.3.0/tests/test_cli_rename_peakatail.py +76 -0
  216. peakatail-0.3.0/tests/test_cli_root.py +67 -0
  217. peakatail-0.3.0/tests/test_cli_run.py +159 -0
  218. peakatail-0.3.0/tests/test_cli_switch.py +279 -0
  219. peakatail-0.3.0/tests/test_cli_wizard.py +38 -0
  220. peakatail-0.3.0/tests/test_clip_rate_sampling.py +317 -0
  221. peakatail-0.3.0/tests/test_cluster_matching.py +593 -0
  222. peakatail-0.3.0/tests/test_clustering_registry.py +30 -0
  223. peakatail-0.3.0/tests/test_collapse_a4.py +138 -0
  224. peakatail-0.3.0/tests/test_config_schema.py +231 -0
  225. peakatail-0.3.0/tests/test_config_schema_atlas_ip_mode_d9.py +79 -0
  226. peakatail-0.3.0/tests/test_data_run_e4.py +417 -0
  227. peakatail-0.3.0/tests/test_docs_consistency.py +334 -0
  228. peakatail-0.3.0/tests/test_downstream_parallel.py +382 -0
  229. peakatail-0.3.0/tests/test_dynamic_threshold_bounds.py +372 -0
  230. peakatail-0.3.0/tests/test_filtered_cb_b3.py +39 -0
  231. peakatail-0.3.0/tests/test_findings_long_e5.py +347 -0
  232. peakatail-0.3.0/tests/test_fisher_percell_d4.py +85 -0
  233. peakatail-0.3.0/tests/test_gene_id_repair_b7.py +68 -0
  234. peakatail-0.3.0/tests/test_gene_track_regions.py +369 -0
  235. peakatail-0.3.0/tests/test_global_pool.py +310 -0
  236. peakatail-0.3.0/tests/test_gtf2isoform_utr.py +293 -0
  237. peakatail-0.3.0/tests/test_gtf_cache_global.py +418 -0
  238. peakatail-0.3.0/tests/test_internal_priming_strand.py +305 -0
  239. peakatail-0.3.0/tests/test_ip_annot_filter_d6.py +411 -0
  240. peakatail-0.3.0/tests/test_ip_filter_default.py +139 -0
  241. peakatail-0.3.0/tests/test_label_independent_prefilter_i94.py +466 -0
  242. peakatail-0.3.0/tests/test_logging_config.py +102 -0
  243. peakatail-0.3.0/tests/test_marker_selector_dtype.py +70 -0
  244. peakatail-0.3.0/tests/test_marker_top_n_double_dip_i94.py +471 -0
  245. peakatail-0.3.0/tests/test_marker_top_n_utr_denominator_i94.py +299 -0
  246. peakatail-0.3.0/tests/test_matrix_pas_id_row_alignment.py +226 -0
  247. peakatail-0.3.0/tests/test_matrixfilter_vectorized.py +386 -0
  248. peakatail-0.3.0/tests/test_nb_multi_split_d5.py +66 -0
  249. peakatail-0.3.0/tests/test_nb_offset_full_matrix_i94.py +226 -0
  250. peakatail-0.3.0/tests/test_nb_regression.py +510 -0
  251. peakatail-0.3.0/tests/test_outputs_atomic_writers.py +139 -0
  252. peakatail-0.3.0/tests/test_outputs_concat_beds.py +52 -0
  253. peakatail-0.3.0/tests/test_pair_parallel.py +262 -0
  254. peakatail-0.3.0/tests/test_pas_features.py +893 -0
  255. peakatail-0.3.0/tests/test_pas_gene_artifacts_atomic_write.py +167 -0
  256. peakatail-0.3.0/tests/test_pas_gene_overlapping_loci_i99.py +420 -0
  257. peakatail-0.3.0/tests/test_pas_gene_rescue.py +179 -0
  258. peakatail-0.3.0/tests/test_pas_merge.py +204 -0
  259. peakatail-0.3.0/tests/test_pas_merge_strand_b1.py +151 -0
  260. peakatail-0.3.0/tests/test_pas_score.py +558 -0
  261. peakatail-0.3.0/tests/test_pas_to_isoform.py +396 -0
  262. peakatail-0.3.0/tests/test_pas_to_isoform_spliced_dedup.py +197 -0
  263. peakatail-0.3.0/tests/test_pas_uid_e1.py +47 -0
  264. peakatail-0.3.0/tests/test_pasbed_status_columns_d9.py +133 -0
  265. peakatail-0.3.0/tests/test_pdui_strategies.py +477 -0
  266. peakatail-0.3.0/tests/test_peakcall_grid_ip_dedup.py +96 -0
  267. peakatail-0.3.0/tests/test_polya_clip_evidence_units.py +464 -0
  268. peakatail-0.3.0/tests/test_polya_clip_site.py +237 -0
  269. peakatail-0.3.0/tests/test_polya_clustering.py +271 -0
  270. peakatail-0.3.0/tests/test_polya_three_path_agreement.py +299 -0
  271. peakatail-0.3.0/tests/test_polya_tier1_counts.py +485 -0
  272. peakatail-0.3.0/tests/test_polya_two_tier_integration.py +449 -0
  273. peakatail-0.3.0/tests/test_prime_compat_flags.py +538 -0
  274. peakatail-0.3.0/tests/test_prime_dynamic_threshold_clamp.py +315 -0
  275. peakatail-0.3.0/tests/test_prime_ip_default_mode.py +355 -0
  276. peakatail-0.3.0/tests/test_prime_ip_escape_docs.py +220 -0
  277. peakatail-0.3.0/tests/test_prime_sidecar_merge_guard.py +143 -0
  278. peakatail-0.3.0/tests/test_prime_strand_implant.py +365 -0
  279. peakatail-0.3.0/tests/test_prime_v2_compat_golden.py +371 -0
  280. peakatail-0.3.0/tests/test_progress.py +71 -0
  281. peakatail-0.3.0/tests/test_provenance.py +221 -0
  282. peakatail-0.3.0/tests/test_provenance_atlas_ip_d9.py +110 -0
  283. peakatail-0.3.0/tests/test_provenance_invariant_e3.py +85 -0
  284. peakatail-0.3.0/tests/test_provenance_reconcile_e3.py +107 -0
  285. peakatail-0.3.0/tests/test_provenance_wiring_e3.py +121 -0
  286. peakatail-0.3.0/tests/test_pyproject_install.py +118 -0
  287. peakatail-0.3.0/tests/test_ram_adaptive_tile.py +253 -0
  288. peakatail-0.3.0/tests/test_read_check_fastpath.py +158 -0
  289. peakatail-0.3.0/tests/test_read_geometry.py +422 -0
  290. peakatail-0.3.0/tests/test_reannotate_cmd.py +573 -0
  291. peakatail-0.3.0/tests/test_reannotate_out_dir_guard.py +105 -0
  292. peakatail-0.3.0/tests/test_region_fetch.py +248 -0
  293. peakatail-0.3.0/tests/test_release_packaging.py +273 -0
  294. peakatail-0.3.0/tests/test_repair_gene_id.py +45 -0
  295. peakatail-0.3.0/tests/test_resource_manager.py +269 -0
  296. peakatail-0.3.0/tests/test_rg_sample_id_bijection.py +422 -0
  297. peakatail-0.3.0/tests/test_run_config_b0.py +67 -0
  298. peakatail-0.3.0/tests/test_run_diff_isoform.py +434 -0
  299. peakatail-0.3.0/tests/test_run_manifest_e2.py +132 -0
  300. peakatail-0.3.0/tests/test_state_encapsulation.py +383 -0
  301. peakatail-0.3.0/tests/test_sweep_analysis.py +610 -0
  302. peakatail-0.3.0/tests/test_switch_combine_a2.py +136 -0
  303. peakatail-0.3.0/tests/test_switch_diff_isoform_agg_scope.py +312 -0
  304. peakatail-0.3.0/tests/test_switch_length_degenerate_pairs.py +253 -0
  305. peakatail-0.3.0/tests/test_switch_length_strand_and_counts.py +305 -0
  306. peakatail-0.3.0/tests/test_switch_pasbed_resolve_b4.py +48 -0
  307. peakatail-0.3.0/tests/test_switch_trend_a3.py +238 -0
  308. peakatail-0.3.0/tests/test_tfidf_sparse_identity.py +114 -0
  309. peakatail-0.3.0/tests/test_trend_metrics.py +321 -0
  310. peakatail-0.3.0/tests/test_version_sync.py +132 -0
  311. peakatail-0.3.0/tests/test_viz_registry.py +58 -0
  312. peakatail-0.3.0/tests/test_viz_strategies_smoke.py +57 -0
  313. peakatail-0.3.0/tests/test_viz_tier2_smoke.py +199 -0
  314. peakatail-0.3.0/tests/test_viz_tier3_smoke.py +253 -0
  315. peakatail-0.3.0/tests/test_viz_tier4_smoke.py +278 -0
  316. peakatail-0.3.0/tests/test_wizard_e2e.py +226 -0
  317. peakatail-0.3.0/tests/test_yaml_loader.py +103 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BMGLab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,337 @@
1
+ Metadata-Version: 2.4
2
+ Name: peakatail
3
+ Version: 0.3.0
4
+ Summary: PeakATail — single-cell poly(A) site detection and APA analysis
5
+ Author-email: Amir Amiri Tabat <amiramiritabat01@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/BMGLab/PeakATail
8
+ Project-URL: Repository, https://github.com/BMGLab/PeakATail
9
+ Keywords: bioinformatics,scRNA-seq,polyadenylation,APA
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
13
+ Requires-Python: >=3.11
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: pysam>=0.22
17
+ Requires-Dist: anndata>=0.10
18
+ Requires-Dist: scanpy>=1.10
19
+ Requires-Dist: pandas>=2.1
20
+ Requires-Dist: scipy>=1.11
21
+ Requires-Dist: numpy>=1.26
22
+ Requires-Dist: igraph>=0.11
23
+ Requires-Dist: leidenalg>=0.10
24
+ Requires-Dist: louvain>=0.8.0
25
+ Requires-Dist: pybedtools>=0.10
26
+ Requires-Dist: psutil>=5.9
27
+ Requires-Dist: PyYAML>=6.0
28
+ Requires-Dist: joblib>=1.3
29
+ Requires-Dist: statsmodels>=0.14
30
+ Requires-Dist: sortedcontainers>=2.4
31
+ Requires-Dist: pyarrow>=15.0
32
+ Requires-Dist: tqdm>=4.66
33
+ Requires-Dist: click>=8.1
34
+ Requires-Dist: rich>=13.7
35
+ Requires-Dist: questionary>=2.0
36
+ Requires-Dist: matplotlib>=3.8
37
+ Requires-Dist: seaborn>=0.13
38
+ Requires-Dist: plotly>=5.18
39
+ Requires-Dist: kaleido>=0.2.1
40
+ Requires-Dist: upsetplot>=0.9
41
+ Provides-Extra: test
42
+ Requires-Dist: pytest>=8; extra == "test"
43
+ Requires-Dist: pytest-timeout>=2.4; extra == "test"
44
+ Requires-Dist: pyfaidx>=0.7; extra == "test"
45
+ Provides-Extra: dev
46
+ Requires-Dist: pytest>=8; extra == "dev"
47
+ Requires-Dist: pytest-timeout>=2.4; extra == "dev"
48
+ Requires-Dist: ruff>=0.4; extra == "dev"
49
+ Requires-Dist: mypy>=1.10; extra == "dev"
50
+ Provides-Extra: all
51
+ Requires-Dist: peakatail[dev]; extra == "all"
52
+ Dynamic: license-file
53
+
54
+ # PeakATail
55
+
56
+ <p align="center">
57
+ <img src="https://raw.githubusercontent.com/BMGLab/PeakATail/develop/docs/assets/logos/main_logo.png" alt="PeakATail — coiled snake with poly(A) tail" width="640">
58
+ </p>
59
+
60
+ PeakATail is a Python tool for single-cell poly(A) site (PAS) detection and alternative polyadenylation (APA) analysis. It works with any scRNA-seq BAM that carries a `CB:Z` (corrected cell barcode) tag — STARsolo, CellRanger, Alevin-fry, or any aligner that emits the standard 10x-style tag schema. UMI (`UB:Z`) tags are NOT required or used: PeakATail counts raw read 3'ends, not UMI-deduplicated molecules. PeakATail does NOT correct barcodes; your aligner must apply a barcode whitelist (e.g. STARsolo's `--soloCBwhitelist`). From the input BAM it calls polyadenylation sites at the read level, builds a per-cell PAS count matrix, clusters cells by their APA profiles, and provides downstream analyses including differential APA testing between clusters, 3'UTR length quantification, and cross-dataset cluster matching. Developed at BMGLab.
61
+
62
+ [![Docs](https://img.shields.io/badge/docs-bmglab.github.io%2FPeakATail-blue)](https://bmglab.github.io/PeakATail/)
63
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
64
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](pyproject.toml)
65
+
66
+ <!-- TODO[verify]: A CI workflow badge is not included because the repository currently contains only a docs-deploy workflow (.github/workflows/docs.yml). Add a badge once a CI workflow (e.g. .github/workflows/ci.yml) is committed. -->
67
+
68
+ ---
69
+
70
+ ## Quick install
71
+
72
+ ### System prerequisites
73
+
74
+ PeakATail calls `samtools` and `bedtools` as subprocesses. Both must be on your `PATH` before running the pipeline.
75
+
76
+ ```bash
77
+ # Debian/Ubuntu
78
+ sudo apt-get install samtools bedtools
79
+
80
+ # macOS (Homebrew)
81
+ brew install samtools bedtools
82
+ ```
83
+
84
+ The code has been tested against samtools >= 1.10 (enforced at runtime in `ema/datasets/manager.py`).
85
+
86
+ ### Python version
87
+
88
+ Python **3.11 or later** is required (declared in `pyproject.toml` as `requires-python = ">=3.11"`).
89
+
90
+ ### Install from source
91
+
92
+ ```bash
93
+ git clone https://github.com/BMGLab/PeakATail.git
94
+ cd PeakATail
95
+
96
+ # Create and activate a virtual environment
97
+ python3.11 -m venv .venv
98
+ source .venv/bin/activate
99
+
100
+ # Install with uv (recommended — matches the development environment)
101
+ pip install uv
102
+ uv pip install -e .
103
+
104
+ # Or with plain pip
105
+ pip install -e .
106
+ ```
107
+
108
+ All Python dependencies are declared in `pyproject.toml` and installed automatically.
109
+
110
+ ---
111
+
112
+ ## Quick start
113
+
114
+ ```bash
115
+ # Step 1: copy the example config and edit paths
116
+ cp example.yaml my_run.yaml
117
+ # Edit my_run.yaml — set datasets[].bams, gtf, seqlen, cb_len, barcode_tag
118
+
119
+ # Step 2: run the full pipeline (peak calling → annotation → clustering)
120
+ uv run peakatail run --config my_run.yaml --threads 4
121
+
122
+ # Step 3: differential APA between every cluster pair
123
+ uv run peakatail switch diff \
124
+ -i peakatail_runs/<run>/per_dataset/<ds>/clusters.h5ad \
125
+ --pasbed peakatail_runs/<run>/per_dataset/<ds>/pasbed.bed \
126
+ --strategy fisher
127
+
128
+ # Step 4: 3'UTR length quantification across clusters
129
+ uv run peakatail switch length \
130
+ -i peakatail_runs/<run>/per_dataset/<ds>/clusters.h5ad \
131
+ --strategy classic
132
+ ```
133
+
134
+ The pipeline writes all output under `peakatail_runs/<name>_<timestamp>/`. A typical run directory looks like:
135
+
136
+ ```
137
+ peakatail_runs/emaout_20240501_143022/
138
+ run_config.json # full resolved parameters
139
+ peakatail_<ts>.log # structured run log
140
+ per_dataset/
141
+ <dataset_id>/
142
+ raw/ # pre-filter BEDs and matrices
143
+ posbed.bed # filtered positive-strand PAS BED
144
+ negbed.bed # filtered negative-strand PAS BED
145
+ pasbed.bed # combined filtered PAS BED (both strands)
146
+ filtered_cb.tsv # barcodes that passed min_read filter
147
+ pas_gene.tsv # PAS-to-gene mapping table
148
+ annotatedpas.bed # pasbed.bed extended with gene_id column
149
+ annotated_matrix.mtx # post-annotation count matrix (MatrixMarket)
150
+ annotated_pas_ids.tsv # row index for annotated_matrix.mtx
151
+ annotated_cells.tsv # column index for annotated_matrix.mtx
152
+ preprocessed.h5ad # filtered AnnData before clustering
153
+ clusters.h5ad # AnnData with leiden cluster labels
154
+ switch_diff_<ts>/ # output of `peakatail switch diff` (auto-routed)
155
+ switch_length_<ts>/ # output of `peakatail switch length` (auto-routed)
156
+ switch_match_<ts>/ # output of `peakatail switch match` (auto-routed)
157
+ switch_geneview_<ts>/ # output of `peakatail switch geneview` (auto-routed)
158
+ ```
159
+
160
+ ---
161
+
162
+ ## What PeakATail produces
163
+
164
+ ### Peak calling stage
165
+
166
+ | File | Location | Description |
167
+ |---|---|---|
168
+ | `raw/pos.bed` | `per_dataset/<ds>/raw/` | Unfiltered positive-strand PAS calls (concatenated across BAM replicates) |
169
+ | `raw/neg.bed` | `per_dataset/<ds>/raw/` | Unfiltered negative-strand PAS calls |
170
+ | `raw/pas.bed` | `per_dataset/<ds>/raw/` | Union of raw pos + neg BED (pre-filter) |
171
+ | `raw/pos.mtx` | `per_dataset/<ds>/raw/` | Raw count matrix, positive strand (MatrixMarket) |
172
+ | `raw/neg.mtx` | `per_dataset/<ds>/raw/` | Raw count matrix, negative strand (MatrixMarket) |
173
+ | `raw/cb.tsv` | `per_dataset/<ds>/raw/` | Raw cell-barcode index aligned to raw MTX columns |
174
+ | `posbed.bed` | `per_dataset/<ds>/` | Filtered positive-strand PAS BED |
175
+ | `negbed.bed` | `per_dataset/<ds>/` | Filtered negative-strand PAS BED |
176
+ | `pasbed.bed` | `per_dataset/<ds>/` | Combined filtered PAS BED (both strands); used as input for downstream commands |
177
+ | `filtered_cb.tsv` | `per_dataset/<ds>/` | Barcodes that passed the `min_read` filter, with filter threshold in header |
178
+
179
+ ### Annotation stage
180
+
181
+ | File | Location | Description |
182
+ |---|---|---|
183
+ | `pas_gene.tsv` | `per_dataset/<ds>/` | Two-column table: `pas_id`, `gene_id` |
184
+ | `annotatedpas.bed` | `per_dataset/<ds>/` | `pasbed.bed` extended with a trailing `gene_id` column |
185
+ | `annotated_matrix.mtx` | `per_dataset/<ds>/` | MatrixMarket sparse count matrix (rows = annotated PAS, cols = cells) |
186
+ | `annotated_pas_ids.tsv` | `per_dataset/<ds>/` | Row index for `annotated_matrix.mtx` |
187
+ | `annotated_cells.tsv` | `per_dataset/<ds>/` | Column index for `annotated_matrix.mtx` |
188
+
189
+ ### Clustering stage
190
+
191
+ | File | Location | Description |
192
+ |---|---|---|
193
+ | `preprocessed.h5ad` | `per_dataset/<ds>/` | AnnData after cell/PAS filtering, before cluster labels are assigned |
194
+ | `clusters.h5ad` | `per_dataset/<ds>/` | AnnData with `leiden` cluster labels in `.obs`; primary input for all `switch` subcommands |
195
+
196
+ ### Differential APA stage (`peakatail switch diff`)
197
+
198
+ | File | Location | Description |
199
+ |---|---|---|
200
+ | `diff_<c1>_vs_<c2>.tsv` | `switch_diff_<ts>/` | Per-cluster-pair differential APA results table |
201
+ | `cluster_match.tsv` | `switch_match_<ts>/` | Cross-dataset cluster correspondence scores (`peakatail switch match`) |
202
+ | `pdui_classic.tsv` | `switch_length_<ts>/` | Per-cell PDUI scores when strategy is `classic` |
203
+ | `proportion.tsv` | `switch_length_<ts>/` | Per-cell per-PAS proportion scores when strategy is `proportion` |
204
+ | `entropy_shannon.tsv` | `switch_length_<ts>/` | Per-cell Shannon entropy scores when strategy is `shannon` |
205
+
206
+ ---
207
+
208
+ ## Available CLI commands
209
+
210
+ All commands are accessed through the `peakatail` entry point installed by `pip install -e .`. The old `ema` command still works as a deprecated alias.
211
+
212
+ | Command | Description | Docs |
213
+ |---|---|---|
214
+ | `peakatail run` | Run the full pipeline: peak calling, annotation, clustering | [cli/run](https://bmglab.github.io/PeakATail/cli/run/) |
215
+ | `peakatail reannotate` | Branch a finished run into a new trim/filter/clustering variant without re-peak-calling | [cli/reannotate](https://bmglab.github.io/PeakATail/cli/reannotate/) |
216
+ | `peakatail switch diff` | Differential APA test across cluster pairs (Fisher / NB regression) | [cli/switch-diff](https://bmglab.github.io/PeakATail/cli/switch-diff/) |
217
+ | `peakatail switch length` | 3'UTR shortening/lengthening quantification (PDUI variants) | [cli/switch-length](https://bmglab.github.io/PeakATail/cli/switch-length/) |
218
+ | `peakatail switch trend` | Ordered-covariate (e.g. stage-progression) APA-length trend: slope + Spearman + direction | [cli](https://bmglab.github.io/PeakATail/cli/) |
219
+ | `peakatail switch combine` | Stitch stage/celltype-labelled `clusters.h5ad` files into one grouped h5ad for cross-group testing | [cli](https://bmglab.github.io/PeakATail/cli/) |
220
+ | `peakatail switch match` | Cross-dataset cluster matching | [cli/switch-match](https://bmglab.github.io/PeakATail/cli/switch-match/) |
221
+ | `peakatail switch geneview` | Gene-track visualisation: per-cluster PAS coverage and proportions | [cli/switch-geneview](https://bmglab.github.io/PeakATail/cli/switch-geneview/) |
222
+ | `peakatail collapse` | Pool `samtools merge` RG-suffixed run tags back into per-library cells | [cli](https://bmglab.github.io/PeakATail/cli/) |
223
+ | `peakatail merge` | Merge multiple BAM files into one sorted and indexed BAM | [cli/merge](https://bmglab.github.io/PeakATail/cli/merge/) |
224
+ | `peakatail parse-gtf` | Pre-warm the GTF cache so subsequent runs start immediately | [cli/parse-gtf](https://bmglab.github.io/PeakATail/cli/parse-gtf/) |
225
+ | `peakatail wizard` | Interactive setup wizard (also invoked by bare `ema`) | [cli/wizard](https://bmglab.github.io/PeakATail/cli/wizard/) |
226
+
227
+ Use `--list-strategies` on `peakatail run`, `peakatail switch diff`, `peakatail switch length`, and `peakatail switch match` to see the strategies registered in the current installation.
228
+
229
+ Every command accepts `--help` for full flag documentation.
230
+
231
+ ---
232
+
233
+ ## Available strategies
234
+
235
+ ### Peak calling (`peakatail run --peak-strategy`)
236
+
237
+ | Name | Description |
238
+ |---|---|
239
+ | `original` | Wraps the original `pasfind()` logic unchanged; used as a baseline for comparison |
240
+ | `lambda_poisson` | MACS2-style: Poisson p-value against a local lambda estimated from floor positions |
241
+ | `sierra_iterative` | Sierra-style iterative peak subtraction; finds multiple PAS per UTR |
242
+ | `lambda_gradient` | Local-lambda estimation combined with gradient-based peak delineation |
243
+
244
+ ### Clustering (`peakatail run --cluster-method`)
245
+
246
+ | Name | Description |
247
+ |---|---|
248
+ | `leiden_tfidf` | TF-IDF normalisation followed by LSI dimensionality reduction and Leiden community detection |
249
+ | `leiden_libsize` | Library-size normalisation followed by PCA and Leiden community detection |
250
+ | `external` | Load pre-computed cluster labels from a file instead of running clustering |
251
+
252
+ ### Cross-dataset cluster matching (`peakatail switch match --strategy` / `peakatail run --match-method`)
253
+
254
+ | Name | Description |
255
+ |---|---|
256
+ | `marker_overlap` | Match clusters by overlap of top marker PAS sets |
257
+ | `jaccard` | Match clusters by Jaccard similarity of cell sets |
258
+ | `mnn` | Mutual nearest neighbours in a shared LSI embedding |
259
+
260
+ ### 3'UTR length quantification (`peakatail switch length --strategy`)
261
+
262
+ | Name | Output file | Description |
263
+ |---|---|---|
264
+ | `classic` | `pdui_classic.tsv` | Classic 2-PAS PDUI: distal_count / (proximal + distal); proximal/distal selected by genomic or transcript-coordinate rank |
265
+ | `proportion` | `proportion.tsv` | Per-PAS proportion vector: reads per PAS as fraction of gene total per cell |
266
+ | `shannon` | `entropy_shannon.tsv` | Shannon entropy of the per-PAS proportion distribution per (gene, cell) |
267
+
268
+ ### Differential APA testing (`peakatail switch diff --strategy`)
269
+
270
+ | Name | Description |
271
+ |---|---|
272
+ | `fisher` | Fisher's exact test on per-PAS read counts between two cluster groups |
273
+ | `nb_pairwise` | Negative binomial regression, pairwise cluster comparison |
274
+ | `nb_multi` | Negative binomial regression, multi-condition |
275
+
276
+ ---
277
+
278
+ ## Documentation
279
+
280
+ Full docs: **https://bmglab.github.io/PeakATail/**
281
+
282
+ The MkDocs documentation site is built automatically from the `develop` and `main` branches via the `.github/workflows/docs.yml` GitHub Actions workflow and published to GitHub Pages.
283
+
284
+ ---
285
+
286
+ ## Repository layout
287
+
288
+ ```
289
+ PeakATail/
290
+ ema/ # core Python package (entry point: ema.cli:main)
291
+ cli/ # Click subcommands and config schema
292
+ strategies/ # peak-calling strategy registry
293
+ clustering/ # clustering strategies and cross-dataset matching
294
+ quantification/ # PDUI / proportion / entropy strategies
295
+ switch_test/ # differential APA testing strategies
296
+ outputs.py # all file I/O for the pipeline
297
+ main.py # pipeline orchestration
298
+ downstream_runner.py# per-dataset worker (safe for multiprocessing)
299
+ data/ # example data files
300
+ test/ # test suite (pytest)
301
+ other_repos/ # reference implementations (Sierra, SCAPE, scTail, etc.)
302
+ example.yaml # canonical YAML config template
303
+ combined_polya_scrna_methods.csv # comparison of poly(A) scRNA methods
304
+ pyproject.toml # package metadata, dependencies, entry points
305
+ ROADMAP.md # development and publication roadmap
306
+ LICENSE # MIT License
307
+ Dockerfile # container build
308
+ ```
309
+
310
+ ---
311
+
312
+ ## Citation
313
+
314
+ If you use PeakATail, please cite the software entry below for now. The `author`
315
+ field mirrors the package author declared in `pyproject.toml`; the full
316
+ manuscript author list and a machine-readable `CITATION.cff` will be added with
317
+ the paper release (tracked in the release-engineering issue).
318
+
319
+ <!-- TODO[verify]: No CITATION.cff file exists yet. Replace this software entry
320
+ with the published journal citation — and expand `author` to the full manuscript
321
+ author list — once the paper is out. -->
322
+
323
+ ```bibtex
324
+ @software{peakatail,
325
+ author = {Amiri Tabat, Amir},
326
+ title = {{PeakATail}: single-cell poly(A) site detection and APA analysis},
327
+ url = {https://github.com/BMGLab/PeakATail},
328
+ version = {0.3.0},
329
+ note = {Preprint in preparation; replace with the journal citation when available}
330
+ }
331
+ ```
332
+
333
+ ---
334
+
335
+ ## License
336
+
337
+ This project is licensed under the **MIT License** — see the [LICENSE](LICENSE) file for the full text. `pyproject.toml` declares the matching SPDX identifier (`license = "MIT"`).
@@ -0,0 +1,284 @@
1
+ # PeakATail
2
+
3
+ <p align="center">
4
+ <img src="https://raw.githubusercontent.com/BMGLab/PeakATail/develop/docs/assets/logos/main_logo.png" alt="PeakATail — coiled snake with poly(A) tail" width="640">
5
+ </p>
6
+
7
+ PeakATail is a Python tool for single-cell poly(A) site (PAS) detection and alternative polyadenylation (APA) analysis. It works with any scRNA-seq BAM that carries a `CB:Z` (corrected cell barcode) tag — STARsolo, CellRanger, Alevin-fry, or any aligner that emits the standard 10x-style tag schema. UMI (`UB:Z`) tags are NOT required or used: PeakATail counts raw read 3'ends, not UMI-deduplicated molecules. PeakATail does NOT correct barcodes; your aligner must apply a barcode whitelist (e.g. STARsolo's `--soloCBwhitelist`). From the input BAM it calls polyadenylation sites at the read level, builds a per-cell PAS count matrix, clusters cells by their APA profiles, and provides downstream analyses including differential APA testing between clusters, 3'UTR length quantification, and cross-dataset cluster matching. Developed at BMGLab.
8
+
9
+ [![Docs](https://img.shields.io/badge/docs-bmglab.github.io%2FPeakATail-blue)](https://bmglab.github.io/PeakATail/)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
11
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](pyproject.toml)
12
+
13
+ <!-- TODO[verify]: A CI workflow badge is not included because the repository currently contains only a docs-deploy workflow (.github/workflows/docs.yml). Add a badge once a CI workflow (e.g. .github/workflows/ci.yml) is committed. -->
14
+
15
+ ---
16
+
17
+ ## Quick install
18
+
19
+ ### System prerequisites
20
+
21
+ PeakATail calls `samtools` and `bedtools` as subprocesses. Both must be on your `PATH` before running the pipeline.
22
+
23
+ ```bash
24
+ # Debian/Ubuntu
25
+ sudo apt-get install samtools bedtools
26
+
27
+ # macOS (Homebrew)
28
+ brew install samtools bedtools
29
+ ```
30
+
31
+ The code has been tested against samtools >= 1.10 (enforced at runtime in `ema/datasets/manager.py`).
32
+
33
+ ### Python version
34
+
35
+ Python **3.11 or later** is required (declared in `pyproject.toml` as `requires-python = ">=3.11"`).
36
+
37
+ ### Install from source
38
+
39
+ ```bash
40
+ git clone https://github.com/BMGLab/PeakATail.git
41
+ cd PeakATail
42
+
43
+ # Create and activate a virtual environment
44
+ python3.11 -m venv .venv
45
+ source .venv/bin/activate
46
+
47
+ # Install with uv (recommended — matches the development environment)
48
+ pip install uv
49
+ uv pip install -e .
50
+
51
+ # Or with plain pip
52
+ pip install -e .
53
+ ```
54
+
55
+ All Python dependencies are declared in `pyproject.toml` and installed automatically.
56
+
57
+ ---
58
+
59
+ ## Quick start
60
+
61
+ ```bash
62
+ # Step 1: copy the example config and edit paths
63
+ cp example.yaml my_run.yaml
64
+ # Edit my_run.yaml — set datasets[].bams, gtf, seqlen, cb_len, barcode_tag
65
+
66
+ # Step 2: run the full pipeline (peak calling → annotation → clustering)
67
+ uv run peakatail run --config my_run.yaml --threads 4
68
+
69
+ # Step 3: differential APA between every cluster pair
70
+ uv run peakatail switch diff \
71
+ -i peakatail_runs/<run>/per_dataset/<ds>/clusters.h5ad \
72
+ --pasbed peakatail_runs/<run>/per_dataset/<ds>/pasbed.bed \
73
+ --strategy fisher
74
+
75
+ # Step 4: 3'UTR length quantification across clusters
76
+ uv run peakatail switch length \
77
+ -i peakatail_runs/<run>/per_dataset/<ds>/clusters.h5ad \
78
+ --strategy classic
79
+ ```
80
+
81
+ The pipeline writes all output under `peakatail_runs/<name>_<timestamp>/`. A typical run directory looks like:
82
+
83
+ ```
84
+ peakatail_runs/emaout_20240501_143022/
85
+ run_config.json # full resolved parameters
86
+ peakatail_<ts>.log # structured run log
87
+ per_dataset/
88
+ <dataset_id>/
89
+ raw/ # pre-filter BEDs and matrices
90
+ posbed.bed # filtered positive-strand PAS BED
91
+ negbed.bed # filtered negative-strand PAS BED
92
+ pasbed.bed # combined filtered PAS BED (both strands)
93
+ filtered_cb.tsv # barcodes that passed min_read filter
94
+ pas_gene.tsv # PAS-to-gene mapping table
95
+ annotatedpas.bed # pasbed.bed extended with gene_id column
96
+ annotated_matrix.mtx # post-annotation count matrix (MatrixMarket)
97
+ annotated_pas_ids.tsv # row index for annotated_matrix.mtx
98
+ annotated_cells.tsv # column index for annotated_matrix.mtx
99
+ preprocessed.h5ad # filtered AnnData before clustering
100
+ clusters.h5ad # AnnData with leiden cluster labels
101
+ switch_diff_<ts>/ # output of `peakatail switch diff` (auto-routed)
102
+ switch_length_<ts>/ # output of `peakatail switch length` (auto-routed)
103
+ switch_match_<ts>/ # output of `peakatail switch match` (auto-routed)
104
+ switch_geneview_<ts>/ # output of `peakatail switch geneview` (auto-routed)
105
+ ```
106
+
107
+ ---
108
+
109
+ ## What PeakATail produces
110
+
111
+ ### Peak calling stage
112
+
113
+ | File | Location | Description |
114
+ |---|---|---|
115
+ | `raw/pos.bed` | `per_dataset/<ds>/raw/` | Unfiltered positive-strand PAS calls (concatenated across BAM replicates) |
116
+ | `raw/neg.bed` | `per_dataset/<ds>/raw/` | Unfiltered negative-strand PAS calls |
117
+ | `raw/pas.bed` | `per_dataset/<ds>/raw/` | Union of raw pos + neg BED (pre-filter) |
118
+ | `raw/pos.mtx` | `per_dataset/<ds>/raw/` | Raw count matrix, positive strand (MatrixMarket) |
119
+ | `raw/neg.mtx` | `per_dataset/<ds>/raw/` | Raw count matrix, negative strand (MatrixMarket) |
120
+ | `raw/cb.tsv` | `per_dataset/<ds>/raw/` | Raw cell-barcode index aligned to raw MTX columns |
121
+ | `posbed.bed` | `per_dataset/<ds>/` | Filtered positive-strand PAS BED |
122
+ | `negbed.bed` | `per_dataset/<ds>/` | Filtered negative-strand PAS BED |
123
+ | `pasbed.bed` | `per_dataset/<ds>/` | Combined filtered PAS BED (both strands); used as input for downstream commands |
124
+ | `filtered_cb.tsv` | `per_dataset/<ds>/` | Barcodes that passed the `min_read` filter, with filter threshold in header |
125
+
126
+ ### Annotation stage
127
+
128
+ | File | Location | Description |
129
+ |---|---|---|
130
+ | `pas_gene.tsv` | `per_dataset/<ds>/` | Two-column table: `pas_id`, `gene_id` |
131
+ | `annotatedpas.bed` | `per_dataset/<ds>/` | `pasbed.bed` extended with a trailing `gene_id` column |
132
+ | `annotated_matrix.mtx` | `per_dataset/<ds>/` | MatrixMarket sparse count matrix (rows = annotated PAS, cols = cells) |
133
+ | `annotated_pas_ids.tsv` | `per_dataset/<ds>/` | Row index for `annotated_matrix.mtx` |
134
+ | `annotated_cells.tsv` | `per_dataset/<ds>/` | Column index for `annotated_matrix.mtx` |
135
+
136
+ ### Clustering stage
137
+
138
+ | File | Location | Description |
139
+ |---|---|---|
140
+ | `preprocessed.h5ad` | `per_dataset/<ds>/` | AnnData after cell/PAS filtering, before cluster labels are assigned |
141
+ | `clusters.h5ad` | `per_dataset/<ds>/` | AnnData with `leiden` cluster labels in `.obs`; primary input for all `switch` subcommands |
142
+
143
+ ### Differential APA stage (`peakatail switch diff`)
144
+
145
+ | File | Location | Description |
146
+ |---|---|---|
147
+ | `diff_<c1>_vs_<c2>.tsv` | `switch_diff_<ts>/` | Per-cluster-pair differential APA results table |
148
+ | `cluster_match.tsv` | `switch_match_<ts>/` | Cross-dataset cluster correspondence scores (`peakatail switch match`) |
149
+ | `pdui_classic.tsv` | `switch_length_<ts>/` | Per-cell PDUI scores when strategy is `classic` |
150
+ | `proportion.tsv` | `switch_length_<ts>/` | Per-cell per-PAS proportion scores when strategy is `proportion` |
151
+ | `entropy_shannon.tsv` | `switch_length_<ts>/` | Per-cell Shannon entropy scores when strategy is `shannon` |
152
+
153
+ ---
154
+
155
+ ## Available CLI commands
156
+
157
+ All commands are accessed through the `peakatail` entry point installed by `pip install -e .`. The old `ema` command still works as a deprecated alias.
158
+
159
+ | Command | Description | Docs |
160
+ |---|---|---|
161
+ | `peakatail run` | Run the full pipeline: peak calling, annotation, clustering | [cli/run](https://bmglab.github.io/PeakATail/cli/run/) |
162
+ | `peakatail reannotate` | Branch a finished run into a new trim/filter/clustering variant without re-peak-calling | [cli/reannotate](https://bmglab.github.io/PeakATail/cli/reannotate/) |
163
+ | `peakatail switch diff` | Differential APA test across cluster pairs (Fisher / NB regression) | [cli/switch-diff](https://bmglab.github.io/PeakATail/cli/switch-diff/) |
164
+ | `peakatail switch length` | 3'UTR shortening/lengthening quantification (PDUI variants) | [cli/switch-length](https://bmglab.github.io/PeakATail/cli/switch-length/) |
165
+ | `peakatail switch trend` | Ordered-covariate (e.g. stage-progression) APA-length trend: slope + Spearman + direction | [cli](https://bmglab.github.io/PeakATail/cli/) |
166
+ | `peakatail switch combine` | Stitch stage/celltype-labelled `clusters.h5ad` files into one grouped h5ad for cross-group testing | [cli](https://bmglab.github.io/PeakATail/cli/) |
167
+ | `peakatail switch match` | Cross-dataset cluster matching | [cli/switch-match](https://bmglab.github.io/PeakATail/cli/switch-match/) |
168
+ | `peakatail switch geneview` | Gene-track visualisation: per-cluster PAS coverage and proportions | [cli/switch-geneview](https://bmglab.github.io/PeakATail/cli/switch-geneview/) |
169
+ | `peakatail collapse` | Pool `samtools merge` RG-suffixed run tags back into per-library cells | [cli](https://bmglab.github.io/PeakATail/cli/) |
170
+ | `peakatail merge` | Merge multiple BAM files into one sorted and indexed BAM | [cli/merge](https://bmglab.github.io/PeakATail/cli/merge/) |
171
+ | `peakatail parse-gtf` | Pre-warm the GTF cache so subsequent runs start immediately | [cli/parse-gtf](https://bmglab.github.io/PeakATail/cli/parse-gtf/) |
172
+ | `peakatail wizard` | Interactive setup wizard (also invoked by bare `ema`) | [cli/wizard](https://bmglab.github.io/PeakATail/cli/wizard/) |
173
+
174
+ Use `--list-strategies` on `peakatail run`, `peakatail switch diff`, `peakatail switch length`, and `peakatail switch match` to see the strategies registered in the current installation.
175
+
176
+ Every command accepts `--help` for full flag documentation.
177
+
178
+ ---
179
+
180
+ ## Available strategies
181
+
182
+ ### Peak calling (`peakatail run --peak-strategy`)
183
+
184
+ | Name | Description |
185
+ |---|---|
186
+ | `original` | Wraps the original `pasfind()` logic unchanged; used as a baseline for comparison |
187
+ | `lambda_poisson` | MACS2-style: Poisson p-value against a local lambda estimated from floor positions |
188
+ | `sierra_iterative` | Sierra-style iterative peak subtraction; finds multiple PAS per UTR |
189
+ | `lambda_gradient` | Local-lambda estimation combined with gradient-based peak delineation |
190
+
191
+ ### Clustering (`peakatail run --cluster-method`)
192
+
193
+ | Name | Description |
194
+ |---|---|
195
+ | `leiden_tfidf` | TF-IDF normalisation followed by LSI dimensionality reduction and Leiden community detection |
196
+ | `leiden_libsize` | Library-size normalisation followed by PCA and Leiden community detection |
197
+ | `external` | Load pre-computed cluster labels from a file instead of running clustering |
198
+
199
+ ### Cross-dataset cluster matching (`peakatail switch match --strategy` / `peakatail run --match-method`)
200
+
201
+ | Name | Description |
202
+ |---|---|
203
+ | `marker_overlap` | Match clusters by overlap of top marker PAS sets |
204
+ | `jaccard` | Match clusters by Jaccard similarity of cell sets |
205
+ | `mnn` | Mutual nearest neighbours in a shared LSI embedding |
206
+
207
+ ### 3'UTR length quantification (`peakatail switch length --strategy`)
208
+
209
+ | Name | Output file | Description |
210
+ |---|---|---|
211
+ | `classic` | `pdui_classic.tsv` | Classic 2-PAS PDUI: distal_count / (proximal + distal); proximal/distal selected by genomic or transcript-coordinate rank |
212
+ | `proportion` | `proportion.tsv` | Per-PAS proportion vector: reads per PAS as fraction of gene total per cell |
213
+ | `shannon` | `entropy_shannon.tsv` | Shannon entropy of the per-PAS proportion distribution per (gene, cell) |
214
+
215
+ ### Differential APA testing (`peakatail switch diff --strategy`)
216
+
217
+ | Name | Description |
218
+ |---|---|
219
+ | `fisher` | Fisher's exact test on per-PAS read counts between two cluster groups |
220
+ | `nb_pairwise` | Negative binomial regression, pairwise cluster comparison |
221
+ | `nb_multi` | Negative binomial regression, multi-condition |
222
+
223
+ ---
224
+
225
+ ## Documentation
226
+
227
+ Full docs: **https://bmglab.github.io/PeakATail/**
228
+
229
+ The MkDocs documentation site is built automatically from the `develop` and `main` branches via the `.github/workflows/docs.yml` GitHub Actions workflow and published to GitHub Pages.
230
+
231
+ ---
232
+
233
+ ## Repository layout
234
+
235
+ ```
236
+ PeakATail/
237
+ ema/ # core Python package (entry point: ema.cli:main)
238
+ cli/ # Click subcommands and config schema
239
+ strategies/ # peak-calling strategy registry
240
+ clustering/ # clustering strategies and cross-dataset matching
241
+ quantification/ # PDUI / proportion / entropy strategies
242
+ switch_test/ # differential APA testing strategies
243
+ outputs.py # all file I/O for the pipeline
244
+ main.py # pipeline orchestration
245
+ downstream_runner.py# per-dataset worker (safe for multiprocessing)
246
+ data/ # example data files
247
+ test/ # test suite (pytest)
248
+ other_repos/ # reference implementations (Sierra, SCAPE, scTail, etc.)
249
+ example.yaml # canonical YAML config template
250
+ combined_polya_scrna_methods.csv # comparison of poly(A) scRNA methods
251
+ pyproject.toml # package metadata, dependencies, entry points
252
+ ROADMAP.md # development and publication roadmap
253
+ LICENSE # MIT License
254
+ Dockerfile # container build
255
+ ```
256
+
257
+ ---
258
+
259
+ ## Citation
260
+
261
+ If you use PeakATail, please cite the software entry below for now. The `author`
262
+ field mirrors the package author declared in `pyproject.toml`; the full
263
+ manuscript author list and a machine-readable `CITATION.cff` will be added with
264
+ the paper release (tracked in the release-engineering issue).
265
+
266
+ <!-- TODO[verify]: No CITATION.cff file exists yet. Replace this software entry
267
+ with the published journal citation — and expand `author` to the full manuscript
268
+ author list — once the paper is out. -->
269
+
270
+ ```bibtex
271
+ @software{peakatail,
272
+ author = {Amiri Tabat, Amir},
273
+ title = {{PeakATail}: single-cell poly(A) site detection and APA analysis},
274
+ url = {https://github.com/BMGLab/PeakATail},
275
+ version = {0.3.0},
276
+ note = {Preprint in preparation; replace with the journal citation when available}
277
+ }
278
+ ```
279
+
280
+ ---
281
+
282
+ ## License
283
+
284
+ This project is licensed under the **MIT License** — see the [LICENSE](LICENSE) file for the full text. `pyproject.toml` declares the matching SPDX identifier (`license = "MIT"`).
@@ -0,0 +1,22 @@
1
+ """PeakATail package init.
2
+
3
+ IMPORTANT: this module sets BLAS / OpenMP thread caps BEFORE any submodule
4
+ (or numpy/scipy/scanpy) gets imported. Without this, the multiprocessing
5
+ ``spawn`` Pool used by peak calling leaves the parent process's BLAS thread
6
+ pool in a state where downstream ``scanpy``/``leidenalg`` calls deadlock on
7
+ a futex inside OpenBLAS — observed as a hang at the clustering step on
8
+ datasets larger than a few hundred cells.
9
+
10
+ We default to single-threaded BLAS in the parent because (a) all heavy
11
+ matrix work is already parallelised at the multiprocessing level (one
12
+ worker per dataset / per tile), and (b) the parent process orchestrates
13
+ spawn workers — over-subscribing BLAS threads in the parent only competes
14
+ with worker CPU. Users who want multi-threaded BLAS for a specific call
15
+ can override by exporting these vars themselves before invoking ``ema``.
16
+ """
17
+ import os as _os
18
+
19
+ for _var in ("OMP_NUM_THREADS", "OPENBLAS_NUM_THREADS",
20
+ "MKL_NUM_THREADS", "BLIS_NUM_THREADS",
21
+ "VECLIB_MAXIMUM_THREADS", "NUMEXPR_NUM_THREADS"):
22
+ _os.environ.setdefault(_var, "1")