BiopythonのBio.Phyloを利用した系統樹操作まとめ
系統樹操作まとめ内容
- 系統樹データ読み込み
- 系統樹の可視化
- 全ノード取得
- 終端ノードのみ取得
- 内部ノードのみ取得
- ノードプロパティ変更
- ノード検索
- 終端ノード群の単系統判定
- ルートから対象ノードまでの全ノード経路リスト取得
- 最近共通祖先ノード取得
- 各ノード深さ取得
- 対象ノード間の枝長取得
- 系統樹全体の枝長総和取得
系統樹データ読み込み
Bio.Phylo.read()
メソッドで系統樹データ読み込み
from io import StringIO
from Bio import Phylo
from Bio.Phylo.BaseTree import Tree
treedata = "((((A:1,B:1)100:1,(C:1,D:1)100:1)100:1,(E:2,F:2)90:1):1,G:4)100;"
tree: Tree = Phylo.read(file=StringIO(treedata), format="newick")
print(tree)
Tree(rooted=False, weight=1.0)
Clade(confidence=100)
Clade(branch_length=1.0)
Clade(branch_length=1.0, confidence=100)
Clade(branch_length=1.0, confidence=100)
Clade(branch_length=1.0, name='A')
Clade(branch_length=1.0, name='B')
Clade(branch_length=1.0, confidence=100)
Clade(branch_length=1.0, name='C')
Clade(branch_length=1.0, name='D')
Clade(branch_length=1.0, confidence=90)
Clade(branch_length=2.0, name='E')
Clade(branch_length=2.0, name='F')
Clade(branch_length=4.0, name='G')
系統樹の可視化
Bio.Phylo.draw()
メソッドでTreeオブジェクトの系統樹情報を可視化
Phylo.draw(tree)
全ノード取得
Treeオブジェクトのfind_clades()
メソッドで取得
各ノードはそれぞれ 1.name, 2.branch_length(枝長), 3.confidence(ブートストラップ値), 4.clades(子孫ノードリスト)プロパティを格納
for node in tree.find_clades():
print(f"Node name = {node.name}, ", end="")
print(f"Branch length = {node.branch_length}, ", end="")
print(f"Confidence = {node.confidence}, ", end="")
print(f"Descendants = {node.clades}")
Node name = None, Branch length = None, Confidence = 100, Descendants = [Clade(branch_length=1.0), Clade(branch_length=4.0, name='G')]
Node name = None, Branch length = 1.0, Confidence = None, Descendants = [Clade(branch_length=1.0, confidence=100), Clade(branch_length=1.0, confidence=90)]
Node name = None, Branch length = 1.0, Confidence = 100, Descendants = [Clade(branch_length=1.0, confidence=100), Clade(branch_length=1.0, confidence=100)]
Node name = None, Branch length = 1.0, Confidence = 100, Descendants = [Clade(branch_length=1.0, name='A'), Clade(branch_length=1.0, name='B')]
Node name = A, Branch length = 1.0, Confidence = None, Descendants = []
Node name = B, Branch length = 1.0, Confidence = None, Descendants = []
Node name = None, Branch length = 1.0, Confidence = 100, Descendants = [Clade(branch_length=1.0, name='C'), Clade(branch_length=1.0, name='D')]
Node name = C, Branch length = 1.0, Confidence = None, Descendants = []
Node name = D, Branch length = 1.0, Confidence = None, Descendants = []
Node name = None, Branch length = 1.0, Confidence = 90, Descendants = [Clade(branch_length=2.0, name='E'), Clade(branch_length=2.0, name='F')]
Node name = E, Branch length = 2.0, Confidence = None, Descendants = []
Node name = F, Branch length = 2.0, Confidence = None, Descendants = []
Node name = G, Branch length = 4.0, Confidence = None, Descendants = []
終端ノードのみ取得
Treeオブジェクトのget_terminals()
メソッドにより取得
count_terminals()
メソッドにより終端ノード数の取得も可能
print(tree.get_terminals())
print("終端ノード数 =", tree.count_terminals()
[Clade(branch_length=1.0, name='A'), Clade(branch_length=1.0, name='B'), Clade(branch_length=1.0, name='C'), Clade(branch_length=1.0, name='D'), Clade(branch_length=2.0, name='E'), Clade(branch_length=2.0, name='F'), Clade(branch_length=4.0, name='G')]
終端ノード数 = 7
内部ノードのみ取得
Treeオブジェクトのget_nonterminals()
メソッドにより取得
print(tree.get_nonterminals())
print("内部ノード数 =", len(list(tree.get_nonterminals())))
[Clade(confidence=100), Clade(branch_length=1.0), Clade(branch_length=1.0, confidence=100), Clade(branch_length=1.0, confidence=100), Clade(branch_length=1.0, confidence=100), Clade(branch_length=1.0, confidence=90)]
内部ノード数 = 6
ノードプロパティ変更
各ノード(Cladeオブジェクト)プロパティは下記のように変更可能
個人的には内部ノードに一意的な識別子を与える目的で利用することが多い。
for cnt, node in enumerate(tree.get_nonterminals()):
if node.name is None:
node.name = f"N{cnt}"
Phylo.draw(tree)
ノード検索
Treeオブジェクトのfind_clades()
メソッドでノード検索・取得
メソッド引数により検索対象・方法を設定可能
# 単純検索
print(list(tree.find_clades("A")))
print(list(tree.find_clades("N1")))
# 終端ノードのみを対象として検索
print(list(tree.find_clades("N1", terminal=True)))
# nameプロパティを対象として、正規表現検索
print(list(tree.find_clades({"name": "N.*"})))
# confidenceプロパティを対象として検索
print(list(tree.find_clades({"confidence": 90})))
[Clade(branch_length=1.0, name='A')]
[Clade(branch_length=1.0, name='N1')]
[]
[Clade(confidence=100, name='N0'), Clade(branch_length=1.0, name='N1'), Clade(branch_length=1.0, confidence=100, name='N2'), Clade(branch_length=1.0, confidence=100, name='N3'), Clade(branch_length=1.0, confidence=100, name='N4'), Clade(branch_length=1.0, confidence=90, name='N5')]
[Clade(branch_length=1.0, confidence=90, name='N5')]
終端ノード群の単系統判定
Treeオブジェクトのis_monophyletic()
メソッドにより対象とする終端ノード群が単系統か判定
- 対象が単系統である場合、単系統のノード名を返す
- 対象が単系統でない場合、Falseを返す
leaf_node_A = next(tree.find_clades("A"))
leaf_node_B = next(tree.find_clades("B"))
leaf_node_C = next(tree.find_clades("C"))
leaf_node_D = next(tree.find_clades("D"))
print("A-B単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_B))
print("A-C単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_C))
print("A-B-C-D単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_B, leaf_node_C, leaf_node_D))
A-B単系統ノード = N3
A-C単系統ノード = False
A-B-C-D単系統ノード = N2
ルートから対象ノードまでの全ノード経路リスト取得
Treeオブジェクトのget_path()
メソッドで取得
(全ノード経路リストにはルートの情報は含まない)
print("N3ノードまでの経路\n", tree.get_path(target="N3"))
print("Cノードまでの経路\n", tree.get_path(target="C"))
N3ノードまでの経路
[Clade(branch_length=1.0, name='N1'), Clade(branch_length=1.0, confidence=100, name='N2'), Clade(branch_length=1.0, confidence=100, name='N3')]
Cノードまでの経路
[Clade(branch_length=1.0, name='N1'), Clade(branch_length=1.0, confidence=100, name='N2'), Clade(branch_length=1.0, confidence=100, name='N4'), Clade(branch_length=1.0, name='C')]
最近共通祖先ノード取得
Treeオブジェクトのcommon_ancestor()
メソッドにより、引数指定の対象ノード群における最近共通祖先ノード取得
mrca_node1 = tree.common_ancestor("E", "F")
print("E-F 最近共通祖先 =", mrca_node1.name)
mrca_node2 = tree.common_ancestor("N3", "N4")
print("N3-N4 最近共通祖先 =", mrca_node2.name)
mrca_node1.color = "red"
mrca_node1.width = 2
mrca_node2.color = "blue"
mrca_node2.width = 2
Phylo.draw(tree)
E-F 最近共通祖先 = N5
N3-N4 最近共通祖先 = N2
各ノード深さ取得
Treeオブジェクトのdepth()
メソッドでノード深さ取得
(Key=各ノード,Value=対象ノードの深さ、としたディクショナリ形式)
print("枝の'数'で深さ算出\n", tree.depths(unit_branch_lengths=True))
print("枝の'長さ'で深さ算出\n", tree.depths(unit_branch_lengths=False)
枝の'数'で深さ算出
{Clade(confidence=100, name='N0'): 0, Clade(branch_length=1.0, name='N1'): 1, Clade(branch_length=1.0, confidence=100, name='N2'): 2, Clade(branch_length=1.0, confidence=100, name='N3'): 3, Clade(branch_length=1.0, name='A'): 4, Clade(branch_length=1.0, name='B'): 4, Clade(branch_length=1.0, confidence=100, name='N4'): 3, Clade(branch_length=1.0, name='C'): 4, Clade(branch_length=1.0, name='D'): 4, Clade(branch_length=1.0, confidence=90, name='N5'): 2, Clade(branch_length=2.0, name='E'): 3, Clade(branch_length=2.0, name='F'): 3, Clade(branch_length=4.0, name='G'): 1}
枝の'長さ'で深さ算出
{Clade(confidence=100, name='N0'): 0, Clade(branch_length=1.0, name='N1'): 1.0, Clade(branch_length=1.0, confidence=100, name='N2'): 2.0, Clade(branch_length=1.0, confidence=100, name='N3'): 3.0, Clade(branch_length=1.0, name='A'): 4.0, Clade(branch_length=1.0, name='B'): 4.0, Clade(branch_length=1.0, confidence=100, name='N4'): 3.0, Clade(branch_length=1.0, name='C'): 4.0, Clade(branch_length=1.0, name='D'): 4.0, Clade(branch_length=1.0, confidence=90, name='N5'): 2.0, Clade(branch_length=2.0, name='E'): 4.0, Clade(branch_length=2.0, name='F'): 4.0, Clade(branch_length=4.0, name='G'): 4.0}
対象ノード間の枝長取得
Treeオブジェクトのdistance()
メソッドにより引数指定の対象ノード間の枝長取得
print("A-B distance =", tree.distance(target1="A", target2="B"))
print("C-G distance =", tree.distance(target1="C", target2="G"))
print("N3-N5 distance =", tree.distance(target1="N3", target2="N5")
A-B distance = 2.0
C-G distance = 8.0
N3-N5 distance = 3.0
系統樹全体の枝長総和取得
Treeオブジェクトのtotal_branch_length()
メソッドで取得
print("枝長総和 =", tree.total_branch_length())
枝長総和 = 17.0
全実行ソースまとめ
from io import StringIO
from Bio import Phylo
from Bio.Phylo.BaseTree import Tree
print("### 系統樹データ読み込み ###")
treedata = "((((A:1,B:1)100:1,(C:1,D:1)100:1)100:1,(E:2,F:2)90:1):1,G:4)100;"
tree: Tree = Phylo.read(file=StringIO(treedata), format="newick")
print(tree)
print("### 系統樹の可視化 ###")
Phylo.draw(tree)
print("### 全ノード取得 ###")
for node in tree.find_clades():
print(f"Node name = {node.name}, ", end="")
print(f"Branch length = {node.branch_length}, ", end="")
print(f"Confidence = {node.confidence}, ", end="")
print(f"Descendants = {node.clades}")
print("### 終端ノードのみ取得 ###")
print(tree.get_terminals())
print("終端ノード数 =", tree.count_terminals())
print("### 内部ノードのみ取得 ###")
print(tree.get_nonterminals())
print("内部ノード数 =", len(list(tree.get_nonterminals())))
print("### ノードプロパティ変更 ###")
for cnt, node in enumerate(tree.get_nonterminals()):
if node.name is None:
node.name = f"N{cnt}"
Phylo.draw(tree)
print("### ノード検索 ###")
# 単純検索
print(list(tree.find_clades("A")))
print(list(tree.find_clades("N1")))
# 終端ノードのみを対象として検索
print(list(tree.find_clades("N1", terminal=True)))
# nameプロパティを対象として、正規表現検索
print(list(tree.find_clades({"name": "N.*"})))
# confidenceプロパティを対象として検索
print(list(tree.find_clades({"confidence": 90})))
print("### 終端ノード群の単系統判定 ###")
leaf_node_A = next(tree.find_clades("A"))
leaf_node_B = next(tree.find_clades("B"))
leaf_node_C = next(tree.find_clades("C"))
leaf_node_D = next(tree.find_clades("D"))
print("A-B単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_B))
print("A-C単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_C))
print("A-B-C-D単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_B, leaf_node_C, leaf_node_D))
print("### ルートから対象ノードまでの全ノード経路リスト取得 ###")
print("N3ノードまでの経路\n", tree.get_path(target="N3"))
print("Cノードまでの経路\n", tree.get_path(target="C"))
print("### 最近共通祖先ノード取得 ###")
mrca_node1 = tree.common_ancestor("E", "F")
print("E-F 最近共通祖先 =", mrca_node1.name)
mrca_node2 = tree.common_ancestor("N3", "N4")
print("N3-N4 最近共通祖先 =", mrca_node2.name)
mrca_node1.color = "red"
mrca_node1.width = 2
mrca_node2.color = "blue"
mrca_node2.width = 2
Phylo.draw(tree)
print("### 各ノード深さ算出 ###")
print("枝の'数'で深さ算出\n", tree.depths(unit_branch_lengths=True))
print("枝の'長さ'で深さ算出\n", tree.depths(unit_branch_lengths=False))
print("### 対象ノード間の枝長取得 ###")
print("A-B distance =", tree.distance(target1="A", target2="B"))
print("C-G distance =", tree.distance(target1="C", target2="G"))
print("N3-N5 distance =", tree.distance(target1="N3", target2="N5"))
print("### 系統樹全体の枝長総和算出 ###")
print("枝長総和 =", tree.total_branch_length())