Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Read, write, and convert phylogenetic tree files using Biopython Bio.Phylo. Use when parsing Newick, Nexus, PhyloXML, or NeXML tree formats, converting between formats, or handling multiple trees.
.claude/skills/bio-phylo-tree-io/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 124% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 185% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 145% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 127% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 100% | 0% |
<!--
#
#
-->
Parse, write, and convert phylogenetic tree files in various formats.
pythonfrom Bio import Phylo from io import StringIO
| Format | Extension | Description | |--------|-----------|-------------| | newick | .nwk, .tre, .tree | Standard format with branch lengths | | nexus | .nex, .nxs | Rich format with annotations (PAUP, MrBayes) | | phyloxml | .xml | XML format with metadata support | | nexml | .nexml | Modern XML format | | cdao | .rdf | RDF format (limited use) |
python# Read single tree tree = Phylo.read('tree.nwk', 'newick') # Read multiple trees from file trees = list(Phylo.parse('bootstrap_trees.nwk', 'newick')) print(f'Loaded {len(trees)} trees') # Read from string tree_string = '((A:0.1,B:0.2):0.3,(C:0.4,D:0.5):0.6);' tree = Phylo.read(StringIO(tree_string), 'newick') # Read PhyloXML with metadata tree = Phylo.read('annotated.xml', 'phyloxml') # Read Nexus (often contains multiple trees) trees = list(Phylo.parse('mrbayes.nex', 'nexus'))
python# Write single tree Phylo.write(tree, 'output.nwk', 'newick') # Write multiple trees Phylo.write(trees, 'all_trees.nwk', 'newick') # Write to PhyloXML (preserves metadata) Phylo.write(tree, 'output.xml', 'phyloxml') # Write to Nexus Phylo.write(tree, 'output.nex', 'nexus')
pythontree = Phylo.read('tree.nwk', 'newick') # Get tree as string (useful for embedding, logging, or API responses) newick_string = format(tree, 'newick') print(newick_string) # ((A:0.1,B:0.2):0.3,(C:0.4,D:0.5):0.6); # Alternative method newick_string = tree.format('newick') # Other formats work too phyloxml_string = format(tree, 'phyloxml')
python# Direct file conversion Phylo.convert('input.nwk', 'newick', 'output.xml', 'phyloxml') Phylo.convert('mrbayes.nex', 'nexus', 'trees.nwk', 'newick') # Convert with processing tree = Phylo.read('input.nwk', 'newick') tree.ladderize() # Sort branches Phylo.write(tree, 'sorted.nwk', 'newick')
pythontree = Phylo.read('tree.nwk', 'newick') # Print ASCII representation print(tree) # ASCII tree diagram Phylo.draw_ascii(tree) # Basic tree properties print(f'Total branch length: {tree.total_branch_length()}') print(f'Number of terminals: {len(tree.get_terminals())}') print(f'Is bifurcating: {tree.is_bifurcating()}')
python# Get all terminal (leaf) nodes terminals = tree.get_terminals() for term in terminals: print(f'{term.name}: branch_length={term.branch_length}') # Get all internal nodes nonterminals = tree.get_nonterminals() # Get all clades (nodes) all_clades = list(tree.find_clades()) # Find specific clade by name clade = tree.find_any(name='Human')
python# Simple tree (no branch lengths) tree = Phylo.read(StringIO('((A,B),(C,D));'), 'newick') # With branch lengths tree = Phylo.read(StringIO('((A:0.1,B:0.2):0.3,(C:0.4,D:0.5):0.6);'), 'newick') # With internal node names tree = Phylo.read(StringIO('((A,B)AB,(C,D)CD)root;'), 'newick') # With bootstrap values (internal node names) tree = Phylo.read(StringIO('((A:0.1,B:0.2)95:0.3,(C:0.4,D:0.5)80:0.6);'), 'newick')
python# PhyloXML supports rich annotations tree = Phylo.read('annotated.xml', 'phyloxml') for clade in tree.find_clades(): if clade.confidences: print(f'{clade.name}: confidence={clade.confidences[0].value}') if hasattr(clade, 'taxonomy') and clade.taxonomy: print(f'{clade.name}: taxonomy={clade.taxonomy.scientific_name}') # Convert Newick to PhyloXML (adds metadata capabilities) newick_tree = Phylo.read('simple.nwk', 'newick') phyloxml_tree = newick_tree.as_phyloxml()
python# Parse bootstrap or posterior trees trees = list(Phylo.parse('bootstrap.nwk', 'newick')) print(f'Loaded {len(trees)} bootstrap trees') # Process each tree for i, tree in enumerate(trees): print(f'Tree {i}: {len(tree.get_terminals())} taxa') # Write subset of trees Phylo.write(trees[:100], 'first_100.nwk', 'newick')
python# Memory-efficient iteration (doesn't load all trees at once) for tree in Phylo.parse('large_file.nwk', 'newick'): if tree.total_branch_length() > 1.0: print(f'Long tree: {tree.total_branch_length()}')
| Input | Description | |-------|-------------| | (A,B,C); | Unrooted, no lengths | | ((A,B),C); | Rooted topology | | (A:0.1,B:0.2); | With branch lengths | | ((A,B)X,C); | Internal node named X | | ((A,B):0.5[90],C); | Branch with bootstrap |
pythonfrom Bio import Phylo from io import StringIO # Check for valid newick tree_string = '((A,B),(C,D));' try: tree = Phylo.read(StringIO(tree_string), 'newick') print('Valid tree') except Exception as e: print(f'Parse error: {e}') # Handle missing 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 # Set default
| Format | Strengths | Limitations | |--------|-----------|-------------| | Newick | Universal, simple | No metadata | | Nexus | PAUP/MrBayes compatible | Complex syntax | | PhyloXML | Rich metadata, colors | Verbose | | NeXML | Modern, extensible | Less common |
<!-- AUTHOR_SIGNATURE: 9a7f3c2e-MD-BABU-MIA-2026-MSSM-SECURE -->
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-03 | fail→pass | 6,086 | 2,786 | -54% | 1 | 1 | 0% | 1,186 | 2,652 | +124% | 0 | 0 | — |
case-04 | pass→pass | 3,022 | 2,482 | -18% | 1 | 1 | 0% | 555 | 2,479 | +347% | 0 | 0 | — |
case-09 | pass→pass | 6,958 | 3,068 | -56% | 1 | 1 | 0% | 1,373 | 2,625 | +91% | 0 | 0 | — |
case-20 | pass→pass | 6,073 | 3,685 | -39% | 1 | 1 | 0% | 1,182 | 2,813 | +138% | 0 | 0 | — |
case-01 | fail→pass | 5,313 | 5,875 | +11% | 1 | 1 | 0% | 1,142 | 3,255 | +185% | 0 | 0 | — |
case-02 | pass→pass | 8,125 | 4,172 | -49% | 1 | 1 | 0% | 1,647 | 2,940 | +79% | 0 | 0 | — |
case-19 | pass→pass | 4,700 | 1,958 | -58% | 1 | 1 | 0% | 829 | 2,347 | +183% | 0 | 0 | — |
case-05 | pass→pass | 6,063 | 2,164 | -64% | 1 | 1 | 0% | 1,084 | 2,423 | +124% | 0 | 0 | — |
case-06 | fail→pass | 5,543 | 2,117 | -62% | 1 | 1 | 0% | 995 | 2,440 | +145% | 0 | 0 | — |
case-07 | fail→fail | 15,415 | 7,224 | -53% | 1 | 1 | 0% | 3,183 | 3,467 | +9% | 0 | 0 | — |
case-08 | pass→pass | 6,043 | 3,058 | -49% | 1 | 1 | 0% | 946 | 2,647 | +180% | 0 | 0 | — |
case-10 | pass→pass | 9,134 | 3,160 | -65% | 1 | 1 | 0% | 1,796 | 2,682 | +49% | 0 | 0 | — |
case-11 | pass→pass | 4,732 | 3,081 | -35% | 1 | 1 | 0% | 911 | 2,620 | +188% | 0 | 0 | — |
case-12 | fail→pass | 5,254 | 1,992 | -62% | 1 | 1 | 0% | 1,075 | 2,437 | +127% | 0 | 0 | — |
case-13 | pass→pass | 13,482 | 5,192 | -61% | 1 | 1 | 0% | 2,542 | 3,009 | +18% | 0 | 0 | — |
case-14 | pass→pass | 5,444 | 3,637 | -33% | 1 | 1 | 0% | 1,048 | 2,716 | +159% | 0 | 0 | — |
case-15 | fail→fail | 8,575 | 3,897 | -55% | 1 | 1 | 0% | 1,701 | 2,796 | +64% | 0 | 0 | — |
case-16 | fail→pass | 7,234 | 5,892 | -19% | 1 | 1 | 0% | 1,632 | 3,270 | +100% | 0 | 0 | — |
case-17 | pass→pass | 5,034 | 2,296 | -54% | 1 | 1 | 0% | 1,020 | 2,426 | +138% | 0 | 0 | — |
case-18 | pass→pass | 15,370 | 5,615 | -63% | 1 | 1 | 0% | 3,417 | 3,199 | -6% | 0 | 0 | — |
case-21 | fail→fail | 8,945 | 8,167 | -9% | 1 | 1 | 0% | 1,964 | 3,727 | +90% | 0 | 0 | — |
case-22 | pass→pass | 5,754 | 3,378 | -41% | 1 | 1 | 0% | 1,022 | 2,703 | +164% | 0 | 0 | — |
case-23 | pass→pass | 4,686 | 3,542 | -24% | 1 | 1 | 0% | 918 | 2,694 | +193% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +22 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/24/2026 | +23% |
Other measured skills in the registry, with their headline benchmark lift.