etetoolkit

Par mkurman · zorai

Boîte à outils phylogénétique (ETE). Manipulation d'arbres (Newick/NHX), détection d'événements évolutifs, orthologie/paralogie, taxonomie NCBI, visualisation (PDF/SVG), pour la phylogénomique.

npx skills add https://github.com/mkurman/zorai --skill etetoolkit

Skill ETE Toolkit

Présentation

ETE (Environment for Tree Exploration) est une boîte à outils pour l'analyse phylogénétique et des arbres hiérarchiques. Manipulez les arbres, analysez les événements évolutifs, visualisez les résultats et intégrez-les aux bases de données biologiques pour la recherche phylogénomique et l'analyse de clustering.

Capacités principales

1. Manipulation et analyse d'arbres

Chargez, manipulez et analysez des structures d'arbres hiérarchiques avec support pour :

  • Entrée/sortie d'arbres : Lire et écrire les formats Newick, NHX, PhyloXML et NeXML
  • Parcours d'arbres : Parcourez les arbres selon des stratégies préorder, postorder ou levelorder
  • Modification de topologie : Élaguez, enracinez, effondrez des nœuds, résolvez les polytomies
  • Calculs de distances : Calculez les longueurs de branches et les distances topologiques entre nœuds
  • Comparaison d'arbres : Calculez les distances de Robinson-Foulds et identifiez les différences topologiques

Modèles courants :

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")

Utilisez scripts/tree_operations.py pour la manipulation d'arbres en ligne de commande :

# 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

2. Analyse phylogénétique

Analysez les arbres de gènes avec détection des événements évolutifs :

  • Intégration d'alignement de séquences : Reliez les arbres aux alignements de séquences multiples (FASTA, Phylip)
  • Nommage d'espèces : Extraction automatique ou personnalisée d'espèces à partir de noms de gènes
  • Événements évolutifs : Détectez les événements de duplication et de spéciation à l'aide du chevauchement d'espèces ou de la réconciliation d'arbres
  • Détection d'orthologie : Identifiez les orthologues et paralogues en fonction des événements évolutifs
  • Analyse de famille de gènes : Divisez les arbres par duplications, effondrez les expansions spécifiques à la lignée

Flux de travail pour l'analyse d'arbres de gènes :

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")

Recherche d'orthologues et de paralogues :

# Find orthologs to query gene
query = tree & "species1_gene1"

orthologs = []
paralogs = []

for event in events:
    if query in event.in_seqs:
        if event.etype == "S":
            orthologs.extend([s for s in event.out_seqs if s != query])
        elif event.etype == "D":
            paralogs.extend([s for s in event.out_seqs if s != query])

3. Intégration de la taxonomie NCBI

Intégrez les informations taxonomiques à partir de la base de données NCBI Taxonomy :

  • Accès à la base de données : Téléchargement automatique et cache local de la taxonomie NCBI (~300 Mo)
  • Traduction taxid/nom : Convertissez entre les identifiants taxonomiques et les noms scientifiques
  • Récupération de lignée : Obtenez les lignées évolutives complètes
  • Arbres de taxonomie : Construisez des arbres d'espèces reliant les taxa spécifiés
  • Annotation d'arbre : Annotez automatiquement les arbres avec les informations taxonomiques

Construction d'arbres basés sur la taxonomie :

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}")

Annotation d'arbres existants :

# Get taxonomy info for tree leaves
for leaf in tree:
    species = extract_species_from_name(leaf.name)
    taxid = ncbi.get_name_translator([species])[species][0]

    # Get lineage
    lineage = ncbi.get_lineage(taxid)
    ranks = ncbi.get_rank(lineage)
    names = ncbi.get_taxid_translator(lineage)

    # Add to node
    leaf.add_feature("taxid", taxid)
    leaf.add_feature("lineage", [names[t] for t in lineage])

4. Visualisation d'arbre

Créez des visualisations d'arbre de qualité publication :

  • Formats de sortie : PNG (raster), PDF et SVG (vecteur) pour les publications
  • Modes de disposition : Dispositions rectangulaires et circulaires d'arbres
  • GUI interactif : Explorez les arbres de manière interactive avec zoom, panoramique et recherche
  • Style personnalisé : NodeStyle pour l'apparence des nœuds (couleurs, formes, tailles)
  • Faces : Ajoutez des éléments graphiques (texte, images, graphiques, cartes thermiques) aux nœuds
  • Fonctions de disposition : Style dynamique en fonction des propriétés des nœuds

