背景
微生物の種の系統樹をアノテーションする時に、GTDBから取得した系統樹をiTOLでアノテーションしたいという人は私以外にもいるかもしれません。現状では、GTDBから取得した系統樹そのままでは、iTOLで正常に開くことができません。その解決方法をまとめました。
用語説明
GTDBとは
GTDB(Genome Taxonomy Database)は、ゲノム系統発生に基づく標準的な微生物分類を確立するために作成されたデータベースです。このデータベースでは、バクテリアの120個の単一コピーマーカー遺伝子の連結セットを使用して推定(FastTreeを使用)されたゲノムツリーと、アーキアの53個(R07-RS207以降)のマーカー遺伝子の連結セットによるゲノムツリーが収録されています。加えて、これら微生物のゲノム配列も収録されています。
iTOLとは
iTOLは、系統樹の表示、注釈付け、管理を行うオンラインツールです。iTOLを使えば、系統樹の図をかっこよくつくることができます。
課題
「GTDBから取得した系統樹をiTOLで開くことができない」
正確には、ファイルを開くことはできますが、一部の枝しか表示されていません。GTDB-TKには、convert_to_itolというメソッドが用意されており、これを使えば問題は解決します。しかし、GTDB-Tkを使用するには、110Gほどのデータをダウンロードする必要があるなど、セットアップが面倒くさいです。そこで、convert_to_itolの部分を抜き出したサンプルプログラムを作成しました。
サンプルプログラム
添付したconvert_to_itol.pyをこのように実行すれば($ python convert_to_itol.py ./bac120.tree ./bac120_to_itol_noboot.tree
)、iTOLで表示できるツリーファイルに変換できます。第一引数はGTDBから取得したファイルのパスで、第二引数は出力のファイルのパスです。このコードを実行するには、dendropyをインストールする必要があります。また、出力したファイルではブートストラップ値を除去しています。
import dendropy
import sys
def is_float(s):
"""Check if a string can be converted to a float.
Parameters
----------
s : str
String to evaluate.
Returns
-------
boolean
True if string can be converted, else False.
"""
try:
float(s)
except ValueError:
return False
return True
def parse_label(label):
"""Parse a Newick label which may contain a support value, taxon, and/or auxiliary information.
Parameters
----------
label : str
Internal label in a Newick tree.
Returns
-------
float
Support value specified by label, or None
str
Taxon specified by label, or None
str
Auxiliary information, on None
"""
support = None
taxon = None
auxiliary_info = None
if label:
label = label.strip()
if '|' in label:
label, auxiliary_info = label.split('|')
if ':' in label:
support, taxon = label.split(':')
support = float(support)
else:
if is_float(label):
support = float(label)
elif label != '':
taxon = label
return support, taxon, auxiliary_info
def convert_to_itol(input_file, output_file):
intree= dendropy.Tree.get_from_path(input_file,
schema='newick',
rooting='force-rooted',
preserve_underscores=True)
for node in intree.internal_nodes():
if node.label:
bootstrap,label,_aux = parse_label(node.label)
if label:
label = label.replace('; ',';').replace(';','|').replace("'","").lstrip('')
node.label = label
if node.edge.length:
#node.edge.length = f'{node.edge.length}[{bootstrap}]'
node.edge.length = f'{node.edge.length}'
intree.write_to_path(output_file, schema='newick', suppress_rooting=True,unquoted_underscores=True)
if __name__ == '__main__':
input_file = sys.argv[1]
output_file = sys.argv[2]
convert_to_itol(input_file, output_file)
結果
参考