phykit 2.1.90__tar.gz → 2.1.92__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.
- {phykit-2.1.90 → phykit-2.1.92}/PKG-INFO +2 -18
- {phykit-2.1.90 → phykit-2.1.92}/phykit/cli_registry.py +4 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/phykit.py +89 -6
- {phykit-2.1.90 → phykit-2.1.92}/phykit/service_factories.py +1 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/__init__.py +1 -0
- phykit-2.1.92/phykit/services/tree/faiths_pd.py +148 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/prune_tree.py +26 -1
- phykit-2.1.92/phykit/version.py +1 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit.egg-info/PKG-INFO +2 -18
- {phykit-2.1.90 → phykit-2.1.92}/phykit.egg-info/SOURCES.txt +1 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit.egg-info/entry_points.txt +4 -0
- phykit-2.1.90/phykit/version.py +0 -1
- {phykit-2.1.90 → phykit-2.1.92}/LICENSE.md +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/README.md +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/__init__.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/__main__.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/errors.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/__init__.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/boolean_argument_parsing.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/caching.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/circular_layout.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/color_annotations.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/discrete_models.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/files.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/geological_timescale.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/json_output.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/parallel.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/parsimony_utils.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/pgls_utils.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/plot_config.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/quartet_utils.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/stats_summary.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/streaming.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/helpers/trait_parsing.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/__init__.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/__init__.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/alignment_entropy.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/alignment_length.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/alignment_length_no_gaps.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/alignment_outlier_taxa.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/alignment_recoding.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/alignment_subsample.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/base.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/column_score.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/composition_per_taxon.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/compositional_bias_per_site.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/create_concatenation_matrix.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/dfoil.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/dna_threader.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/dstatistic.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/evolutionary_rate_per_site.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/faidx.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/gc_content.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/identity_matrix.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/mask_alignment.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/occupancy_filter.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/occupancy_per_taxon.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/pairwise_identity.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/parsimony_informative_sites.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/phylo_gwas.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/plot_alignment_qc.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/rcv.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/rcvt.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/rename_fasta_entries.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/sum_of_pairs_score.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/taxon_groups.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/alignment/variable_sites.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/base.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/ancestral_reconstruction.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/base.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/bipartition_support_stats.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/branch_length_multiplier.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/character_map.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/chronogram.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/collapse_branches.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/concordance_asr.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/consensus_network.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/consensus_tree.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/cont_map.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/cophylo.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/covarying_evolutionary_rates.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/density_map.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/discordance_asymmetry.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/dtt.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/dvmc.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/evo_tempo_map.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/evolutionary_rate.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/fit_continuous.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/fit_discrete.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/hidden_paralogy_check.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/hybridization.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/independent_contrasts.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/internal_branch_stats.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/internode_labeler.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/kf_distance.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/last_common_ancestor_subtree.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/lb_score.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/ltt.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/monophyly_check.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/nearest_neighbor_interchange.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/neighbor_net.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/network_signal.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/ou_shift_detection.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/ouwie.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/parsimony_score.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/patristic_distances.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phenogram.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phylo_anova.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phylo_heatmap.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phylo_impute.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phylo_logistic.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phylo_path.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phylogenetic_glm.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phylogenetic_ordination.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phylogenetic_regression.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phylogenetic_signal.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/phylomorphospace.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/polytomy_test.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/print_tree.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/quartet_network.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/quartet_pie.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/rate_heterogeneity.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/relative_rate_test.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/rename_tree_tips.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/rf_distance.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/root_tree.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/saturation.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/simmap_summary.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/spectral_discordance.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/spr.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/spurious_sequence.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/stochastic_character_map.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/terminal_branch_stats.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/threshold_model.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/tip_labels.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/tip_to_tip_distance.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/tip_to_tip_node_distance.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/total_tree_length.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/trait_correlation.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/trait_rate_map.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/transfer_annotations.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/tree_space.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/treeness.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/treeness_over_rcv.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit/services/tree/vcv_utils.py +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit.egg-info/dependency_links.txt +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit.egg-info/requires.txt +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/phykit.egg-info/top_level.txt +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/setup.cfg +0 -0
- {phykit-2.1.90 → phykit-2.1.92}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: phykit
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.92
|
|
4
4
|
Home-page: https://github.com/jlsteenwyk/phykit
|
|
5
5
|
Author: Jacob L. Steenwyk
|
|
6
6
|
Author-email: jlsteenwyk@gmail.com
|
|
@@ -15,22 +15,6 @@ Classifier: Topic :: Scientific/Engineering
|
|
|
15
15
|
Requires-Python: >=3.10
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE.md
|
|
18
|
-
Requires-Dist: biopython>=1.82
|
|
19
|
-
Requires-Dist: matplotlib>=3.7.0
|
|
20
|
-
Requires-Dist: numpy>=1.24.0
|
|
21
|
-
Requires-Dist: scipy>=1.11.3
|
|
22
|
-
Requires-Dist: scikit-learn>=1.4.2
|
|
23
|
-
Requires-Dist: umap-learn>=0.5.0
|
|
24
|
-
Requires-Dist: tqdm>=4.65.0
|
|
25
|
-
Dynamic: author
|
|
26
|
-
Dynamic: author-email
|
|
27
|
-
Dynamic: classifier
|
|
28
|
-
Dynamic: description
|
|
29
|
-
Dynamic: description-content-type
|
|
30
|
-
Dynamic: home-page
|
|
31
|
-
Dynamic: license-file
|
|
32
|
-
Dynamic: requires-dist
|
|
33
|
-
Dynamic: requires-python
|
|
34
18
|
|
|
35
19
|
<p align="center">
|
|
36
20
|
<a href="https://github.com/jlsteenwyk/phykit">
|
|
@@ -83,6 +83,10 @@ ALIAS_TO_HANDLER: Dict[str, str] = {
|
|
|
83
83
|
"ctree": "consensus_tree",
|
|
84
84
|
"degree_of_violation_of_a_molecular_clock": "dvmc",
|
|
85
85
|
"evo_rate": "evolutionary_rate",
|
|
86
|
+
"faiths_pd": "faiths_pd",
|
|
87
|
+
"faith_pd": "faiths_pd",
|
|
88
|
+
"fpd": "faiths_pd",
|
|
89
|
+
"phylo_diversity": "faiths_pd",
|
|
86
90
|
"clan_check": "hidden_paralogy_check",
|
|
87
91
|
"ibs": "internal_branch_stats",
|
|
88
92
|
"il": "internode_labeler",
|
|
@@ -230,6 +230,9 @@ class Phykit:
|
|
|
230
230
|
- determines if a set of tip names are monophyletic
|
|
231
231
|
nearest_neighbor_interchange (alias: nni)
|
|
232
232
|
- make nearest neighbor interchange moves on a tree
|
|
233
|
+
faiths_pd (alias: faith_pd; fpd; phylo_diversity)
|
|
234
|
+
- calculate Faith's phylogenetic diversity for a
|
|
235
|
+
community of tips
|
|
233
236
|
patristic_distances (alias: pd)
|
|
234
237
|
- calculate all pairwise distances between tips in a tree
|
|
235
238
|
phylogenetic_signal (alias: phylo_signal; ps)
|
|
@@ -3777,6 +3780,67 @@ class Phykit:
|
|
|
3777
3780
|
_add_json_argument(parser)
|
|
3778
3781
|
_run_service(parser, argv, NearestNeighborInterchange)
|
|
3779
3782
|
|
|
3783
|
+
@staticmethod
|
|
3784
|
+
def faiths_pd(argv):
|
|
3785
|
+
parser = _new_parser(
|
|
3786
|
+
description=textwrap.dedent(
|
|
3787
|
+
f"""\
|
|
3788
|
+
{help_header}
|
|
3789
|
+
|
|
3790
|
+
Calculate Faith's phylogenetic diversity (PD) for a
|
|
3791
|
+
community of tips on a phylogeny.
|
|
3792
|
+
|
|
3793
|
+
Faith's PD is the sum of branch lengths in the minimum
|
|
3794
|
+
subtree that connects a set of taxa. By default, the
|
|
3795
|
+
path from the community's most recent common ancestor
|
|
3796
|
+
up to the tree root is included, matching Faith (1992)
|
|
3797
|
+
and picante::pd(..., include.root = TRUE). Use
|
|
3798
|
+
--exclude-root to sum only the branches of the induced
|
|
3799
|
+
subtree rooted at the MRCA, matching
|
|
3800
|
+
picante::pd(..., include.root = FALSE).
|
|
3801
|
+
|
|
3802
|
+
Aliases:
|
|
3803
|
+
faiths_pd, faith_pd, fpd, phylo_diversity
|
|
3804
|
+
Command line interfaces:
|
|
3805
|
+
pk_faiths_pd, pk_faith_pd, pk_fpd, pk_phylo_diversity
|
|
3806
|
+
|
|
3807
|
+
Usage:
|
|
3808
|
+
phykit faiths_pd <tree> -t/--taxa <taxa_file>
|
|
3809
|
+
[--exclude-root] [--json]
|
|
3810
|
+
|
|
3811
|
+
Options
|
|
3812
|
+
=====================================================
|
|
3813
|
+
<tree> first argument after
|
|
3814
|
+
function name should be
|
|
3815
|
+
a tree file
|
|
3816
|
+
|
|
3817
|
+
-t/--taxa file with one tip label per
|
|
3818
|
+
line defining the community
|
|
3819
|
+
|
|
3820
|
+
--exclude-root sum only branches of the
|
|
3821
|
+
induced subtree rooted at
|
|
3822
|
+
the community MRCA; by
|
|
3823
|
+
default the path up to the
|
|
3824
|
+
tree root is included
|
|
3825
|
+
|
|
3826
|
+
--json optional argument to output
|
|
3827
|
+
results as JSON
|
|
3828
|
+
"""
|
|
3829
|
+
),
|
|
3830
|
+
)
|
|
3831
|
+
parser.add_argument("tree", type=str, help=SUPPRESS)
|
|
3832
|
+
parser.add_argument(
|
|
3833
|
+
"-t", "--taxa", type=str, required=True, help=SUPPRESS, metavar=""
|
|
3834
|
+
)
|
|
3835
|
+
parser.add_argument(
|
|
3836
|
+
"--exclude-root",
|
|
3837
|
+
dest="exclude_root",
|
|
3838
|
+
action="store_true",
|
|
3839
|
+
help=SUPPRESS,
|
|
3840
|
+
)
|
|
3841
|
+
_add_json_argument(parser)
|
|
3842
|
+
_run_service(parser, argv, FaithsPD)
|
|
3843
|
+
|
|
3780
3844
|
@staticmethod
|
|
3781
3845
|
def patristic_distances(argv):
|
|
3782
3846
|
parser = _new_parser(
|
|
@@ -6887,29 +6951,38 @@ class Phykit:
|
|
|
6887
6951
|
|
|
6888
6952
|
Usage:
|
|
6889
6953
|
phykit prune_tree <tree> <list_of_taxa> [-o/--output <output_file>
|
|
6890
|
-
-k/--keep] [--json]
|
|
6954
|
+
-k/--keep] [--ignore-branch-labels] [--json]
|
|
6891
6955
|
|
|
6892
6956
|
Options
|
|
6893
6957
|
=====================================================
|
|
6894
|
-
<tree> first argument after
|
|
6958
|
+
<tree> first argument after
|
|
6895
6959
|
function name should be
|
|
6896
6960
|
a tree file
|
|
6897
6961
|
|
|
6898
6962
|
<list_of_taxa> single column file with the
|
|
6899
6963
|
names of the tips to remove
|
|
6900
|
-
from the phylogeny
|
|
6964
|
+
from the phylogeny
|
|
6901
6965
|
|
|
6902
6966
|
-o/--output name of output file for the
|
|
6903
|
-
pruned phylogeny.
|
|
6904
|
-
Default output will have
|
|
6967
|
+
pruned phylogeny.
|
|
6968
|
+
Default output will have
|
|
6905
6969
|
the same name as the input
|
|
6906
|
-
file but with the suffix
|
|
6970
|
+
file but with the suffix
|
|
6907
6971
|
".pruned"
|
|
6908
6972
|
|
|
6909
6973
|
-k/--keep optional argument. If used
|
|
6910
6974
|
instead of pruning taxa in
|
|
6911
6975
|
<list_of_taxa>, keep them
|
|
6912
6976
|
|
|
6977
|
+
--ignore-branch-labels optional argument. Strip
|
|
6978
|
+
HyPhy/aBSREL-style {{...}}
|
|
6979
|
+
branch labels (e.g.,
|
|
6980
|
+
"Hydlep{{FG}}") from tip
|
|
6981
|
+
names when matching
|
|
6982
|
+
against <list_of_taxa>.
|
|
6983
|
+
The labels are preserved
|
|
6984
|
+
in the output tree.
|
|
6985
|
+
|
|
6913
6986
|
--json optional argument to output
|
|
6914
6987
|
results as JSON
|
|
6915
6988
|
"""
|
|
@@ -6921,6 +6994,12 @@ class Phykit:
|
|
|
6921
6994
|
parser.add_argument(
|
|
6922
6995
|
"-k", "--keep", type=str2bool, nargs="?", default=False, help=SUPPRESS
|
|
6923
6996
|
)
|
|
6997
|
+
parser.add_argument(
|
|
6998
|
+
"--ignore-branch-labels",
|
|
6999
|
+
action="store_true",
|
|
7000
|
+
default=False,
|
|
7001
|
+
help=SUPPRESS,
|
|
7002
|
+
)
|
|
6924
7003
|
_add_json_argument(parser)
|
|
6925
7004
|
_run_service(parser, argv, PruneTree)
|
|
6926
7005
|
|
|
@@ -9270,6 +9349,10 @@ def nearest_neighbor_interchange(argv=None):
|
|
|
9270
9349
|
Phykit.nearest_neighbor_interchange(sys.argv[1:])
|
|
9271
9350
|
|
|
9272
9351
|
|
|
9352
|
+
def faiths_pd(argv=None):
|
|
9353
|
+
Phykit.faiths_pd(sys.argv[1:])
|
|
9354
|
+
|
|
9355
|
+
|
|
9273
9356
|
def patristic_distances(argv=None):
|
|
9274
9357
|
Phykit.patristic_distances(sys.argv[1:])
|
|
9275
9358
|
|
|
@@ -66,6 +66,7 @@ NeighborNet = _LazyServiceFactory("phykit.services.tree.neighbor_net", "Neighbor
|
|
|
66
66
|
ConsensusTree = _LazyServiceFactory("phykit.services.tree.consensus_tree", "ConsensusTree")
|
|
67
67
|
DVMC = _LazyServiceFactory("phykit.services.tree.dvmc", "DVMC")
|
|
68
68
|
EvolutionaryRate = _LazyServiceFactory("phykit.services.tree.evolutionary_rate", "EvolutionaryRate")
|
|
69
|
+
FaithsPD = _LazyServiceFactory("phykit.services.tree.faiths_pd", "FaithsPD")
|
|
69
70
|
HiddenParalogyCheck = _LazyServiceFactory("phykit.services.tree.hidden_paralogy_check", "HiddenParalogyCheck")
|
|
70
71
|
InternalBranchStats = _LazyServiceFactory("phykit.services.tree.internal_branch_stats", "InternalBranchStats")
|
|
71
72
|
InternodeLabeler = _LazyServiceFactory("phykit.services.tree.internode_labeler", "InternodeLabeler")
|
|
@@ -15,6 +15,7 @@ _EXPORTS = {
|
|
|
15
15
|
"DiscordanceAsymmetry": "discordance_asymmetry",
|
|
16
16
|
"EvolutionaryRate": "evolutionary_rate",
|
|
17
17
|
"EvoTempoMap": "evo_tempo_map",
|
|
18
|
+
"FaithsPD": "faiths_pd",
|
|
18
19
|
"FitDiscrete": "fit_discrete",
|
|
19
20
|
"HiddenParalogyCheck": "hidden_paralogy_check",
|
|
20
21
|
"Hybridization": "hybridization",
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Faith's phylogenetic diversity (PD).
|
|
3
|
+
|
|
4
|
+
Given a tree and a community (list of tip labels), sum the branch
|
|
5
|
+
lengths of the minimum subtree connecting the community. When
|
|
6
|
+
``include_root`` is True (default), the sum includes the path from
|
|
7
|
+
the community's MRCA up to the tree root, matching Faith (1992) and
|
|
8
|
+
``picante::pd(..., include.root = TRUE)``.
|
|
9
|
+
"""
|
|
10
|
+
from typing import Dict, List, Tuple
|
|
11
|
+
|
|
12
|
+
from .base import Tree
|
|
13
|
+
from ...errors import PhykitUserError
|
|
14
|
+
from ...helpers.files import read_single_column_file_to_list
|
|
15
|
+
from ...helpers.json_output import print_json
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FaithsPD(Tree):
|
|
19
|
+
def __init__(self, args) -> None:
|
|
20
|
+
parsed = self.process_args(args)
|
|
21
|
+
super().__init__(tree_file_path=parsed["tree_file_path"])
|
|
22
|
+
self.taxa_file = parsed["taxa_file"]
|
|
23
|
+
self.include_root = parsed["include_root"]
|
|
24
|
+
self.json_output = parsed["json_output"]
|
|
25
|
+
|
|
26
|
+
def process_args(self, args) -> Dict:
|
|
27
|
+
return dict(
|
|
28
|
+
tree_file_path=args.tree,
|
|
29
|
+
taxa_file=args.taxa,
|
|
30
|
+
include_root=not getattr(args, "exclude_root", False),
|
|
31
|
+
json_output=getattr(args, "json", False),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def run(self) -> None:
|
|
35
|
+
tree = self.read_tree_file()
|
|
36
|
+
taxa = self._load_taxa(self.taxa_file)
|
|
37
|
+
pd_value, n_tips = self.calculate_faiths_pd(
|
|
38
|
+
tree, taxa, include_root=self.include_root
|
|
39
|
+
)
|
|
40
|
+
pd_rounded = round(pd_value, 4)
|
|
41
|
+
|
|
42
|
+
if self.json_output:
|
|
43
|
+
print_json(
|
|
44
|
+
dict(
|
|
45
|
+
faiths_pd=pd_rounded,
|
|
46
|
+
n_taxa=n_tips,
|
|
47
|
+
include_root=self.include_root,
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
return
|
|
51
|
+
print(pd_rounded)
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def _load_taxa(taxa_file: str) -> List[str]:
|
|
55
|
+
raw = read_single_column_file_to_list(taxa_file)
|
|
56
|
+
seen = set()
|
|
57
|
+
taxa: List[str] = []
|
|
58
|
+
for name in raw:
|
|
59
|
+
if not name or name in seen:
|
|
60
|
+
continue
|
|
61
|
+
seen.add(name)
|
|
62
|
+
taxa.append(name)
|
|
63
|
+
if not taxa:
|
|
64
|
+
raise PhykitUserError(
|
|
65
|
+
[f"No taxa found in {taxa_file}."], code=2,
|
|
66
|
+
)
|
|
67
|
+
return taxa
|
|
68
|
+
|
|
69
|
+
def calculate_faiths_pd(
|
|
70
|
+
self, tree, taxa: List[str], include_root: bool = True,
|
|
71
|
+
) -> Tuple[float, int]:
|
|
72
|
+
"""Compute Faith's PD for ``taxa`` on ``tree``.
|
|
73
|
+
|
|
74
|
+
Returns (pd, n_taxa). n_taxa is the deduplicated community size.
|
|
75
|
+
"""
|
|
76
|
+
self.validate_tree(tree, min_tips=2, require_branch_lengths=True,
|
|
77
|
+
context="Faith's PD")
|
|
78
|
+
|
|
79
|
+
seen: set = set()
|
|
80
|
+
deduped: List[str] = []
|
|
81
|
+
for name in taxa:
|
|
82
|
+
if name and name not in seen:
|
|
83
|
+
seen.add(name)
|
|
84
|
+
deduped.append(name)
|
|
85
|
+
taxa = deduped
|
|
86
|
+
if not taxa:
|
|
87
|
+
raise PhykitUserError(
|
|
88
|
+
["Community must contain at least one taxon."], code=2,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
tip_map = {t.name: t for t in tree.get_terminals()}
|
|
92
|
+
missing = [name for name in taxa if name not in tip_map]
|
|
93
|
+
if missing:
|
|
94
|
+
sample = ", ".join(sorted(missing)[:5])
|
|
95
|
+
suffix = f" ... ({len(missing)} total)" if len(missing) > 5 else ""
|
|
96
|
+
raise PhykitUserError(
|
|
97
|
+
[
|
|
98
|
+
"Taxa not found in tree:",
|
|
99
|
+
sample + suffix,
|
|
100
|
+
],
|
|
101
|
+
code=2,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
community_tips = [tip_map[name] for name in taxa]
|
|
105
|
+
|
|
106
|
+
if len(community_tips) == 1:
|
|
107
|
+
# Single-tip community: PD with include_root=True is the path
|
|
108
|
+
# length from the root to that tip; with include_root=False it
|
|
109
|
+
# is 0 (no induced subtree). picante returns NA for the latter;
|
|
110
|
+
# we return 0 for programmatic convenience.
|
|
111
|
+
if not include_root:
|
|
112
|
+
return 0.0, 1
|
|
113
|
+
path = tree.get_path(community_tips[0])
|
|
114
|
+
return (
|
|
115
|
+
sum((c.branch_length or 0.0) for c in path),
|
|
116
|
+
1,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if include_root:
|
|
120
|
+
start_clade = tree.root
|
|
121
|
+
else:
|
|
122
|
+
mrca = tree.common_ancestor(community_tips)
|
|
123
|
+
# If the MRCA is the root, include.root=False is equivalent
|
|
124
|
+
# to include.root=True because there is no branch leading to
|
|
125
|
+
# the MRCA to subtract (matches picante).
|
|
126
|
+
start_clade = mrca
|
|
127
|
+
|
|
128
|
+
total = 0.0
|
|
129
|
+
seen_ids = set()
|
|
130
|
+
for tip in community_tips:
|
|
131
|
+
# Skip clades at or above start_clade. For include_root=True,
|
|
132
|
+
# start_clade is the root, which is never in get_path.
|
|
133
|
+
path = tree.get_path(tip)
|
|
134
|
+
if start_clade is not tree.root:
|
|
135
|
+
try:
|
|
136
|
+
idx = path.index(start_clade)
|
|
137
|
+
path = path[idx + 1:]
|
|
138
|
+
except ValueError:
|
|
139
|
+
# start_clade (MRCA) not on path - defensive; shouldn't happen
|
|
140
|
+
pass
|
|
141
|
+
for clade in path:
|
|
142
|
+
cid = id(clade)
|
|
143
|
+
if cid in seen_ids:
|
|
144
|
+
continue
|
|
145
|
+
seen_ids.add(cid)
|
|
146
|
+
total += clade.branch_length or 0.0
|
|
147
|
+
|
|
148
|
+
return total, len(community_tips)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import Dict
|
|
2
2
|
import pickle
|
|
3
|
+
import re
|
|
3
4
|
|
|
4
5
|
from .base import Tree
|
|
5
6
|
|
|
@@ -7,6 +8,14 @@ from ...helpers.files import read_single_column_file_to_list
|
|
|
7
8
|
from ...helpers.json_output import print_json
|
|
8
9
|
|
|
9
10
|
|
|
11
|
+
_BRANCH_LABEL_RE = re.compile(r"\{[^{}]*\}")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _strip_branch_label(name: str) -> str:
|
|
15
|
+
"""Remove HyPhy/aBSREL-style {…} branch labels from a tip name."""
|
|
16
|
+
return _BRANCH_LABEL_RE.sub("", name) if name else name
|
|
17
|
+
|
|
18
|
+
|
|
10
19
|
class PruneTree(Tree):
|
|
11
20
|
def __init__(self, args) -> None:
|
|
12
21
|
parsed = self.process_args(args)
|
|
@@ -17,6 +26,7 @@ class PruneTree(Tree):
|
|
|
17
26
|
keep=parsed["keep"],
|
|
18
27
|
)
|
|
19
28
|
self.json_output = parsed["json_output"]
|
|
29
|
+
self.ignore_branch_labels = parsed["ignore_branch_labels"]
|
|
20
30
|
|
|
21
31
|
def run(self) -> None:
|
|
22
32
|
tree = self.read_tree_file()
|
|
@@ -25,7 +35,20 @@ class PruneTree(Tree):
|
|
|
25
35
|
|
|
26
36
|
taxa = read_single_column_file_to_list(self.list_of_taxa)
|
|
27
37
|
|
|
28
|
-
if self.
|
|
38
|
+
if self.ignore_branch_labels:
|
|
39
|
+
taxa_set = set(taxa)
|
|
40
|
+
tips_in_tree = [term.name for term in tree_copy.get_terminals()]
|
|
41
|
+
if self.keep:
|
|
42
|
+
taxa = [
|
|
43
|
+
tip for tip in tips_in_tree
|
|
44
|
+
if _strip_branch_label(tip) not in taxa_set
|
|
45
|
+
]
|
|
46
|
+
else:
|
|
47
|
+
taxa = [
|
|
48
|
+
tip for tip in tips_in_tree
|
|
49
|
+
if _strip_branch_label(tip) in taxa_set
|
|
50
|
+
]
|
|
51
|
+
elif self.keep:
|
|
29
52
|
tips_in_tree = [term.name for term in tree_copy.get_terminals()]
|
|
30
53
|
taxa = [x for x in tips_in_tree if x not in taxa]
|
|
31
54
|
|
|
@@ -39,6 +62,7 @@ class PruneTree(Tree):
|
|
|
39
62
|
input_tree=self.tree_file_path,
|
|
40
63
|
input_taxa_file=self.list_of_taxa,
|
|
41
64
|
keep_input_taxa=self.keep,
|
|
65
|
+
ignore_branch_labels=self.ignore_branch_labels,
|
|
42
66
|
taxa_pruned=sorted(taxa),
|
|
43
67
|
pruned_count=len(taxa),
|
|
44
68
|
remaining_tips=tree_copy.count_terminals(),
|
|
@@ -58,5 +82,6 @@ class PruneTree(Tree):
|
|
|
58
82
|
list_of_taxa=args.list_of_taxa,
|
|
59
83
|
output_file_path=output_file_path,
|
|
60
84
|
keep=keep,
|
|
85
|
+
ignore_branch_labels=getattr(args, "ignore_branch_labels", False),
|
|
61
86
|
json_output=getattr(args, "json", False),
|
|
62
87
|
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.1.92"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: phykit
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.92
|
|
4
4
|
Home-page: https://github.com/jlsteenwyk/phykit
|
|
5
5
|
Author: Jacob L. Steenwyk
|
|
6
6
|
Author-email: jlsteenwyk@gmail.com
|
|
@@ -15,22 +15,6 @@ Classifier: Topic :: Scientific/Engineering
|
|
|
15
15
|
Requires-Python: >=3.10
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE.md
|
|
18
|
-
Requires-Dist: biopython>=1.82
|
|
19
|
-
Requires-Dist: matplotlib>=3.7.0
|
|
20
|
-
Requires-Dist: numpy>=1.24.0
|
|
21
|
-
Requires-Dist: scipy>=1.11.3
|
|
22
|
-
Requires-Dist: scikit-learn>=1.4.2
|
|
23
|
-
Requires-Dist: umap-learn>=0.5.0
|
|
24
|
-
Requires-Dist: tqdm>=4.65.0
|
|
25
|
-
Dynamic: author
|
|
26
|
-
Dynamic: author-email
|
|
27
|
-
Dynamic: classifier
|
|
28
|
-
Dynamic: description
|
|
29
|
-
Dynamic: description-content-type
|
|
30
|
-
Dynamic: home-page
|
|
31
|
-
Dynamic: license-file
|
|
32
|
-
Dynamic: requires-dist
|
|
33
|
-
Dynamic: requires-python
|
|
34
18
|
|
|
35
19
|
<p align="center">
|
|
36
20
|
<a href="https://github.com/jlsteenwyk/phykit">
|
|
@@ -85,6 +85,7 @@ phykit/services/tree/dtt.py
|
|
|
85
85
|
phykit/services/tree/dvmc.py
|
|
86
86
|
phykit/services/tree/evo_tempo_map.py
|
|
87
87
|
phykit/services/tree/evolutionary_rate.py
|
|
88
|
+
phykit/services/tree/faiths_pd.py
|
|
88
89
|
phykit/services/tree/fit_continuous.py
|
|
89
90
|
phykit/services/tree/fit_discrete.py
|
|
90
91
|
phykit/services/tree/hidden_paralogy_check.py
|
|
@@ -55,12 +55,15 @@ pk_erps = phykit.phykit:evolutionary_rate_per_site
|
|
|
55
55
|
pk_etm = phykit.phykit:evo_tempo_map
|
|
56
56
|
pk_evo_rate = phykit.phykit:evolutionary_rate
|
|
57
57
|
pk_evo_rate_per_site = phykit.phykit:evolutionary_rate_per_site
|
|
58
|
+
pk_faith_pd = phykit.phykit:faiths_pd
|
|
59
|
+
pk_faiths_pd = phykit.phykit:faiths_pd
|
|
58
60
|
pk_fc = phykit.phykit:fit_continuous
|
|
59
61
|
pk_fd = phykit.phykit:fit_discrete
|
|
60
62
|
pk_filter_occupancy = phykit.phykit:occupancy_filter
|
|
61
63
|
pk_fit_ouwie = phykit.phykit:ouwie
|
|
62
64
|
pk_fitcontinuous = phykit.phykit:fit_continuous
|
|
63
65
|
pk_fitdiscrete = phykit.phykit:fit_discrete
|
|
66
|
+
pk_fpd = phykit.phykit:faiths_pd
|
|
64
67
|
pk_gamma = phykit.phykit:ltt
|
|
65
68
|
pk_gamma_stat = phykit.phykit:ltt
|
|
66
69
|
pk_gc = phykit.phykit:gc_content
|
|
@@ -121,6 +124,7 @@ pk_phylo_anova = phykit.phykit:phylo_anova
|
|
|
121
124
|
pk_phylo_contrasts = phykit.phykit:independent_contrasts
|
|
122
125
|
pk_phylo_corr = phykit.phykit:trait_correlation
|
|
123
126
|
pk_phylo_dimreduce = phykit.phykit:phylogenetic_ordination
|
|
127
|
+
pk_phylo_diversity = phykit.phykit:faiths_pd
|
|
124
128
|
pk_phylo_glm = phykit.phykit:phylogenetic_glm
|
|
125
129
|
pk_phylo_gwas = phykit.phykit:phylo_gwas
|
|
126
130
|
pk_phylo_imp = phykit.phykit:phylo_impute
|
phykit-2.1.90/phykit/version.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.1.90"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|