domains / science / phylogenetic-tree-analysis / etetoolkit

etetoolkit

Skill card

combined

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.

Repositories

RepositoryPath
K-Dense-AI/scientific-agent-skillsskills/etetoolkit/SKILL.md
foryourhealth111-pixel/Vibe-Skillsbundled/skills/etetoolkit/SKILL.md
aipoch/medical-research-skillsscientific-skills/Data Analysis/etetoolkit/SKILL.md
FreedomIntelligence/OpenClaw-Medical-Skillsskills/etetoolkit/SKILL.md

Other copies

RoleRepositoryPath
peerK-Dense-AI/scientific-agent-skillsskills/etetoolkit/SKILL.md
peerforyourhealth111-pixel/Vibe-Skillsbundled/skills/etetoolkit/SKILL.md
peeraipoch/medical-research-skillsscientific-skills/Data Analysis/etetoolkit/SKILL.md
peerFreedomIntelligence/OpenClaw-Medical-Skillsskills/etetoolkit/SKILL.md

Combined skill

---
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.