关于 alterlab-phylogenetics
alterlab-phylogenetics 是帮助研究人员根据生物序列重建进化关系的技能,介绍从 MAFFT 比对、IQ-TREE 3 或 FastTree 推断,到 ETE3 树分析与可视化的工作流。
主要功能
- 01使用 MAFFT 进行多序列比对
- 02使用 TrimAl 可选地修剪比对
- 03使用 IQ-TREE 3 推断最大似然树
- 04使用 FastTree 快速近似推断树
- 05使用 ETE3 分析和可视化树
- 06模型选择与自举支持度指南
适用场景
- 01推断基因或生物之间的关系
- 02追踪病毒进化模式
- 03分析蛋白质家族的进化
- 04根据 16S rRNA 序列构建物种树
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ alterlab-ieu/ alterlab-academic-skills --skill alterlab-phylogenetics安装后在 Claude Code 中输入/alterlab-phylogenetics确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/evals.jsonreferences/iqtree_inference.mdscripts/phylogenetic_analysis.py详细介绍
系统发育学
概述
系统发育分析通过推断谱系分支模式,重建生物序列(基因、蛋白质、基因组)的进化历史。本技能涵盖标准工作流:
- MAFFT — 多序列比对
- IQ-TREE 3 — 通过模型选择进行最大似然树推断
- FastTree — 快速近似最大似然(适用于大型数据集)
- ETE3 — 用于树操作和可视化的 Python 库
安装: 比对工具和建树工具是编译型 CLI 工具(不在 PyPI 上)。通过 bioconda 或 Homebrew 安装二进制文件;使用 uv 安装 Python 可视化层。
# CLI binaries — bioconda (cross-platform) ...
conda install -c bioconda mafft iqtree fasttree trimal # iqtree is now IQ-TREE 3
# ... or Homebrew on macOS (Apple Silicon): IQ-TREE/TrimAl live in the brewsci/bio tap
brew install mafft fasttree
brew tap brewsci/bio && brew install brewsci/bio/iqtree brewsci/bio/trimal
# Python visualization layer
uv pip install "ete3==3.1.3" # also needs numpy<2 and PyQt5 for rendering
二进制文件名称: bioconda 的
iqtree软件包现为 IQ-TREE 3(3.1.x),并会安装可执行文件iqtree和iqtree3——其中没有iqtree2。调用iqtree即可,它适用于 2.x 和 3.x 软件包;只有在 PATH 中同时存在两个版本时,才使用带版本号的名称。IQ-TREE 3 新增了 MixtureFinder、多树混合模型(MAST)、基因/位点一致性因子,以及适用于超大型病原体数据集的 CMAPLE;以下选项与 2.x 相同。ETE3(3.1.3)是 ete3 的最后一个版本,在 Python ≥3.12 上可能难以安装(依赖旧版 numpy/PyQt5)。如果
t.render()失败,可改为写出 Newick 树并在 FigTree/iTOL 中查看,或使用其维护中的继任者ete4(注意:ete4 更改了TreeStyle/renderAPI,因此以下代码片段适用于 ete3)。
何时使用此技能
在以下情况使用系统发育分析:
- 进化关系:哪个生物/基因与我的序列亲缘关系最近?
- 病毒系统发育动力学:追踪疫情传播并估算传播日期
- 蛋白质家族分析:推断基因家族内部的进化关系
- 水平基因转移检测:识别物种树与基因树不一致的基因
- 祖先序列重建:推断祖先蛋白质序列
- 分子钟分析:利用时间采样估算分化日期
- GWAS 配套分析:将变异置于进化背景中(例如 SARS-CoV-2 变异)
- 微生物学:基于 16S rRNA 的物种系统发育或核心基因组系统发育
不适用的情况
| 场景 | 改用 |
|---|---|
| 操作或比较现有 Newick 树(剪枝、定根、Robinson-Foulds、重复/物种形成) | alterlab-etetoolkit |
| 简单的序列解析、翻译或格式转换 | alterlab-biopython |
| 比对前通过同源性搜索查找序列 | alterlab-blast |
| 对群落特征表进行多样性/排序分析(UniFrac、PCoA、PERMANOVA) | alterlab-scikit-bio |
| 运行生成 ASV 和树的 16S 扩增子工作流 | alterlab-qiime2-amplicon |
标准工作流
1. 使用 MAFFT 进行多序列比对
import subprocess
import os
def run_mafft(input_fasta: str, output_fasta: str, method: str = "auto",
n_threads: int = 4) -> str:
"""
Align sequences with MAFFT.
Args:
input_fasta: Path to unaligned FASTA file
output_fasta: Path for aligned output
method: 'auto' (auto-select), 'einsi' (accurate), 'linsi' (accurate, slow),
'fftnsi' (medium), 'fftns' (fast), 'retree2' (fast)
n_threads: Number of CPU threads
Returns:
Path to aligned FASTA file
"""
methods = {
"auto": ["mafft", "--auto"],
"einsi": ["mafft", "--genafpair", "--maxiterate", "1000"],
"linsi": ["mafft", "--localpair", "--maxiterate", "1000"],
"fftnsi": ["mafft", "--retree", "2", "--maxiterate", "2"],
"fftns": ["mafft", "--retree", "2", "--maxiterate", "0"],
"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 failed:\n{result.stderr}")
# Count aligned sequences
with open(output_fasta) as f:
n_seqs = sum(1 for line in f if line.startswith('>'))
print(f"MAFFT: aligned {n_seqs} sequences → {output_fasta}")
return output_fasta
# MAFFT method selection guide:
# Few sequences (<200), accurate: linsi or einsi
# Many sequences (<1000), moderate: fftnsi
# Large datasets (>1000): fftns or auto
# Ultra-fast (>10000): mafft --retree 1
2. 修剪比对结果(可选,但建议)
def trim_alignment_trimal(aligned_fasta: str, output_fasta: str,
method: str = "automated1") -> str:
"""
Trim poorly aligned columns with TrimAl.
Methods:
- 'automated1': Automatic heuristic (recommended)
- 'gappyout': Remove gappy columns
- 'strict': Strict gap threshold
"""
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"TrimAl warning: {result.stderr}")
# Fall back to using the untrimmed alignment
import shutil
shutil.copy(aligned_fasta, output_fasta)
return output_fasta
3. IQ-TREE 3 — 最大似然树
def run_iqtree(aligned_fasta: str, output_prefix: str,
model: str = "TEST", bootstrap: int = 1000,
n_threads: int = 4, extra_args: list = None) -> dict:
"""
Build a maximum likelihood tree with IQ-TREE 3.
Args:
aligned_fasta: Aligned FASTA file
output_prefix: Prefix for output files
model: 'TEST' for automatic model selection, or specify (e.g., 'GTR+G' for DNA,
'LG+G4' for proteins, 'JTT+G' for proteins)
bootstrap: Number of ultrafast bootstrap replicates (1000 recommended)
n_threads: Number of threads ('AUTO' to auto-detect)
extra_args: Additional IQ-TREE arguments
Returns:
Dict with paths to output files
"""
cmd = [
"iqtree",
"-s", aligned_fasta,
"--prefix", output_prefix,
"-m", model,
"-B", str(bootstrap), # Ultrafast bootstrap
"-T", str(n_threads),
"--redo" # Overwrite existing results
]
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 failed:\n{result.stderr}")
# Print model selection result
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", # Full report
"model": f"{output_prefix}.model.gz",
}
print(f"IQ-TREE: Tree saved to {output_files['tree']}")
return output_files
# Model selection: ModelFinder Plus (-m MFP) is the DEFAULT — omitting -m runs it.
# -m TEST is the narrower jModelTest/ProtTest-style search (no FreeRate models);
# use it only when you need to match those tools.
# Typical winners — DNA: GTR+F+I+G4, HKY+F+G4; Protein: LG+F+G4, Q.pfam+G4;
# Codon: MG+F3X4.
# For temporal (molecular clock) analysis, add:
# extra_args = ["--date", "dates.txt", "--clock-test", "--date-CI", "95"]
4. FastTree — 快速近似 ML
适用于 IQ-TREE 速度过慢的大型数据集(>1000 条序列):
def run_fasttree(aligned_fasta: str, output_tree: str,
sequence_type: str = "nt", model: str = "gtr",
n_threads: int = 4) -> str:
"""
Build a fast approximate ML tree with FastTree.
Args:
sequence_type: 'nt' for nucleotide or 'aa' for amino acid
model: For nt: 'gtr' (recommended) or 'jc'; for 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 failed:\n{result.stderr}")
print(f"FastTree: Tree saved to {output_tree}")
return output_tree
5. 使用 ETE3 进行树分析和可视化
from ete3 import Tree, TreeStyle, NodeStyle, TextFace, PhyloTree
import matplotlib.pyplot as plt
def load_tree(tree_file: str) -> Tree:
"""Load a Newick tree file."""
t = Tree(tree_file)
print(f"Tree: {len(t)} leaves, {len(list(t.traverse()))} nodes")
return t
def basic_tree_stats(t: Tree) -> dict:
"""Compute basic tree statistics."""
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:
"""Find the most recent common ancestor of a set of leaves."""
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:
"""
Render phylogenetic tree to image.
Args:
t: ETE3 Tree object
color_groups: Dict mapping leaf_name → color (for coloring taxa)
show_branch_support: Show bootstrap values
"""
ts = TreeStyle()
ts.show_leaf_name = True
ts.show_branch_support = show_branch_support
ts.mode = "r" # 'r' = rectangular, 'c' = circular
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"Tree saved to: {output_file}")
def midpoint_root(t: Tree) -> Tree:
"""Root tree at midpoint (use when outgroup unknown)."""
t.set_outgroup(t.get_midpoint_outgroup())
return t
def prune_tree(t: Tree, keep_leaves: list) -> Tree:
"""Prune tree to keep only specified leaves."""
t.prune(keep_leaves, preserve_branch_length=True)
return t
6. 完整分析脚本
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:
"""
Complete phylogenetic pipeline: align → trim → tree → visualize.
Args:
input_fasta: Unaligned FASTA
sequence_type: 'nt' (nucleotide) or 'aa' (amino acid/protein)
use_fasttree: Use FastTree instead of IQ-TREE (faster for large datasets)
"""
os.makedirs(output_dir, exist_ok=True)
prefix = os.path.join(output_dir, "phylo")
print("=" * 50)
print("Step 1: Multiple Sequence Alignment (MAFFT)")
aligned = run_mafft(input_fasta, f"{prefix}_aligned.fasta",
method="auto", n_threads=n_threads)
print("\nStep 2: Tree Inference")
if use_fasttree:
tree_file = run_fasttree(
aligned, f"{prefix}.tree",
sequence_type=sequence_type,
model="gtr" if sequence_type == "nt" else "lg"
)
else:
# -m TEST auto-detects the alphabet (nt vs aa) and selects the best model.
iqtree_files = run_iqtree(
aligned, prefix,
model="TEST",
bootstrap=bootstrap,
n_threads=n_threads
)
tree_file = iqtree_files["tree"]
print("\nStep 3: Tree Analysis")
t = Tree(tree_file)
t = midpoint_root(t)
stats = basic_tree_stats(t)
print(f"Tree statistics: {stats}")
print("\nStep 4: Visualization")
visualize_tree(t, f"{prefix}_tree.png", show_branch_support=True)
# Save rooted tree
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("Phylogenetic analysis complete!")
print(f"Results in: {output_dir}/")
return results
IQ-TREE 模型指南
DNA 模型
| 模型 | 描述 | 用例 |
|---|---|---|
GTR+G4 | 通用时间可逆模型 + Gamma | 最灵活的 DNA 模型 |
HKY+G4 | Hasegawa-Kishino-Yano + Gamma | 双速率模型(常用) |
TrN+G4 | Tamura-Nei | 转换率不相等 |
JC | Jukes-Cantor | 最简单;所有速率相等 |
蛋白质模型
| 模型 | 描述 | 用例 |
|---|---|---|
LG+G4 | Le-Gascuel + Gamma | 平均表现最佳的蛋白质模型 |
WAG+G4 | Whelan-Goldman | 使用广泛 |
JTT+G4 | Jones-Taylor-Thornton | 经典模型 |
Q.pfam+G4 | 基于 Pfam 训练(QMaker) | 通用蛋白质家族 |
Q.bird+G4 | 鸟类支系专用(QMaker) | 鸟类蛋白质;同系列模型:Q.mammal、Q.insect、Q.yeast、Q.plant |
提示: IQ-TREE 默认会自动选择模型(-m MFP);只有在需要固定模型时才传入显式模型。
最佳实践
- 优先保证比对质量:比对质量差 → 树不可靠;请手动检查比对结果
- 小型比对(<200 条序列)使用
linsi,大型比对使用fftns或auto - 模型选择:ModelFinder Plus 是 IQ-TREE 的默认选项——省略
-m(或传入-m MFP)即可。-m TEST会将搜索范围限制为 jModelTest/ProtTest 风格的模型,因此仅在需要与这些工具保持一致时使用 - Bootstrap:使用 ≥1000 次 ultrafast bootstrap(
-B 1000)评估分支支持度 - 为树定根:无根树可能产生误导;请使用外群定根或中点定根
- 超过 5000 条序列时使用 FastTree:IQ-TREE 会变慢;FastTree 的速度快 10–100 倍
- 修剪较长的比对:TrimAl 可移除不可靠的列,从而提高树的准确性
- 在构建树之前检查病毒/细菌序列是否发生重组(
RDP4、GARD)
其他资源
- MAFFT:https://mafft.cbrc.jp/alignment/software/
- IQ-TREE 3:http://www.iqtree.org/ | 教程:https://www.iqtree.org/workshop/molevol2022
- FastTree:http://www.microbesonline.org/fasttree/
- ETE3:http://etetoolkit.org/
- FigTree(GUI 可视化):https://tree.bio.ed.ac.uk/software/figtree/
- iTOL(网页可视化):https://itol.embl.de/
- MUSCLE(替代比对工具):https://www.drive5.com/muscle/
- TrimAl(比对修剪):https://vicfero.github.io/trimal/