Phylogénétique
Aperçu
L'analyse phylogénétique reconstitue l'histoire évolutive de séquences biologiques (gènes, protéines, génomes) en inférant le motif de ramification de la descendance. Cette compétence couvre le pipeline standard :
- MAFFT — Alignement multiple de séquences
- IQ-TREE 2 — Inférence d'arbre par maximum de vraisemblance avec sélection de modèle
- FastTree — Maximum de vraisemblance approximatif rapide (pour grands jeux de données)
- ETE3 — Bibliothèque Python pour la manipulation et la visualisation d'arbres
Installation :
# Conda (recommandé pour les outils en ligne de commande)
conda install -c bioconda mafft iqtree fasttree
uv pip install ete3
# Le rendu TreeStyle/NodeStyle d'ete3 dépend de son backend Qt, donc la sortie d'image
# nécessite PyQt5 également ; l'analyse et les statistiques d'arbres fonctionnent sans.
uv pip install PyQt5
Quand utiliser cette compétence
Utilisez la phylogénétique lorsque :
- Relations évolutives : Quel organisme/gène est le plus proche de ma séquence ?
- Phylodynamique virale : Tracer la propagation d'une épidémie et estimer les dates de transmission
- Analyse des familles de protéines : Inférer les relations évolutives au sein d'une famille de gènes
- Détection de transfert horizontal de gènes : Identifier les gènes avec des arbres espèces/gènes discordants
- Reconstruction de séquences ancestrales : Inférer des séquences protéiques ancestrales
- Analyse d'horloge moléculaire : Estimer les dates de divergence en utilisant un échantillonnage temporel
- Compagnon d'étude d'association pangénomique (GWAS) : Placer les variants dans un contexte évolutif (par exemple, variants du SARS-CoV-2)
- Microbiologie : Phylogénie d'espèces à partir de l'ARNr 16S ou phylogénie du génome central
Flux de travail standard
1. Alignement multiple de séquences avec MAFFT
import subprocess
import os
def run_mafft(input_fasta: str, output_fasta: str, method: str = "auto",
n_threads: int = 4) -> str:
"""
Aligner des séquences avec MAFFT.
Args :
input_fasta : Chemin vers le fichier FASTA non aligné
output_fasta : Chemin pour la sortie alignée
method : 'auto' (auto-sélection), 'einsi' (précis), 'linsi' (précis, lent),
'fftnsi' (moyen), 'fftns' (rapide), 'retree2' (rapide)
n_threads : Nombre de threads CPU
Renvoie :
Chemin vers le fichier FASTA aligné
"""
methods = {
"auto": ["mafft", "--auto"],
"einsi": ["mafft", "--genafpair", "--maxiterate", "1000"],
"linsi": ["mafft", "--localpair", "--maxiterate", "1000"],
"fftnsi": ["mafft", "--fftnsi"],
"fftns": ["mafft", "--fftns"],
"retree2": ["mafft", "--retree", "2"],
}
cmd = methods.get(method, methods["auto"])
cmd += ["--thread", str(n_threads), "--inputorder", input_fasta]
with open(output_fasta, 'w') as out:
result = subprocess.run(cmd, stdout=out, stderr=subprocess.PIPE, text=True)
if result.returncode != 0:
raise RuntimeError(f"MAFFT a échoué :\n{result.stderr}")
# Compter les séquences alignées
with open(output_fasta) as f:
n_seqs = sum(1 for line in f if line.startswith('>'))
print(f"MAFFT : {n_seqs} séquences alignées → {output_fasta}")
return output_fasta
# Guide de sélection de méthode MAFFT :
# Peu de séquences (<200), précis : linsi ou einsi
# Nombreuses séquences (<1000), modéré : fftnsi
# Grands jeux de données (>1000) : fftns ou auto
# Ultra-rapide (>10000) : mafft --retree 1
2. Rogner l'alignement (optionnel mais recommandé)
def trim_alignment_trimal(aligned_fasta: str, output_fasta: str,
method: str = "automated1") -> str:
"""
Rogner les colonnes mal alignées avec TrimAl.
Méthodes :
- 'automated1' : Heuristique automatique (recommandée)
- 'gappyout' : Supprimer les colonnes avec des gaps
- 'strict' : Seuil strict pour les gaps
"""
cmd = ["trimal", f"-{method}", "-in", aligned_fasta, "-out", output_fasta, "-fasta"]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"Avertissement TrimAl : {result.stderr}")
# Revenir à l'alignement non rogné
import shutil
shutil.copy(aligned_fasta, output_fasta)
return output_fasta
3. IQ-TREE 2 — Arbre par maximum de vraisemblance
def run_iqtree(aligned_fasta: str, output_prefix: str,
model: str = "TEST", bootstrap: int = 1000,
n_threads: int = 4, extra_args: list = None) -> dict:
"""
Construire un arbre par maximum de vraisemblance avec IQ-TREE 2.
Args :
aligned_fasta : Fichier FASTA aligné
output_prefix : Préfixe pour les fichiers de sortie
model : 'TEST' pour une sélection automatique du modèle, ou spécifier (ex., 'GTR+G' pour ADN,
'LG+G4' pour protéines, 'JTT+G' pour protéines)
bootstrap : Nombre de répliques de bootstrap ultra-rapide (1000 recommandé)
n_threads : Nombre de threads ('AUTO' pour détection automatique)
extra_args : Arguments supplémentaires pour IQ-TREE
Renvoie :
Dict avec les chemins vers les fichiers de sortie
"""
cmd = [
"iqtree2",
"-s", aligned_fasta,
"--prefix", output_prefix,
"-m", model,
"-B", str(bootstrap), # Bootstrap ultra-rapide
"-T", str(n_threads),
"--redo" # Écraser les résultats existants
]
if extra_args:
cmd.extend(extra_args)
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"IQ-TREE a échoué :\n{result.stderr}")
# Afficher le résultat de la sélection de modèle
log_file = f"{output_prefix}.log"
if os.path.exists(log_file):
with open(log_file) as f:
for line in f:
if "Best-fit model" in line:
print(f"IQ-TREE : {line.strip()}")
output_files = {
"tree": f"{output_prefix}.treefile",
"log": f"{output_prefix}.log",
"iqtree": f"{output_prefix}.iqtree", # Rapport complet
"model": f"{output_prefix}.model.gz",
}
print(f"IQ-TREE : Arbre sauvegardé dans {output_files['tree']}")
return output_files
# Guide de sélection de modèle IQ-TREE :
# ADN : TEST → GTR+G, HKY+G, TrN+G
# Protéine : TEST → LG+G4, WAG+G, JTT+G, Q.pfam+G
# Codon : TEST → MG+F3X4
# Pour une analyse temporelle (horloge moléculaire), ajoutez :
# extra_args = ["--date", "dates.txt", "--clock-test", "--date-CI", "95"]
4. FastTree — ML approximatif rapide
Pour les grands jeux de données (>1000 séquences) où IQ-TREE est trop lent :
def run_fasttree(aligned_fasta: str, output_tree: str,
sequence_type: str = "nt", model: str = "gtr",
n_threads: int = 4) -> str:
"""
Construire un arbre ML approximatif rapide avec FastTree.
Args :
sequence_type : 'nt' pour nucléotide ou 'aa' pour acide aminé
model : Pour nt : 'gtr' (recommandé) ou 'jc' ; pour aa : 'lg', 'wag', 'jtt'
"""
if sequence_type == "nt":
cmd = ["FastTree", "-nt", "-gtr"]
else:
cmd = ["FastTree", f"-{model}"]
cmd += [aligned_fasta]
with open(output_tree, 'w') as out:
result = subprocess.run(cmd, stdout=out, stderr=subprocess.PIPE, text=True)
if result.returncode != 0:
raise RuntimeError(f"FastTree a échoué :\n{result.stderr}")
print(f"FastTree : Arbre sauvegardé dans {output_tree}")
return output_tree
5. Analyse et visualisation d'arbres avec ETE3
from ete3 import Tree, TreeStyle, NodeStyle, TextFace, PhyloTree
import matplotlib.pyplot as plt
def load_tree(tree_file: str) -> Tree:
"""Charger un fichier d'arbre au format Newick."""
t = Tree(tree_file)
print(f"Arbre : {len(t)} feuilles, {len(list(t.traverse()))} nœuds")
return t
def basic_tree_stats(t: Tree) -> dict:
"""Calculer les statistiques de base d'un arbre."""
leaves = t.get_leaves()
distances = [t.get_distance(l1, l2) for l1 in leaves[:min(50, len(leaves))]
for l2 in leaves[:min(50, len(leaves))] if l1 != l2]
stats = {
"n_leaves": len(leaves),
"n_internal_nodes": len(t) - len(leaves),
"total_branch_length": sum(n.dist for n in t.traverse()),
"max_leaf_distance": max(distances) if distances else 0,
"mean_leaf_distance": sum(distances)/len(distances) if distances else 0,
}
return stats
def find_mrca(t: Tree, leaf_names: list) -> Tree:
"""Trouver l'ancêtre commun le plus récent d'un ensemble de feuilles."""
return t.get_common_ancestor(*leaf_names)
def visualize_tree(t: Tree, output_file: str = "tree.png",
show_branch_support: bool = True,
color_groups: dict = None,
width: int = 800) -> None:
"""
Rendre un arbre phylogénétique en image.
Args :
t : Objet Tree ETE3
color_groups : Dict mappant nom_feuille → couleur (pour colorer les taxons)
show_branch_support : Afficher les valeurs de bootstrap
"""
ts = TreeStyle()
ts.show_leaf_name = True
ts.show_branch_support = show_branch_support
ts.mode = "r" # 'r' = rectangulaire, 'c' = circulaire
if color_groups:
for node in t.traverse():
if node.is_leaf() and node.name in color_groups:
nstyle = NodeStyle()
nstyle["fgcolor"] = color_groups[node.name]
nstyle["size"] = 8
node.set_style(nstyle)
t.render(output_file, tree_style=ts, w=width, units="px")
print(f"Arbre sauvegardé dans : {output_file}")
def midpoint_root(t: Tree) -> Tree:
"""Enraciner l'arbre au point médian (à utiliser lorsque le groupe externe est inconnu)."""
t.set_outgroup(t.get_midpoint_outgroup())
return t
def prune_tree(t: Tree, keep_leaves: list) -> Tree:
"""Élaguer l'arbre pour ne conserver que les feuilles spécifiées."""
t.prune(keep_leaves, preserve_branch_length=True)
return t
6. Script d'analyse complet
import subprocess, os
from ete3 import Tree
def full_phylogenetic_analysis(
input_fasta: str,
output_dir: str = "phylo_results",
sequence_type: str = "nt",
n_threads: int = 4,
bootstrap: int = 1000,
use_fasttree: bool = False
) -> dict:
"""
Pipeline phylogénétique complet : aligner → rogner → arbre → visualiser.
Args :
input_fasta : FASTA non aligné
sequence_type : 'nt' (nucléotide) ou 'aa' (acide aminé/protéine)
use_fasttree : Utiliser FastTree au lieu d'IQ-TREE (plus rapide pour les grands jeux de données)
"""
os.makedirs(output_dir, exist_ok=True)
prefix = os.path.join(output_dir, "phylo")
print("=" * 50)
print("Étape 1 : Alignement multiple de séquences (MAFFT)")
aligned = run_mafft(input_fasta, f"{prefix}_aligned.fasta",
method="auto", n_threads=n_threads)
print("\nÉtape 2 : Inférence de l'arbre")
if use_fasttree:
tree_file = run_fasttree(
aligned, f"{prefix}.tree",
sequence_type=sequence_type,
model="gtr" if sequence_type == "nt" else "lg"
)
else:
model = "TEST" if sequence_type == "nt" else "TEST"
iqtree_files = run_iqtree(
aligned, prefix,
model=model,
bootstrap=bootstrap,
n_threads=n_threads
)
tree_file = iqtree_files["tree"]
print("\nÉtape 3 : Analyse de l'arbre")
t = Tree(tree_file)
t = midpoint_root(t)
stats = basic_tree_stats(t)
print(f"Statistiques de l'arbre : {stats}")
print("\nÉtape 4 : Visualisation")
visualize_tree(t, f"{prefix}_tree.png", show_branch_support=True)
# Sauvegarder l'arbre enraciné
rooted_tree_file = f"{prefix}_rooted.nwk"
t.write(format=1, outfile=rooted_tree_file)
results = {
"aligned_fasta": aligned,
"tree_file": tree_file,
"rooted_tree": rooted_tree_file,
"visualization": f"{prefix}_tree.png",
"stats": stats
}
print("\n" + "=" * 50)
print("Analyse phylogénétique terminée !")
print(f"Résultats dans : {output_dir}/")
return results
Guide des modèles IQ-TREE
Modèles ADN
| Modèle | Description | Cas d'utilisation |
|---|---|---|
GTR+G4 | Général réversible dans le temps + Gamma | Modèle ADN le plus flexible |
HKY+G4 | Hasegawa-Kishino-Yano + Gamma | Modèle à deux taux (courant) |
TrN+G4 | Tamura-Nei | Transitions inégales |
JC | Jukes-Cantor | Le plus simple ; tous les taux égaux |
Modèles protéiques
| Modèle | Description | Cas d'utilisation |
|---|---|---|
LG+G4 | Le-Gascuel + Gamma | Meilleur modèle protéique moyen |
WAG+G4 | Whelan-Goldman | Largement utilisé |
JTT+G4 | Jones-Taylor-Thornton | Modèle classique |
Q.pfam+G4 | Entraîné sur Pfam | Pour les familles de protéines de type Pfam |
Q.bird+G4 | Spécifique aux oiseaux | Protéines de vertébrés |
Astuce : Utilisez -m TEST pour laisser IQ-TREE sélectionner automatiquement le meilleur modèle.
Bonnes pratiques
- Qualité de l'alignement d'abord : Un mauvais alignement conduit à des arbres peu fiables ; vérifiez l'alignement manuellement
- Utilisez
linsipour les petits (<200 seq),fftnsouautopour les grands alignements - Sélection de modèle : Utilisez toujours
-m TESTpour IQ-TREE sauf si vous avez une raison spécifique - Bootstrap : Utilisez ≥1000 bootstraps ultra-rapides (
-B 1000) pour la confiance des branches - Enracinez l'arbre : Les arbres non enracinés peuvent être trompeurs ; utilisez un groupe externe ou l'enracinement au point médian
- FastTree pour >5000 séquences : IQ-TREE devient lent ; FastTree est 10–100× plus rapide
- Rognez les longs alignements : TrimAl supprime les colonnes peu fiables ; améliore la précision de l'arbre
- Vérifiez la présence de recombinaison dans les séquences virales/bactériennes avant de construire des arbres (
RDP4,GARD)
Ressources supplémentaires
- MAFFT : https://mafft.cbrc.jp/alignment/software/
- IQ-TREE 2 : http://www.iqtree.org/ | Tutoriel : https://www.iqtree.org/workshop/molevol2022
- FastTree : http://www.microbesonline.org/fasttree/
- ETE3 : http://etetoolkit.org/
- FigTree (visualisation GUI) : https://tree.bio.ed.ac.uk/software/figtree/
- iTOL (visualisation web) : https://itol.embl.de/
- MUSCLE (aligneur alternatif) : https://www.drive5.com/muscle/
- TrimAl (rognage d'alignement) : https://vicfero.github.io/trimal/