domains / science / phylogenetic-tree-analysis / etetoolkit
The copies overlap on ETE tree I/O, pruning, rooting, Robinson-Foulds comparison, gene-tree event detection, NCBI taxonomy, and visualization, but they target different ETE generations and include material steps the others lack. K-Dense-AI/scientific-agent-skills is the only copy targeting ETE 4.4.0 with ete4-specific API constraints, installation extras, SmartView/static rendering, and a migration warning. foryourhealth111-pixel/Vibe-Skills and FreedomIntelligence/OpenClaw-Medical-Skills are nearly identical ETE 3 skills and add a bundled command-line tree_operations.py workflow. aipoch/medical-research-skills adds clustering/dendrogram support and detailed Newick format-code guidance. Crowning one copy would hide either the ETE 4 procedure or the ETE 3 command-line/clustering alternatives.
| Repository | Path |
|---|---|
| K-Dense-AI/scientific-agent-skills | skills/etetoolkit/SKILL.md |
| foryourhealth111-pixel/Vibe-Skills | bundled/skills/etetoolkit/SKILL.md |
| aipoch/medical-research-skills | scientific-skills/Data Analysis/etetoolkit/SKILL.md |
| FreedomIntelligence/OpenClaw-Medical-Skills | skills/etetoolkit/SKILL.md |
| Role | Repository | Path |
|---|---|---|
| peer | K-Dense-AI/scientific-agent-skills | skills/etetoolkit/SKILL.md |
| peer | foryourhealth111-pixel/Vibe-Skills | bundled/skills/etetoolkit/SKILL.md |
| peer | aipoch/medical-research-skills | scientific-skills/Data Analysis/etetoolkit/SKILL.md |
| peer | FreedomIntelligence/OpenClaw-Medical-Skills | skills/etetoolkit/SKILL.md |
---
name: etetoolkit
description: Analyze, manipulate, compare, annotate, and visualize phylogenetic or hierarchical trees with ETE. Supports Newick/NHX/PhyloXML/NeXML I/O, topology edits, Robinson-Foulds comparison, gene-tree evolutionary events, NCBI taxonomy, visualization, and optional clustering. Use for existing trees after alignment and phylogenetic inference.
---
# ETE Toolkit
## Choose the ETE generation
- If the environment uses ETE 4, follow the ETE 4 section. Do not silently translate ETE 4 examples back to ETE 3.
- If the environment uses ETE 3, follow the ETE 3 section.
- For porting older code, consult the ETE 3 to ETE 4 migration notes if available.
## ETE 4 workflow
### Install and verify
```bash
uv pip install "ete4==4.4.0"
```
Add only the visualization extra required by the workflow:
```bash
# SmartView static PNG screenshots
uv pip install "ete4[render-sm]==4.4.0"
# Legacy Qt renderer for PNG, PDF, and SVG
uv pip install "ete4[treeview]==4.4.0"
```
Confirm the active environment:
```bash
uv run --no-project --isolated --with "ete4==4.4.0" python -c "import ete4; print(ete4.__version__)"
```
### Core ETE 4 patterns
```python
from pathlib import Path
from ete4 import Tree
# Use an open file object for files; reserve strings for Newick text.
with Path("tree.nw").open(encoding="utf-8") as handle:
tree = Tree(handle, parser=1) # parser 1: internal node names
print(tree.to_str(props=["name", "dist"], compact=True))
print("Leaves:", list(tree.leaf_names()))
# Search and annotate.
focal = tree["species1"]
focal.add_props(host="human", status="focal")
# Keep selected tips while preserving pairwise branch-length distances.
tree.prune(
["species1", "species2", "species3"],
preserve_branch_length=True,
)
# Root and serialize explicitly.
tree.set_midpoint_outgroup()
tree.write(
outfile="processed.nw",
parser=1,
props=["host", "status"],
)
```
Choose the parser deliberately. A parser mismatch is the most common cause of NewickError, lost internal labels, or support values being read as names.
### ETE 4 API constraints
- Package and import: ete4, not ete3
- File input: pass an open file object; use strings for Newick text
- Newick selection: parser=, not format=
- Node metadata: props, add_prop(), and add_props()
- Iteration: leaves(), descendants(), and related methods return iterators
- Predicates: node.is_leaf and node.is_root are properties, not methods
- Node lookup: tree["name"], not tree & "name"
### ETE 4 comparison
```python
from ete4 import Tree
tree_a = Tree("((A,B),(C,D));")
tree_b = Tree("((A,C),(B,D));")
(
rf,
max_rf,
common_leaves,
edges_a,
edges_b,
discarded_a,
discarded_b,
) = tree_a.robinson_foulds(tree_b)
normalized_rf = rf / max_rf if max_rf > 0 else None
print(rf, max_rf, normalized_rf, sorted(common_leaves))
```
RF comparison uses shared leaf labels and requires meaningful, preferably unique names. A zero maximum means no comparable splits; normalized RF is undefined (None), not evidence of agreement. Decide explicitly whether rooted or unrooted comparison is scientifically appropriate.
### ETE 4 gene-tree events
```python
from ete4 import PhyloTree
gene_tree = PhyloTree(
"((Hsa|g1,Ptr|g1),(Hsa|g2,Mus|g2));",
species_naming_function=lambda name: name.split("|")[0],
)
events = gene_tree.get_descendant_evol_events()
for node in gene_tree.traverse():
if hasattr(node, "evoltype"):
if node.evoltype == "D":
print(f"Duplication at {node.name}")
elif node.evoltype == "S":
print(f"Speciation at {node.name}")
```
### ETE 4 taxonomy
Query local NCBI or GTDB taxonomy databases. Public taxonomy acquisition needs internet access and can consume substantial disk space. Check the taxonomy reference before the first update.
### ETE 4 visualization
- Explore large trees interactively with SmartView.
- Render PNG with SmartView or PNG/PDF/SVG with the optional Qt treeview.
- Static PNG rendering needs ete4[render-sm] and Chrome/Chromium.
- Qt PDF/SVG rendering needs ete4[treeview].
## ETE 3 workflow
### Install
```bash
pip install "ete3>=3.1.0"
```
Optional GUI/rendering dependencies may include PyQt5 and Qt SVG support.
### Core ETE 3 patterns
```python
from ete3 import Tree
# Load tree from file
tree = Tree("tree.nw", format=1)
# Basic statistics
print(f"Leaves: {len(tree)}")
print(f"Total nodes: {len(list(tree.traverse()))}")
# Prune to taxa of interest
taxa_to_keep = ["species1", "species2", "species3"]
tree.prune(taxa_to_keep, preserve_branch_length=True)
# Midpoint root
midpoint = tree.get_midpoint_outgroup()
tree.set_outgroup(midpoint)
# Save modified tree
tree.write(outfile="rooted_tree.nw")
```
### ETE 3 command-line tree operations
If a bundled scripts/tree_operations.py is available, use it for command-line tree manipulation:
```bash
# Display tree statistics
python scripts/tree_operations.py stats tree.nw
# Convert format
python scripts/tree_operations.py convert tree.nw output.nw --in-format 0 --out-format 1
# Reroot tree
python scripts/tree_operations.py reroot tree.nw rooted.nw --midpoint
# Prune to specific taxa
python scripts/tree_operations.py prune tree.nw pruned.nw --keep-taxa "sp1,sp2,sp3"
# Show ASCII visualization
python scripts/tree_operations.py ascii tree.nw
```
### ETE 3 gene-tree events
```python
from ete3 import PhyloTree
# Load gene tree with alignment
tree = PhyloTree("gene_tree.nw", alignment="alignment.fasta")
# Set species naming function
def get_species(gene_name):
return gene_name.split("_")[0]
tree.set_species_naming_function(get_species)
# Detect evolutionary events
events = tree.get_descendant_evol_events()
# Analyze events
for node in tree.traverse():
if hasattr(node, "evoltype"):
if node.evoltype == "D":
print(f"Duplication at {node.name}")
elif node.evoltype == "S":
print(f"Speciation at {node.name}")
# Extract ortholog groups
ortho_groups = tree.get_speciation_trees()
for i, ortho_tree in enumerate(ortho_groups):
ortho_tree.write(outfile=f"ortholog_group_{i}.nw")
```
### ETE 3 taxonomy
```python
from ete3 import NCBITaxa
ncbi = NCBITaxa()
# Build tree from species names
species = ["Homo sapiens", "Pan troglodytes", "Mus musculus"]
name2taxid = ncbi.get_name_translator(species)
taxids = [name2taxid[sp][0] for sp in species]
# Get minimal tree connecting taxa
tree = ncbi.get_topology(taxids)
# Annotate nodes with taxonomy info
for node in tree.traverse():
if hasattr(node, "sci_name"):
print(f"{node.sci_name} - Rank: {node.rank} - TaxID: {node.taxid}")
```
### ETE 3 visualization
```python
from ete3 import Tree, TreeStyle, NodeStyle
tree = Tree("tree.nw")
# Configure tree style
ts = TreeStyle()
ts.show_leaf_name = True
ts.show_branch_support = True
for n in tree.traverse():
st = NodeStyle()
if n.is_leaf():
st["fgcolor"] = "blue"
st["size"] = 8
else:
st["fgcolor"] = "darkgreen" if getattr(n, "support", 0) >= 80 else "red"
st["size"] = 5
n.set_style(st)
tree.render("example_tree.pdf", tree_style=ts)
```
### ETE 3 Newick format codes
ETE 3 uses a format integer to control how node attributes are interpreted when reading/writing Newick. Common patterns:
- format=0: flexible default (often includes branch lengths)
- format=1: includes internal node names
- format=2: includes support/bootstrap values
- format=5: internal node names + branch lengths
- format=8: name + distance + support (maximal common usage)
- format=9: leaf names only
- format=100: topology only
Example:
```python
from ete3 import Tree
t = Tree("tree.nw", format=1)
t.write(outfile="out.nw", format=5)
```
### NHX feature preservation
NHX is used to store custom per-node features. When writing, specify which features to serialize:
```python
t.write(outfile="tree.nhx", features=["taxid", "habitat", "lineage"])
```
### Rerooting and pruning behavior
- Midpoint rooting uses get_midpoint_outgroup() to select an outgroup that balances path lengths.
- Pruning should typically use preserve_branch_length=True to avoid distorting distances in phylogenetic contexts.
### Tree comparison (Robinson-Foulds)
Tree.robinson_foulds(other_tree) returns:
- rf: RF distance (number of differing bipartitions)
- max_rf: maximum possible RF given shared leaves
- plus shared leaves and partition sets for deeper inspection
Normalized RF is typically computed as rf / max_rf (when max_rf > 0).
### Clustering support
For dendrograms linked to numeric matrices, use ClusterTree. Cluster quality metrics may include silhouette and Dunn index. Heatmap plus tree combined views are supported.
## Conflicts
- K-Dense-AI/scientific-agent-skills targets ETE 4.4.0 and uses ete4 APIs such as parser=, props, add_prop(), tree["name"], and file-object input, while foryourhealth111-pixel/Vibe-Skills, FreedomIntelligence/OpenClaw-Medical-Skills, and aipoch/medical-research-skills target ETE 3 and use ete3 APIs such as format=, add_feature(), tree & "name", and path-string input.
- K-Dense-AI/scientific-agent-skills says not to silently translate examples back to ETE 3, while the other copies provide ETE 3 examples as the primary workflow.
- foryourhealth111-pixel/Vibe-Skills and FreedomIntelligence/OpenClaw-Medical-Skills include a bundled scripts/tree_operations.py command-line workflow that the other copies do not include.
- aipoch/medical-research-skills includes clustering support with ClusterTree, silhouette/Dunn metrics, and heatmap-plus-tree views, which the other copies do not include.