| name | bio-phylo-tree-manipulation |
| description | Modify phylogenetic tree structure using Biopython Bio.Phylo. Use when rooting trees with outgroups or midpoint, pruning taxa, collapsing clades, ladderizing branches, or extracting subtrees. |
| tool_type | python |
| primary_tool | Bio.Phylo |
Tree Manipulation
Modify phylogenetic tree structure: rooting, pruning, ladderizing, and subtree extraction.
Required Import
from Bio import Phylo
from io import StringIO
Rooting Trees
Root with Outgroup
tree = Phylo.read('tree.nwk', 'newick')
tree.root_with_outgroup({'name': 'Outgroup'})
outgroup = [{'name': 'TaxonA'}, {'name': 'TaxonB'}]
if tree.is_monophyletic(outgroup):
tree.root_with_outgroup(*outgroup)
else:
print('Outgroup is not monophyletic')
Root at Midpoint
tree = Phylo.read('tree.nwk', 'newick')
tree.root_at_midpoint()
Check Rooting Status
print(f'Is bifurcating: {tree.is_bifurcating()}')
root = tree.root
print(f'Root has {len(root.clades)} children')
Ladderizing
Sort clades for consistent visual presentation.
tree = Phylo.read('tree.nwk', 'newick')
tree.ladderize()
tree.ladderize(reverse=True)
Phylo.write(tree, 'ladderized.nwk', 'newick')
Pruning Trees
Remove Specific Taxa
tree = Phylo.read('tree.nwk', 'newick')
target = tree.find_any(name='TaxonToRemove')
if target:
tree.prune(target)
for name in ['TaxonA', 'TaxonB', 'TaxonC']:
target = tree.find_any(name=name)
if target:
tree.prune(target)
Keep Only Specified Taxa
tree = Phylo.read('tree.nwk', 'newick')
keep_taxa = {'Human', 'Chimp', 'Gorilla'}
terminals = tree.get_terminals()
for term in terminals:
if term.name not in keep_taxa:
tree.prune(term)
Collapsing Clades
Collapse branches below a threshold.
tree = Phylo.read('tree.nwk', 'newick')
target = tree.find_any(name='SomeInternalNode')
if target:
tree.collapse(target)
tree.collapse_all(lambda c: c.branch_length and c.branch_length < 0.01)
tree.collapse_all(lambda c: c.confidence is not None and c.confidence < 70)
Extracting Subtrees
Get Clade as Subtree
tree = Phylo.read('tree.nwk', 'newick')
clade = tree.common_ancestor({'name': 'Human'}, {'name': 'Chimp'})
Phylo.draw_ascii(clade)
subtree_taxa = [t.name for t in clade.get_terminals()]
print(f'Subtree contains: {subtree_taxa}')
Extract Subtree by Common Ancestor
tree = Phylo.read('tree.nwk', 'newick')
taxa = [{'name': 'Human'}, {'name': 'Chimp'}, {'name': 'Gorilla'}]
mrca = tree.common_ancestor(*taxa)
print(f'MRCA branch length: {mrca.branch_length}')
Tree Traversal
tree = Phylo.read('tree.nwk', 'newick')
for clade in tree.find_clades():
print(clade.name, clade.branch_length)
for clade in tree.find_clades(order='level'):
print(clade.name)
for clade in tree.find_clades(order='postorder'):
print(clade.name)
for term in tree.get_terminals():
print(term.name)
for internal in tree.get_nonterminals():
print(internal)
Finding Clades
tree = Phylo.read('tree.nwk', 'newick')
clade = tree.find_any(name='Human')
matches = tree.find_clades(branch_length=lambda x: x and x > 0.5)
for m in matches:
print(f'{m.name}: {m.branch_length}')
terminals = list(tree.find_clades(terminal=True))
internals = list(tree.find_clades(terminal=False))
Getting Path Between Nodes
tree = Phylo.read('tree.nwk', 'newick')
target = tree.find_any(name='Human')
path = tree.get_path(target)
print(f'Path from root to Human: {len(path)} nodes')
for clade in path:
print(f' {clade.name}: {clade.branch_length}')
human = tree.find_any(name='Human')
mouse = tree.find_any(name='Mouse')
trace = tree.trace(human, mouse)
print(f'Path Human to Mouse: {len(trace)} nodes')
Checking Tree Properties
tree = Phylo.read('tree.nwk', 'newick')
taxa = [tree.find_any(name='Human'), tree.find_any(name='Chimp')]
taxa = [t for t in taxa if t is not None]
print(f'Is monophyletic: {tree.is_monophyletic(taxa)}')
print(f'Is bifurcating: {tree.is_bifurcating()}')
for clade in tree.get_nonterminals():
print(f'{clade}: is_preterminal={clade.is_preterminal()}')
Modifying Branch Lengths
tree = Phylo.read('tree.nwk', 'newick')
for clade in tree.find_clades():
if clade.branch_length is None:
clade.branch_length = 0.0
scale_factor = 100
for clade in tree.find_clades():
if clade.branch_length:
clade.branch_length *= scale_factor
for clade in tree.find_clades():
clade.branch_length = None
Renaming Taxa
tree = Phylo.read('tree.nwk', 'newick')
target = tree.find_any(name='OldName')
if target:
target.name = 'NewName'
name_map = {'Hsap': 'Human', 'Ptro': 'Chimp', 'Mmus': 'Mouse'}
for term in tree.get_terminals():
if term.name in name_map:
term.name = name_map[term.name]
Phylo.write(tree, 'renamed.nwk', 'newick')
Counting Nodes
tree = Phylo.read('tree.nwk', 'newick')
n_terminals = len(tree.get_terminals())
n_internals = len(tree.get_nonterminals())
n_total = tree.count_terminals() + len(tree.get_nonterminals())
print(f'Terminals: {n_terminals}')
print(f'Internal nodes: {n_internals}')
print(f'Total nodes: {n_total}')
Tree Depths
tree = Phylo.read('tree.nwk', 'newick')
depths = tree.depths()
for clade, depth in depths.items():
if clade.is_terminal():
print(f'{clade.name}: depth={depth:.3f}')
max_depth = max(depths.values())
print(f'Tree height: {max_depth:.3f}')
Splitting Clades
tree = Phylo.read('tree.nwk', 'newick')
target = tree.find_any(name='TaxonA')
if target and target.is_terminal():
target.split(n=2, branch_length=0.05)
target.split(branch_length=[0.1, 0.2, 0.3])
Generating Random Trees
from Bio.Phylo.BaseTree import Tree
taxa = ['Human', 'Chimp', 'Gorilla', 'Mouse', 'Rat']
random_tree = Tree.randomized(taxa)
Phylo.draw_ascii(random_tree)
random_tree = Tree.randomized(taxa, branch_length=1.0)
Quick Reference: Tree Methods
| Method | Description |
|---|
root_with_outgroup() | Reroot using outgroup |
root_at_midpoint() | Reroot at midpoint |
ladderize() | Sort branches by size |
prune() | Remove a clade |
collapse() | Collapse a clade into polytomy |
collapse_all() | Collapse all matching clades |
split() | Split clade into children |
trace() | Get path between two clades |
Tree.randomized() | Generate random tree |
common_ancestor() | Find MRCA of taxa |
find_any() | Find first matching clade |
find_clades() | Find all matching clades |
get_path() | Get path from root to clade |
depths() | Get depth of all clades |
is_monophyletic() | Check if taxa form clade |
is_bifurcating() | Check if tree is binary |
Related Skills
- tree-io - Read and write tree files
- tree-visualization - Draw modified trees
- distance-calculations - Build trees from alignments