Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Draw and export phylogenetic trees using Biopython Bio.Phylo with matplotlib. Use when creating publication-quality tree figures, customizing colors and labels, or exporting to image formats.
.claude/skills/bio-phylo-tree-visualization/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | -4% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 138% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 31% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 66% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 27% | 0% |
<!--
#
#
-->
Draw phylogenetic trees using matplotlib integration.
pythonfrom Bio import Phylo import matplotlib.pyplot as plt
pythontree = Phylo.read('tree.nwk', 'newick') # Quick text representation print(tree) # ASCII art diagram Phylo.draw_ascii(tree)
pythontree = Phylo.read('tree.nwk', 'newick') # Simple plot (opens interactive window) Phylo.draw(tree) plt.show() # Save to file fig, ax = plt.subplots(figsize=(10, 8)) Phylo.draw(tree, axes=ax) plt.savefig('tree.png', dpi=300, bbox_inches='tight') plt.close()
pythonfig, ax = plt.subplots(figsize=(12, 10)) Phylo.draw(tree, axes=ax, do_show=False, branch_labels=lambda c: f'{c.branch_length:.2f}' if c.branch_length else '', label_func=lambda c: c.name if c.is_terminal() else '') ax.set_title('Phylogenetic Tree') plt.savefig('custom_tree.png', dpi=300, bbox_inches='tight') plt.close()
python# Custom label function def custom_labels(clade): if clade.is_terminal(): return clade.name elif clade.confidence: return f'{clade.confidence:.0f}' return '' fig, ax = plt.subplots(figsize=(10, 8)) Phylo.draw(tree, axes=ax, label_func=custom_labels) plt.savefig('labeled_tree.png', dpi=300) plt.close()
python# Show branch lengths def branch_length_labels(clade): if clade.branch_length: return f'{clade.branch_length:.3f}' return '' fig, ax = plt.subplots(figsize=(10, 8)) Phylo.draw(tree, axes=ax, branch_labels=branch_length_labels) plt.savefig('with_lengths.png', dpi=300) plt.close() # Show bootstrap values (stored in clade.confidence or clade.name for internal nodes) def bootstrap_labels(clade): if not clade.is_terminal() and clade.confidence: return f'{clade.confidence:.0f}' return '' Phylo.draw(tree, axes=ax, branch_labels=bootstrap_labels)
python# Color specific clades before drawing tree = Phylo.read('tree.nwk', 'newick') # Set colors for specific clades (PhyloXML trees support this natively) for clade in tree.find_clades(): if clade.name and 'Human' in clade.name: clade.color = 'red' elif clade.name and 'Mouse' in clade.name: clade.color = 'blue' fig, ax = plt.subplots(figsize=(10, 8)) Phylo.draw(tree, axes=ax) plt.savefig('colored_tree.png', dpi=300) plt.close()
pythonfrom Bio.Phylo.PhyloXML import BranchColor # Convert to PhyloXML for color support phyloxml_tree = tree.as_phyloxml() # Color a clade and its descendants target = phyloxml_tree.find_any(name='Human') if target: target.color = BranchColor.from_name('red') fig, ax = plt.subplots(figsize=(10, 8)) Phylo.draw(phyloxml_tree, axes=ax) plt.savefig('highlighted.png', dpi=300) plt.close()
pythontree = Phylo.read('tree.nwk', 'newick') tree.ladderize() fig, ax = plt.subplots(figsize=(10, 8)) Phylo.draw(tree, axes=ax, do_show=False) # PNG (raster, good for presentations) plt.savefig('tree.png', dpi=300, bbox_inches='tight') # PDF (vector, good for publications) plt.savefig('tree.pdf', bbox_inches='tight') # SVG (vector, good for web) plt.savefig('tree.svg', bbox_inches='tight') plt.close()
python# Adjust figure size based on tree size n_taxa = len(tree.get_terminals()) height = max(8, n_taxa * 0.3) # Scale with number of taxa fig, ax = plt.subplots(figsize=(10, height)) Phylo.draw(tree, axes=ax, do_show=False) plt.tight_layout() plt.savefig('scaled_tree.png', dpi=300) plt.close()
| Parameter | Type | Description | |-----------|------|-------------| | tree | Tree | Tree object to draw | | axes | Axes | Matplotlib axes (optional) | | label_func | callable | Function to generate tip labels | | branch_labels | callable/dict | Function or dict for branch labels | | do_show | bool | Call plt.show() automatically (default True) |
pythontree = Phylo.read('tree.nwk', 'newick') # Ladderize for cleaner appearance tree.ladderize(reverse=True) # Set missing branch lengths to small value for clade in tree.find_clades(): if clade.branch_length is None: clade.branch_length = 0.001 fig, ax = plt.subplots(figsize=(10, 8)) Phylo.draw(tree, axes=ax) plt.savefig('clean_tree.png', dpi=300) plt.close()
pythontree1 = Phylo.read('tree1.nwk', 'newick') tree2 = Phylo.read('tree2.nwk', 'newick') fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8)) Phylo.draw(tree1, axes=ax1, do_show=False) ax1.set_title('Tree 1') Phylo.draw(tree2, axes=ax2, do_show=False) ax2.set_title('Tree 2') plt.tight_layout() plt.savefig('comparison.png', dpi=300) plt.close()
pythonfig, ax = plt.subplots(figsize=(10, 8)) Phylo.draw(tree, axes=ax, do_show=False) ax.axis('off') # Remove axis ax.set_frame_on(False) # Remove frame plt.savefig('clean_tree.png', dpi=300, bbox_inches='tight', transparent=True) plt.close()
| Function | Status | Alternative | |----------|--------|-------------| | draw_graphviz() | Removed (1.79) | Use Phylo.draw() for rectangular trees |
For radial (circular) tree layouts, use external tools like ETE3 or DendroPy.
| Issue | Cause | Solution | |-------|-------|----------| | Labels overlap | Too many taxa | Increase figure height | | No branch lengths | Missing in file | Set defaults or use cladogram | | Colors not showing | Wrong tree format | Convert to PhyloXML first | | Figure not saving | do_show=True | Set do_show=False before savefig |
<!-- 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-01 | pass→pass | 21,862 | 9,723 | -56% | 1 | 1 | 0% | 4,700 | 4,313 | -8% | 0 | 0 | — |
case-02 | pass→pass | 9,228 | 5,180 | -44% | 1 | 1 | 0% | 1,907 | 2,983 | +56% | 0 | 0 | — |
case-03 | pass→pass | 12,044 | 7,335 | -39% | 1 | 1 | 0% | 2,387 | 3,659 | +53% | 0 | 0 | — |
case-04 | fail→pass | 18,397 | 6,811 | -63% | 1 | 1 | 0% | 3,614 | 3,474 | -4% | 0 | 0 | — |
case-13 | fail→pass | 5,781 | 3,618 | -37% | 1 | 1 | 0% | 1,119 | 2,663 | +138% | 0 | 0 | — |
case-05 | pass→pass | 7,698 | 3,878 | -50% | 1 | 1 | 0% | 1,522 | 2,914 | +91% | 0 | 0 | — |
case-06 | fail→pass | 12,282 | 5,445 | -56% | 1 | 1 | 0% | 2,448 | 3,195 | +31% | 0 | 0 | — |
case-07 | pass→pass | 7,544 | 5,199 | -31% | 1 | 1 | 0% | 1,587 | 3,204 | +102% | 0 | 0 | — |
case-08 | pass→pass | 10,193 | 3,879 | -62% | 1 | 1 | 0% | 1,941 | 2,857 | +47% | 0 | 0 | — |
case-22 | fail→fail | 10,969 | 6,165 | -44% | 1 | 1 | 0% | 2,013 | 3,233 | +61% | 0 | 0 | — |
case-09 | pass→pass | 14,494 | 5,228 | -64% | 1 | 1 | 0% | 1,752 | 3,171 | +81% | 0 | 0 | — |
case-10 | fail→pass | 9,260 | 4,597 | -50% | 1 | 1 | 0% | 1,803 | 2,989 | +66% | 0 | 0 | — |
case-11 | pass→pass | 11,140 | 7,719 | -31% | 1 | 1 | 0% | 1,996 | 3,605 | +81% | 0 | 0 | — |
case-12 | pass→pass | 6,510 | 8,100 | +24% | 1 | 1 | 0% | 1,239 | 2,516 | +103% | 0 | 0 | — |
case-14 | pass→pass | 9,440 | 5,389 | -43% | 1 | 1 | 0% | 1,959 | 3,260 | +66% | 0 | 0 | — |
case-15 | pass→pass | 12,631 | 5,155 | -59% | 1 | 1 | 0% | 2,624 | 3,159 | +20% | 0 | 0 | — |
case-16 | pass→pass | 7,669 | 5,057 | -34% | 1 | 1 | 0% | 1,327 | 3,037 | +129% | 0 | 0 | — |
case-17 | pass→pass | 10,111 | 8,677 | -14% | 1 | 1 | 0% | 2,007 | 3,272 | +63% | 0 | 0 | — |
case-18 | pass→pass | 8,923 | 10,204 | +14% | 1 | 1 | 0% | 1,750 | 3,740 | +114% | 0 | 0 | — |
case-19 | pass→pass | 7,812 | 4,538 | -42% | 1 | 1 | 0% | 1,554 | 3,055 | +97% | 0 | 0 | — |
case-20 | fail→pass | 11,412 | 4,504 | -61% | 1 | 1 | 0% | 2,361 | 3,010 | +27% | 0 | 0 | — |
case-21 | pass→pass | 15,264 | 8,641 | -43% | 1 | 1 | 0% | 2,262 | 3,842 | +70% | 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. 22 cases were attempted. The headline lift of +23 percentage points is the difference between those two pass rates over the 22 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/26/2026 | +9% |
Other measured skills in the registry, with their headline benchmark lift.