Utilities#
Preparing tree sets: pruning trees to the taxa of interest, and the trees as one weighted split system.
- forestpd.utils.prune(trees, taxa, weights=None, *, missing_branch_length='error')[source]#
Prune every tree to
taxa, dropping the trees that do not contain all of them.Each tree is restricted to the subtree spanning
taxa: the other leaves are removed, and so is every vertex left as a leaf or with only two neighbours, whose two edges are merged into one (lengths summed). Unrooted PD of any set of the kept taxa is therefore unchanged. Trees are read as unrooted; pruning a rooted tree would move its root, so this is for unrooted PD.- Parameters:
trees (str | os.PathLike | Sequence) – The path of a file holding one Newick tree per line, or a list of Newick strings and/or PhyloZoo
SemiDirectedPhyNetwork/DirectedPhyNetworktrees (with thephylozooextra). Every Newick tree ends with;. The trees may carry different taxon sets.taxa (Iterable[str]) – The taxa to keep; at least two.
weights (Sequence[float] | Mapping[int, float] | None, optional) – Per-tree weight
w_j, in the order of the trees (the list, or the file), or keyed by tree index.Nonemeans all1.0. Removed trees lose their weight; the others are not rescaled.missing_branch_length (str | float, default "error") – Policy for edges without a branch length:
"error","zero", or a numeric default. Applied after pruning; a merged edge has a length if any of its parts had one.
- Returns:
(trees, weights, registry): the pruned trees in input order, numbered againstregistry; thefloat64weights of the kept trees; and the registry of the kept taxa. Use them asMaxMPDInstance.from_phylotrees(trees, registry, weights=weights).- Return type:
- Raises:
ForestPDInputError – If fewer than two taxa are given, no tree contains all of them, or a tree or weight is invalid.
Examples
>>> import forestpd as fpd >>> trees, weights, registry = fpd.utils.prune( ... ["((A:1,B:1):1,(C:1,(D:1,E:1):1):1);", "((A:1,C:1):1,(B:1,D:1):1);"], ... {"A", "B", "C"}, weights=[2.0, 3.0]) >>> len(trees), weights.tolist(), registry.labels (2, [2.0, 3.0], ('A', 'B', 'C')) >>> instance = fpd.MaxMPDInstance.from_phylotrees(trees, registry, weights=weights) >>> instance.evaluate_pd({"A", "C"}) # 2 * (1 + 3) + 3 * (1 + 1) 14.0
- forestpd.utils.split_system(trees, weights=None, *, labels=None, missing_branch_length='error')[source]#
The trees as one weighted split system.
Every distinct split of the trees appears once, as its side without taxon 0, with weight
sum_j w_j * len_j(e)over the edges of all trees inducing it. The split diversity of a taxon set (the summed weight of the splits separating two of its taxa) then equals its unrootedsum_j w_j PD_{T_j}. Trees are read as unrooted.- Parameters:
trees (str | os.PathLike | Sequence) – The path of a file holding one Newick tree per line, or a list of Newick strings and/or PhyloZoo
SemiDirectedPhyNetwork/DirectedPhyNetworktrees (with thephylozooextra), or a list ofPhyloTree(e.g. fromprune()). All trees must carry the same taxon set.weights (Sequence[float] | Mapping[int, float] | None, optional) – Per-tree weight
w_j, in the order of the trees, or keyed by tree index.Nonemeans all1.0(pass1 / teach for the mean PD).labels (Sequence[str] | None, optional) – For
PhyloTreeinput only: the label of each leaf id (e.g.registry.labelsfromprune()).Noneuses the leaf ids themselves.missing_branch_length (str | float, default "error") – Policy for edges without a branch length (text and PhyloZoo input).
- Returns:
Per split, the sorted taxon ids of its side without taxon 0; the
float64split weights; and the label of each taxon id.- Return type:
tuple[list[numpy.ndarray], numpy.ndarray, tuple[str, …]]
- Raises:
ForestPDInputError – If a tree or weight is invalid, the trees do not share one taxon set, or
labelsis given for text input or has the wrong length.
Examples
>>> import forestpd as fpd >>> sides, weights, labels = fpd.io.splits.split_system( ... ["(A:1,B:1,(C:1,D:1):2);", "(A:1,C:1,(B:1,D:1):2);"]) >>> sorted(("".join(labels[x] for x in side), float(w)) ... for side, w in zip(sides, weights)) # each pendant split twice, each cherry once [('B', 2.0), ('BCD', 2.0), ('BD', 2.0), ('C', 2.0), ('CD', 2.0), ('D', 2.0)]