Flux de travail de visualisation basique :

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
ts.scale = 50  # pixels per branch length unit

# Style nodes
for node in tree.traverse():
    nstyle = NodeStyle()

    if node.is_leaf():
        nstyle["fgcolor"] = "blue"
        nstyle["size"] = 8
    else:
        # Color by support
        if node.support > 0.9:
            nstyle["fgcolor"] = "darkgreen"
        else:
            nstyle["fgcolor"] = "red"
        nstyle["size"] = 5

    node.set_style(nstyle)

# Render to file
tree.render("tree.pdf", tree_style=ts)
tree.render("tree.png", w=800, h=600, units="px", dpi=300)

Utilisez scripts/quick_visualize.py pour une visualisation rapide :

# Basic visualization
python scripts/quick_visualize.py tree.nw output.pdf

# Circular layout with custom styling
python scripts/quick_visualize.py tree.nw output.pdf --mode c --color-by-support

# High-resolution PNG
python scripts/quick_visualize.py tree.nw output.png --width 1200 --height 800 --units px --dpi 300

# Custom title and styling
python scripts/quick_visualize.py tree.nw output.pdf --title "Species Phylogeny" --show-support

Visualisation avancée avec faces :

from ete3 import Tree, TreeStyle, TextFace, CircleFace

tree = Tree("tree.nw")

# Add features to nodes
for leaf in tree:
    leaf.add_feature("habitat", "marine" if "fish" in leaf.name else "land")

# Layout function
def layout(node):
    if node.is_leaf():
        # Add colored circle
        color = "blue" if node.habitat == "marine" else "green"
        circle = CircleFace(radius=5, color=color)
        node.add_face(circle, column=0, position="aligned")

        # Add label
        label = TextFace(node.name, fsize=10)
        node.add_face(label, column=1, position="aligned")

ts = TreeStyle()
ts.layout_fn = layout
ts.show_leaf_name = False

tree.render("annotated_tree.pdf", tree_style=ts)

5. Analyse de clustering

Analysez les résultats de clustering hiérarchique avec intégration de données :

  • ClusterTree : Classe spécialisée pour les dendrogrammes de clustering
  • Liaison de matrice de données : Connectez les feuilles d'arbre aux profils numériques
  • Métriques de cluster : Coefficient de silhouette, indice de Dunn, distances intra/inter-cluster
  • Validation : Testez la qualité du cluster avec différentes métriques de distance
  • Visualisation de carte thermique : Affichez les matrices de données aux côtés des arbres

Flux de travail de clustering :

from ete3 import ClusterTree

# Load tree with data matrix
matrix = """#Names\tSample1\tSample2\tSample3
Gene1\t1.5\t2.3\t0.8
Gene2\t0.9\t1.1\t1.8
Gene3\t2.1\t2.5\t0.5"""

tree = ClusterTree("((Gene1,Gene2),Gene3);", text_array=matrix)

# Evaluate cluster quality
for node in tree.traverse():
    if not node.is_leaf():
        silhouette = node.get_silhouette()
        dunn = node.get_dunn()

        print(f"Cluster: {node.name}")
        print(f"  Silhouette: {silhouette:.3f}")
        print(f"  Dunn index: {dunn:.3f}")

# Visualize with heatmap
tree.show("heatmap")

6. Comparaison d'arbre

Quantifiez les différences topologiques entre arbres :

  • Distance de Robinson-Foulds : Métrique standard pour la comparaison d'arbres
  • RF normalisé : Distance invariante en échelle (0,0 à 1,0)
  • Analyse de partition : Identifiez les bipartitions uniques et partagées
  • Arbres de consensus : Analysez le support sur plusieurs arbres
  • Comparaison par lot : Comparez plusieurs arbres par paire

Comparez deux arbres :

from ete3 import Tree

tree1 = Tree("tree1.nw")
tree2 = Tree("tree2.nw")

# Calculate RF distance
rf, max_rf, common_leaves, parts_t1, parts_t2 = tree1.robinson_foulds(tree2)

print(f"RF distance: {rf}/{max_rf}")
print(f"Normalized RF: {rf/max_rf:.3f}")
print(f"Common leaves: {len(common_leaves)}")

# Find unique partitions
unique_t1 = parts_t1 - parts_t2
unique_t2 = parts_t2 - parts_t1

print(f"Unique to tree1: {len(unique_t1)}")
print(f"Unique to tree2: {len(unique_t2)}")

Comparez plusieurs arbres :

