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.
- peakatail-0.3.0/LICENSE +21 -0
- peakatail-0.3.0/PKG-INFO +337 -0
- peakatail-0.3.0/README.md +284 -0
- peakatail-0.3.0/ema/__init__.py +22 -0
- peakatail-0.3.0/ema/__main__.py +16 -0
- peakatail-0.3.0/ema/annotate/__init__.py +0 -0
- peakatail-0.3.0/ema/annotate/annotate.py +120 -0
- peakatail-0.3.0/ema/annotate/find_close.py +389 -0
- peakatail-0.3.0/ema/annotate/gtf2isoform_utr.py +304 -0
- peakatail-0.3.0/ema/annotate/gtf_cache.py +390 -0
- peakatail-0.3.0/ema/annotate/gtftobed.py +136 -0
- peakatail-0.3.0/ema/benchmark/__init__.py +6 -0
- peakatail-0.3.0/ema/benchmark/cross_experiment.py +1215 -0
- peakatail-0.3.0/ema/benchmark/length_compare.py +367 -0
- peakatail-0.3.0/ema/benchmark/metrics.py +613 -0
- peakatail-0.3.0/ema/benchmark/report.py +86 -0
- peakatail-0.3.0/ema/benchmark/runner.py +236 -0
- peakatail-0.3.0/ema/benchmark/sweep_analysis.py +1377 -0
- peakatail-0.3.0/ema/benchmark/switch_diff_compare.py +368 -0
- peakatail-0.3.0/ema/benchmark/visualize.py +341 -0
- peakatail-0.3.0/ema/celltype/__init__.py +15 -0
- peakatail-0.3.0/ema/celltype/scoring.py +136 -0
- peakatail-0.3.0/ema/cli/__init__.py +192 -0
- peakatail-0.3.0/ema/cli/collapse.py +55 -0
- peakatail-0.3.0/ema/cli/common.py +350 -0
- peakatail-0.3.0/ema/cli/config_schema.py +1853 -0
- peakatail-0.3.0/ema/cli/defaults.py +34 -0
- peakatail-0.3.0/ema/cli/merge.py +55 -0
- peakatail-0.3.0/ema/cli/parse_gtf.py +74 -0
- peakatail-0.3.0/ema/cli/reannotate.py +180 -0
- peakatail-0.3.0/ema/cli/run.py +293 -0
- peakatail-0.3.0/ema/cli/switch.py +23 -0
- peakatail-0.3.0/ema/cli/switch_combine.py +83 -0
- peakatail-0.3.0/ema/cli/switch_diff.py +263 -0
- peakatail-0.3.0/ema/cli/switch_geneview.py +415 -0
- peakatail-0.3.0/ema/cli/switch_length.py +165 -0
- peakatail-0.3.0/ema/cli/switch_match.py +133 -0
- peakatail-0.3.0/ema/cli/switch_trend.py +295 -0
- peakatail-0.3.0/ema/cli/wizard.py +400 -0
- peakatail-0.3.0/ema/cli/yaml_loader.py +115 -0
- peakatail-0.3.0/ema/clustering/__init__.py +0 -0
- peakatail-0.3.0/ema/clustering/_builtins.py +26 -0
- peakatail-0.3.0/ema/clustering/clustering.py +259 -0
- peakatail-0.3.0/ema/clustering/cross_dataset/__init__.py +107 -0
- peakatail-0.3.0/ema/clustering/cross_dataset/base.py +82 -0
- peakatail-0.3.0/ema/clustering/cross_dataset/jaccard.py +234 -0
- peakatail-0.3.0/ema/clustering/cross_dataset/marker_overlap.py +414 -0
- peakatail-0.3.0/ema/clustering/cross_dataset/mnn.py +382 -0
- peakatail-0.3.0/ema/clustering/cross_dataset/roundtrip.py +92 -0
- peakatail-0.3.0/ema/clustering/evaluation.py +147 -0
- peakatail-0.3.0/ema/clustering/registry.py +32 -0
- peakatail-0.3.0/ema/clustering/strategies/__init__.py +36 -0
- peakatail-0.3.0/ema/clustering/strategies/base.py +57 -0
- peakatail-0.3.0/ema/clustering/strategies/external.py +103 -0
- peakatail-0.3.0/ema/clustering/strategies/leiden_libsize.py +108 -0
- peakatail-0.3.0/ema/clustering/strategies/leiden_tfidf.py +252 -0
- peakatail-0.3.0/ema/config.py +511 -0
- peakatail-0.3.0/ema/countmatrix/__init__.py +0 -0
- peakatail-0.3.0/ema/countmatrix/bam_utils.py +41 -0
- peakatail-0.3.0/ema/countmatrix/cb_encode.py +144 -0
- peakatail-0.3.0/ema/countmatrix/chrom_parallel.py +605 -0
- peakatail-0.3.0/ema/countmatrix/cleavage_offset.py +969 -0
- peakatail-0.3.0/ema/countmatrix/dynamic_threshold.py +188 -0
- peakatail-0.3.0/ema/countmatrix/indexing.py +273 -0
- peakatail-0.3.0/ema/countmatrix/models/pas_score_model_prime1.json +1 -0
- peakatail-0.3.0/ema/countmatrix/pas_features.py +605 -0
- peakatail-0.3.0/ema/countmatrix/pas_score.py +289 -0
- peakatail-0.3.0/ema/countmatrix/pasfind.py +1 -0
- peakatail-0.3.0/ema/countmatrix/paswrite.py +187 -0
- peakatail-0.3.0/ema/countmatrix/peackcalling.py +725 -0
- peakatail-0.3.0/ema/countmatrix/peak.py +207 -0
- peakatail-0.3.0/ema/countmatrix/peak_pipeline.py +821 -0
- peakatail-0.3.0/ema/countmatrix/peak_state.py +43 -0
- peakatail-0.3.0/ema/countmatrix/polya.py +1572 -0
- peakatail-0.3.0/ema/countmatrix/read.py +286 -0
- peakatail-0.3.0/ema/countmatrix/tile_runner.py +1192 -0
- peakatail-0.3.0/ema/data/__init__.py +13 -0
- peakatail-0.3.0/ema/data/run.py +533 -0
- peakatail-0.3.0/ema/datasets/__init__.py +1 -0
- peakatail-0.3.0/ema/datasets/atlas_annotate.py +236 -0
- peakatail-0.3.0/ema/datasets/atlas_snap.py +414 -0
- peakatail-0.3.0/ema/datasets/collapse.py +150 -0
- peakatail-0.3.0/ema/datasets/manager.py +131 -0
- peakatail-0.3.0/ema/datasets/pas_merge.py +450 -0
- peakatail-0.3.0/ema/downstream_runner.py +506 -0
- peakatail-0.3.0/ema/experimental/__init__.py +1 -0
- peakatail-0.3.0/ema/experimental/internal_priming.py +304 -0
- peakatail-0.3.0/ema/experimental/peak_filters.py +224 -0
- peakatail-0.3.0/ema/logging_config.py +174 -0
- peakatail-0.3.0/ema/main.py +2551 -0
- peakatail-0.3.0/ema/matrixfilter.py +557 -0
- peakatail-0.3.0/ema/merge_bam/__init__.py +0 -0
- peakatail-0.3.0/ema/merge_bam/merge.py +8 -0
- peakatail-0.3.0/ema/merge_bam/runner.py +32 -0
- peakatail-0.3.0/ema/outputs.py +783 -0
- peakatail-0.3.0/ema/progress.py +198 -0
- peakatail-0.3.0/ema/provenance.py +607 -0
- peakatail-0.3.0/ema/quantification/__init__.py +0 -0
- peakatail-0.3.0/ema/quantification/marker_selector.py +114 -0
- peakatail-0.3.0/ema/quantification/pas_to_isoform.py +385 -0
- peakatail-0.3.0/ema/quantification/pdui.py +189 -0
- peakatail-0.3.0/ema/quantification/strategies/__init__.py +75 -0
- peakatail-0.3.0/ema/quantification/strategies/base.py +88 -0
- peakatail-0.3.0/ema/quantification/strategies/classic.py +394 -0
- peakatail-0.3.0/ema/quantification/strategies/proportion.py +408 -0
- peakatail-0.3.0/ema/quantification/strategies/shannon.py +299 -0
- peakatail-0.3.0/ema/reannotate.py +751 -0
- peakatail-0.3.0/ema/statistics/__init__.py +2 -0
- peakatail-0.3.0/ema/statistics/background.py +66 -0
- peakatail-0.3.0/ema/statistics/significance.py +76 -0
- peakatail-0.3.0/ema/strategies/__init__.py +32 -0
- peakatail-0.3.0/ema/strategies/base.py +70 -0
- peakatail-0.3.0/ema/strategies/clip_seeded.py +129 -0
- peakatail-0.3.0/ema/strategies/lambda_gradient.py +327 -0
- peakatail-0.3.0/ema/strategies/lambda_poisson.py +154 -0
- peakatail-0.3.0/ema/strategies/original.py +24 -0
- peakatail-0.3.0/ema/strategies/sierra_iterative.py +132 -0
- peakatail-0.3.0/ema/strategies/utils.py +186 -0
- peakatail-0.3.0/ema/switch_test/__init__.py +0 -0
- peakatail-0.3.0/ema/switch_test/combine.py +159 -0
- peakatail-0.3.0/ema/switch_test/fishertest.py +152 -0
- peakatail-0.3.0/ema/switch_test/groupby.py +33 -0
- peakatail-0.3.0/ema/switch_test/long_output.py +453 -0
- peakatail-0.3.0/ema/switch_test/pair_runner.py +87 -0
- peakatail-0.3.0/ema/switch_test/prefilter.py +57 -0
- peakatail-0.3.0/ema/switch_test/runner.py +1874 -0
- peakatail-0.3.0/ema/switch_test/strategies/__init__.py +95 -0
- peakatail-0.3.0/ema/switch_test/strategies/base.py +80 -0
- peakatail-0.3.0/ema/switch_test/strategies/fisher.py +288 -0
- peakatail-0.3.0/ema/switch_test/strategies/nb_multi.py +424 -0
- peakatail-0.3.0/ema/switch_test/strategies/nb_pairwise.py +437 -0
- peakatail-0.3.0/ema/switch_test/trend.py +529 -0
- peakatail-0.3.0/ema/utils/__init__.py +52 -0
- peakatail-0.3.0/ema/utils/resource_manager.py +293 -0
- peakatail-0.3.0/ema/validation/__init__.py +1 -0
- peakatail-0.3.0/ema/validation/db_compare.py +228 -0
- peakatail-0.3.0/ema/validation/output_validator.py +219 -0
- peakatail-0.3.0/ema/validation/regression.py +252 -0
- peakatail-0.3.0/ema/viz/__init__.py +99 -0
- peakatail-0.3.0/ema/viz/_gene_track_helpers.py +675 -0
- peakatail-0.3.0/ema/viz/_io.py +37 -0
- peakatail-0.3.0/ema/viz/_meta.py +214 -0
- peakatail-0.3.0/ema/viz/atlas_snap_diag_matplotlib.py +118 -0
- peakatail-0.3.0/ema/viz/atlas_snap_diag_plotly.py +135 -0
- peakatail-0.3.0/ema/viz/base.py +28 -0
- peakatail-0.3.0/ema/viz/cluster_match_sankey_matplotlib.py +141 -0
- peakatail-0.3.0/ema/viz/cluster_match_sankey_plotly.py +161 -0
- peakatail-0.3.0/ema/viz/cluster_sizes_matplotlib.py +46 -0
- peakatail-0.3.0/ema/viz/cluster_sizes_plotly.py +37 -0
- peakatail-0.3.0/ema/viz/diff_agreement_matplotlib.py +91 -0
- peakatail-0.3.0/ema/viz/diff_agreement_plotly.py +98 -0
- peakatail-0.3.0/ema/viz/entropy_distribution_matplotlib.py +91 -0
- peakatail-0.3.0/ema/viz/entropy_distribution_plotly.py +71 -0
- peakatail-0.3.0/ema/viz/gene_track_matplotlib.py +754 -0
- peakatail-0.3.0/ema/viz/gene_track_plotly.py +845 -0
- peakatail-0.3.0/ema/viz/length_shifts_matplotlib.py +88 -0
- peakatail-0.3.0/ema/viz/length_shifts_plotly.py +104 -0
- peakatail-0.3.0/ema/viz/match_confidence_matplotlib.py +123 -0
- peakatail-0.3.0/ema/viz/match_confidence_plotly.py +119 -0
- peakatail-0.3.0/ema/viz/pas_overlap_matplotlib.py +154 -0
- peakatail-0.3.0/ema/viz/pas_overlap_plotly.py +125 -0
- peakatail-0.3.0/ema/viz/pdui_distribution_matplotlib.py +104 -0
- peakatail-0.3.0/ema/viz/pdui_distribution_plotly.py +100 -0
- peakatail-0.3.0/ema/viz/pdui_distribution_scanpy.py +91 -0
- peakatail-0.3.0/ema/viz/peak_qc_matplotlib.py +60 -0
- peakatail-0.3.0/ema/viz/peak_qc_plotly.py +45 -0
- peakatail-0.3.0/ema/viz/pipeline_hooks.py +1168 -0
- peakatail-0.3.0/ema/viz/proportion_heatmap_matplotlib.py +237 -0
- peakatail-0.3.0/ema/viz/proportion_heatmap_plotly.py +72 -0
- peakatail-0.3.0/ema/viz/resource_timeline_matplotlib.py +132 -0
- peakatail-0.3.0/ema/viz/resource_timeline_plotly.py +161 -0
- peakatail-0.3.0/ema/viz/run_report.py +376 -0
- peakatail-0.3.0/ema/viz/tile_timing_matplotlib.py +140 -0
- peakatail-0.3.0/ema/viz/tile_timing_plotly.py +137 -0
- peakatail-0.3.0/ema/viz/umap_matplotlib.py +53 -0
- peakatail-0.3.0/ema/viz/umap_plotly.py +46 -0
- peakatail-0.3.0/ema/viz/umap_scanpy.py +39 -0
- peakatail-0.3.0/ema/viz/volcano_matplotlib.py +189 -0
- peakatail-0.3.0/ema/viz/volcano_plotly.py +188 -0
- peakatail-0.3.0/peakatail.egg-info/PKG-INFO +337 -0
- peakatail-0.3.0/peakatail.egg-info/SOURCES.txt +315 -0
- peakatail-0.3.0/peakatail.egg-info/dependency_links.txt +1 -0
- peakatail-0.3.0/peakatail.egg-info/entry_points.txt +3 -0
- peakatail-0.3.0/peakatail.egg-info/requires.txt +39 -0
- peakatail-0.3.0/peakatail.egg-info/top_level.txt +1 -0
- peakatail-0.3.0/pyproject.toml +110 -0
- peakatail-0.3.0/setup.cfg +4 -0
- peakatail-0.3.0/test/test_cli.py +2 -0
- peakatail-0.3.0/test/test_filtermatrix.py +8 -0
- peakatail-0.3.0/test/test_peak.py +6 -0
- peakatail-0.3.0/test/test_switch_diff_cells_mode.py +255 -0
- peakatail-0.3.0/test/testconfig.py +0 -0
- peakatail-0.3.0/tests/test_annotate_runscoped_b2.py +50 -0
- peakatail-0.3.0/tests/test_artifact_naming_d7.py +67 -0
- peakatail-0.3.0/tests/test_atlas_annotate_overlay.py +275 -0
- peakatail-0.3.0/tests/test_atlas_snap_annotate_d9.py +168 -0
- peakatail-0.3.0/tests/test_atlas_snap_ledger_e3.py +67 -0
- peakatail-0.3.0/tests/test_atlas_snap_rate_d1.py +111 -0
- peakatail-0.3.0/tests/test_atlas_snap_summit.py +146 -0
- peakatail-0.3.0/tests/test_audit_cli_coverage.py +134 -0
- peakatail-0.3.0/tests/test_benchmark_point_strand.py +351 -0
- peakatail-0.3.0/tests/test_between_utr_report_gating_i94.py +160 -0
- peakatail-0.3.0/tests/test_build_count_dfs_which.py +87 -0
- peakatail-0.3.0/tests/test_canonical_roundtrip_b6.py +84 -0
- peakatail-0.3.0/tests/test_cb_encode.py +267 -0
- peakatail-0.3.0/tests/test_cellranger_input_compat.py +385 -0
- peakatail-0.3.0/tests/test_celltype_scoring_a1.py +131 -0
- peakatail-0.3.0/tests/test_changelog_section.py +267 -0
- peakatail-0.3.0/tests/test_chrom_parallel_identity.py +488 -0
- peakatail-0.3.0/tests/test_classic_pdui_vectorized.py +145 -0
- peakatail-0.3.0/tests/test_cleavage_offset_i72.py +380 -0
- peakatail-0.3.0/tests/test_cleavage_offset_prime.py +356 -0
- peakatail-0.3.0/tests/test_cleavage_offset_skips_clip_supported.py +53 -0
- peakatail-0.3.0/tests/test_cli_merge_parse_gtf.py +32 -0
- peakatail-0.3.0/tests/test_cli_rename_peakatail.py +76 -0
- peakatail-0.3.0/tests/test_cli_root.py +67 -0
- peakatail-0.3.0/tests/test_cli_run.py +159 -0
- peakatail-0.3.0/tests/test_cli_switch.py +279 -0
- peakatail-0.3.0/tests/test_cli_wizard.py +38 -0
- peakatail-0.3.0/tests/test_clip_rate_sampling.py +317 -0
- peakatail-0.3.0/tests/test_cluster_matching.py +593 -0
- peakatail-0.3.0/tests/test_clustering_registry.py +30 -0
- peakatail-0.3.0/tests/test_collapse_a4.py +138 -0
- peakatail-0.3.0/tests/test_config_schema.py +231 -0
- peakatail-0.3.0/tests/test_config_schema_atlas_ip_mode_d9.py +79 -0
- peakatail-0.3.0/tests/test_data_run_e4.py +417 -0
- peakatail-0.3.0/tests/test_docs_consistency.py +334 -0
- peakatail-0.3.0/tests/test_downstream_parallel.py +382 -0
- peakatail-0.3.0/tests/test_dynamic_threshold_bounds.py +372 -0
- peakatail-0.3.0/tests/test_filtered_cb_b3.py +39 -0
- peakatail-0.3.0/tests/test_findings_long_e5.py +347 -0
- peakatail-0.3.0/tests/test_fisher_percell_d4.py +85 -0
- peakatail-0.3.0/tests/test_gene_id_repair_b7.py +68 -0
- peakatail-0.3.0/tests/test_gene_track_regions.py +369 -0
- peakatail-0.3.0/tests/test_global_pool.py +310 -0
- peakatail-0.3.0/tests/test_gtf2isoform_utr.py +293 -0
- peakatail-0.3.0/tests/test_gtf_cache_global.py +418 -0
- peakatail-0.3.0/tests/test_internal_priming_strand.py +305 -0
- peakatail-0.3.0/tests/test_ip_annot_filter_d6.py +411 -0
- peakatail-0.3.0/tests/test_ip_filter_default.py +139 -0
- peakatail-0.3.0/tests/test_label_independent_prefilter_i94.py +466 -0
- peakatail-0.3.0/tests/test_logging_config.py +102 -0
- peakatail-0.3.0/tests/test_marker_selector_dtype.py +70 -0
- peakatail-0.3.0/tests/test_marker_top_n_double_dip_i94.py +471 -0
- peakatail-0.3.0/tests/test_marker_top_n_utr_denominator_i94.py +299 -0
- peakatail-0.3.0/tests/test_matrix_pas_id_row_alignment.py +226 -0
- peakatail-0.3.0/tests/test_matrixfilter_vectorized.py +386 -0
- peakatail-0.3.0/tests/test_nb_multi_split_d5.py +66 -0
- peakatail-0.3.0/tests/test_nb_offset_full_matrix_i94.py +226 -0
- peakatail-0.3.0/tests/test_nb_regression.py +510 -0
- peakatail-0.3.0/tests/test_outputs_atomic_writers.py +139 -0
- peakatail-0.3.0/tests/test_outputs_concat_beds.py +52 -0
- peakatail-0.3.0/tests/test_pair_parallel.py +262 -0
- peakatail-0.3.0/tests/test_pas_features.py +893 -0
- peakatail-0.3.0/tests/test_pas_gene_artifacts_atomic_write.py +167 -0
- peakatail-0.3.0/tests/test_pas_gene_overlapping_loci_i99.py +420 -0
- peakatail-0.3.0/tests/test_pas_gene_rescue.py +179 -0
- peakatail-0.3.0/tests/test_pas_merge.py +204 -0
- peakatail-0.3.0/tests/test_pas_merge_strand_b1.py +151 -0
- peakatail-0.3.0/tests/test_pas_score.py +558 -0
- peakatail-0.3.0/tests/test_pas_to_isoform.py +396 -0
- peakatail-0.3.0/tests/test_pas_to_isoform_spliced_dedup.py +197 -0
- peakatail-0.3.0/tests/test_pas_uid_e1.py +47 -0
- peakatail-0.3.0/tests/test_pasbed_status_columns_d9.py +133 -0
- peakatail-0.3.0/tests/test_pdui_strategies.py +477 -0
- peakatail-0.3.0/tests/test_peakcall_grid_ip_dedup.py +96 -0
- peakatail-0.3.0/tests/test_polya_clip_evidence_units.py +464 -0
- peakatail-0.3.0/tests/test_polya_clip_site.py +237 -0
- peakatail-0.3.0/tests/test_polya_clustering.py +271 -0
- peakatail-0.3.0/tests/test_polya_three_path_agreement.py +299 -0
- peakatail-0.3.0/tests/test_polya_tier1_counts.py +485 -0
- peakatail-0.3.0/tests/test_polya_two_tier_integration.py +449 -0
- peakatail-0.3.0/tests/test_prime_compat_flags.py +538 -0
- peakatail-0.3.0/tests/test_prime_dynamic_threshold_clamp.py +315 -0
- peakatail-0.3.0/tests/test_prime_ip_default_mode.py +355 -0
- peakatail-0.3.0/tests/test_prime_ip_escape_docs.py +220 -0
- peakatail-0.3.0/tests/test_prime_sidecar_merge_guard.py +143 -0
- peakatail-0.3.0/tests/test_prime_strand_implant.py +365 -0
- peakatail-0.3.0/tests/test_prime_v2_compat_golden.py +371 -0
- peakatail-0.3.0/tests/test_progress.py +71 -0
- peakatail-0.3.0/tests/test_provenance.py +221 -0
- peakatail-0.3.0/tests/test_provenance_atlas_ip_d9.py +110 -0
- peakatail-0.3.0/tests/test_provenance_invariant_e3.py +85 -0
- peakatail-0.3.0/tests/test_provenance_reconcile_e3.py +107 -0
- peakatail-0.3.0/tests/test_provenance_wiring_e3.py +121 -0
- peakatail-0.3.0/tests/test_pyproject_install.py +118 -0
- peakatail-0.3.0/tests/test_ram_adaptive_tile.py +253 -0
- peakatail-0.3.0/tests/test_read_check_fastpath.py +158 -0
- peakatail-0.3.0/tests/test_read_geometry.py +422 -0
- peakatail-0.3.0/tests/test_reannotate_cmd.py +573 -0
- peakatail-0.3.0/tests/test_reannotate_out_dir_guard.py +105 -0
- peakatail-0.3.0/tests/test_region_fetch.py +248 -0
- peakatail-0.3.0/tests/test_release_packaging.py +273 -0
- peakatail-0.3.0/tests/test_repair_gene_id.py +45 -0
- peakatail-0.3.0/tests/test_resource_manager.py +269 -0
- peakatail-0.3.0/tests/test_rg_sample_id_bijection.py +422 -0
- peakatail-0.3.0/tests/test_run_config_b0.py +67 -0
- peakatail-0.3.0/tests/test_run_diff_isoform.py +434 -0
- peakatail-0.3.0/tests/test_run_manifest_e2.py +132 -0
- peakatail-0.3.0/tests/test_state_encapsulation.py +383 -0
- peakatail-0.3.0/tests/test_sweep_analysis.py +610 -0
- peakatail-0.3.0/tests/test_switch_combine_a2.py +136 -0
- peakatail-0.3.0/tests/test_switch_diff_isoform_agg_scope.py +312 -0
- peakatail-0.3.0/tests/test_switch_length_degenerate_pairs.py +253 -0
- peakatail-0.3.0/tests/test_switch_length_strand_and_counts.py +305 -0
- peakatail-0.3.0/tests/test_switch_pasbed_resolve_b4.py +48 -0
- peakatail-0.3.0/tests/test_switch_trend_a3.py +238 -0
- peakatail-0.3.0/tests/test_tfidf_sparse_identity.py +114 -0
- peakatail-0.3.0/tests/test_trend_metrics.py +321 -0
- peakatail-0.3.0/tests/test_version_sync.py +132 -0
- peakatail-0.3.0/tests/test_viz_registry.py +58 -0
- peakatail-0.3.0/tests/test_viz_strategies_smoke.py +57 -0
- peakatail-0.3.0/tests/test_viz_tier2_smoke.py +199 -0
- peakatail-0.3.0/tests/test_viz_tier3_smoke.py +253 -0
- peakatail-0.3.0/tests/test_viz_tier4_smoke.py +278 -0
- peakatail-0.3.0/tests/test_wizard_e2e.py +226 -0
- peakatail-0.3.0/tests/test_yaml_loader.py +103 -0
peakatail-0.3.0/LICENSE
ADDED
|
@@ -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.
|
peakatail-0.3.0/PKG-INFO
ADDED
|
@@ -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
|
+
[](https://bmglab.github.io/PeakATail/)
|
|
63
|
+
[](LICENSE)
|
|
64
|
+
[](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
|
+
[](https://bmglab.github.io/PeakATail/)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](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")
|