import numpy as np

trees = [Tree(f"tree{i}.nw") for i in range(4)]

# Create distance matrix
n = len(trees)
dist_matrix = np.zeros((n, n))

for i in range(n):
    for j in range(i+1, n):
        rf, max_rf, _, _, _ = trees[i].robinson_foulds(trees[j])
        norm_rf = rf / max_rf if max_rf > 0 else 0
        dist_matrix[i, j] = norm_rf
        dist_matrix[j, i] = norm_rf

Installation et configuration

Installez la boîte à outils ETE :

# Basic installation
uv pip install ete3

# With external dependencies for rendering (optional but recommended)
# On macOS:
brew install qt@5

# On Ubuntu/Debian:
sudo apt-get install python3-pyqt5 python3-pyqt5.qtsvg

# For full features including GUI
uv pip install ete3[gui]

Configuration initiale de la taxonomie NCBI :

La première fois que NCBITaxa est instancié, il télécharge automatiquement la base de données de taxonomie NCBI (~300 Mo) vers ~/.etetoolkit/taxa.sqlite. Cela ne se produit qu'une fois :

from ete3 import NCBITaxa
ncbi = NCBITaxa()  # Downloads database on first run

Mettez à jour la base de données de taxonomie :

ncbi.update_taxonomy_database()  # Download latest NCBI data

Cas d'usage courants

Cas d'usage 1 : Pipeline phylogénomique

Flux de travail complet de l'arbre de gènes à l'identification des orthologues :

from ete3 import PhyloTree, NCBITaxa

# 1. Load gene tree with alignment
tree = PhyloTree("gene_tree.nw", alignment="alignment.fasta")

# 2. Configure species naming
tree.set_species_naming_function(lambda x: x.split("_")[0])

# 3. Detect evolutionary events
tree.get_descendant_evol_events()

# 4. Annotate with taxonomy
ncbi = NCBITaxa()
for leaf in tree:
    if leaf.species in species_to_taxid:
        taxid = species_to_taxid[leaf.species]
        lineage = ncbi.get_lineage(taxid)
        leaf.add_feature("lineage", lineage)

# 5. Extract ortholog groups
ortho_groups = tree.get_speciation_trees()

# 6. Save and visualize
for i, ortho in enumerate(ortho_groups):
    ortho.write(outfile=f"ortho_{i}.nw")

Cas d'usage 2 : Prétraitement et formatage d'arbres

Traitez par lot les arbres pour l'analyse :

# Convert format
python scripts/tree_operations.py convert input.nw output.nw --in-format 0 --out-format 1

# Root at midpoint
python scripts/tree_operations.py reroot input.nw rooted.nw --midpoint

# Prune to focal taxa
python scripts/tree_operations.py prune rooted.nw pruned.nw --keep-taxa taxa_list.txt

# Get statistics
python scripts/tree_operations.py stats pruned.nw

Cas d'usage 3 : Figures de qualité publication

Créez des visualisations stylisées :

from ete3 import Tree, TreeStyle, NodeStyle, TextFace

tree = Tree("tree.nw")

# Define clade colors
clade_colors = {
    "Mammals": "red",
    "Birds": "blue",
    "Fish": "green"
}

def layout(node):
    # Highlight clades
    if node.is_leaf():
        for clade, color in clade_colors.items():
            if clade in node.name:
                nstyle = NodeStyle()
                nstyle["fgcolor"] = color
                nstyle["size"] = 8
                node.set_style(nstyle)
    else:
        # Add support values
        if node.support > 0.95:
            support = TextFace(f"{node.support:.2f}", fsize=8)
            node.add_face(support, column=0, position="branch-top")

ts = TreeStyle()
ts.layout_fn = layout
ts.show_scale = True

# Render for publication
tree.render("figure.pdf", w=200, units="mm", tree_style=ts)
tree.render("figure.svg", tree_style=ts)  # Editable vector

Cas d'usage 4 : Analyse automatisée d'arbres

Traitez systématiquement plusieurs arbres :

from ete3 import Tree
import os

input_dir = "trees"
output_dir = "processed"

for filename in os.listdir(input_dir):
    if filename.endswith(".nw"):
        tree = Tree(os.path.join(input_dir, filename))

        # Standardize: midpoint root, resolve polytomies
        midpoint = tree.get_midpoint_outgroup()
        tree.set_outgroup(midpoint)
        tree.resolve_polytomy(recursive=True)

        # Filter low support branches
        for node in tree.traverse():
            if hasattr(node, 'support') and node.support < 0.5:
                if not node.is_leaf() and not node.is_root():
                    node.delete()

        # Save processed tree
        output_file = os.path.join(output_dir, f"processed_{filename}")
        tree.write(outfile=output_file)

Documentation de référence

Pour une documentation API complète, des exemples de code et des guides détaillés, consultez les ressources suivantes dans le répertoire references/ :

  • api_reference.md : Documentation API complète pour toutes les classes et méthodes ETE (Tree, PhyloTree, ClusterTree, NCBITaxa), incluant les paramètres, les types de retour et les exemples de code
  • workflows.md : Modèles de flux de travail courants organisés par tâche (opérations sur les arbres, analyse phylogénétique, comparaison d'arbres, intégration de taxonomie, analyse de clustering)
  • visualization.md : Guide de visualisation complet couvrant TreeStyle, NodeStyle, Faces, fonctions de disposition et techniques de visualisation avancées

Chargez ces références lorsque des informations détaillées sont nécessaires :

# To use API reference
# Read references/api_reference.md for complete method signatures and parameters

# To implement workflows
# Read references/workflows.md for step-by-step workflow examples

# To create visualizations
# Read references/visualization.md for styling and rendering options

Dépannage

Erreurs d'importation :

# If "ModuleNotFoundError: No module named 'ete3'"
uv pip install ete3

# For GUI and rendering issues
uv pip install ete3[gui]

Problèmes de rendu :

Si tree.render() ou tree.show() échoue avec des erreurs liées à Qt, installez les dépendances système :

# macOS
brew install qt@5

# Ubuntu/Debian
sudo apt-get install python3-pyqt5 python3-pyqt5.qtsvg

Base de données NCBI Taxonomy :

Si le téléchargement de la base de données échoue ou devient corrompu :

from ete3 import NCBITaxa
ncbi = NCBITaxa()
ncbi.update_taxonomy_database()  # Redownload database

Problèmes de mémoire avec les grands arbres :

Pour les très grands arbres (>10 000 feuilles), utilisez des itérateurs plutôt que des compréhensions de liste :

# Memory-efficient iteration
for leaf in tree.iter_leaves():
    process(leaf)

# Instead of
for leaf in tree.get_leaves():  # Loads all into memory
    process(leaf)

Référence du format Newick

ETE supporte plusieurs spécifications de format Newick (0-100) :

  • Format 0 : Flexible avec longueurs de branches (par défaut)
  • Format 1 : Avec noms de nœuds internes
  • Format 2 : Avec valeurs de bootstrap/support
  • Format 5 : Noms de nœuds internes + longueurs de branches
  • Format 8 : Toutes les fonctionnalités (noms, distances, support)
  • Format 9 : Noms de feuilles uniquement
  • Format 100 : Topologie uniquement

Spécifiez le format lors de la lecture/écriture :

tree = Tree("tree.nw", format=1)
tree.write(outfile="output.nw", format=5)

Le format NHX (New Hampshire eXtended) préserve les fonctionnalités personnalisées :

tree.write(outfile="tree.nhx", features=["habitat", "temperature", "depth"])

Bonnes pratiques

  1. Préservez les longueurs de branches : Utilisez preserve_branch_length=True lors de l'élagage pour l'analyse phylogénétique
  2. Contenu en cache : Utilisez get_cached_content() pour l'accès répété au contenu des nœuds sur les grands arbres
  3. Utilisez les itérateurs : Utilisez les méthodes iter_* pour le traitement efficace des grands arbres en termes de mémoire
  4. Choisissez un parcours approprié : Postorder pour l'analyse ascendante, preorder pour l'analyse descendante
  5. Validez la monophylie : Vérifiez toujours le type de clade renvoyé (monophylétique/paraphylétique/polyphylétique)
  6. Formats vectoriels pour publication : Utilisez PDF ou SVG pour les figures de publication (évolutifs, modifiables)
  7. Test interactif : Utilisez tree.show() pour tester les visualisations avant de les rendre dans un fichier
  8. PhyloTree pour la phylogénétique : Utilisez la classe PhyloTree pour les arbres de gènes et l'analyse évolutive
  9. Sélection de la méthode de copie : « newick » pour la vitesse, « cpickle » pour la fidélité complète, « deepcopy » pour les objets complexes
  10. Mise en cache des requêtes NCBI : Stockez les résultats des requêtes de taxonomie NCBI pour éviter les accès répétés à la base de données

Skills similaires