FASTA形式の塩基配列(アミノ酸配列)ファイルをNEXUS形式やPHYLIP形式に変換したい、ということはよくあります。単一のファイルならClustalwやMacCladeを使用して変換できますが、多数のFASTAファイルを扱う場合(数百〜数千遺伝子を用いた系統解析など)、一括でファイル形式を変換するスクリプトがあれば便利です。
ここでは、FASTA形式 --> NEXUS形式、またはFASTA形式 --> PHYLIP形式へ変換するPerlスクリプトを公開します。アラインメント自体は行わないので、すでにアラインメントされたFASTA形式ファイルのみが対象になります。また、配列名は9文字まで、という制約があります。
(1) fasta_to_nex.pl
#!/usr/bin/perl # fasta_to_nex.pl # 2015-04-07 Y Hashiguchi # fasta format をnexus formatに変更する # interleaveしない # sequenceの開始位置をそろえる # ntax, ncharをカウント # このversionはMrBayes blockを書き加えない // 150407 # comment outはあり ## usage ## # ./fasta_to_nex.pl [infile.fa|.aln|.fasta|.fas] > [outfile.nex] # use strict; use warnings; ### Define variables ## my $fname = $ARGV[0]; my @lines = (); # infileの各行を入れる配列 my @seq_with_name = (); #名前付きsequenceを入れる配列 my $ntax = 0; # taxa数 my $nchar = 0; # character数(gapやNも含むsequence長さ) my $seq_data = 0; # sequence with name my $datatype = 'dna'; #data type (dna or protein) my %sequence; #sequence nameおよびsequenceを入れるhash ## ### MAIN ### # input file (FASTA) の読み込み @linesに入れる open (FASTA, "$fname") || die "Cannot open file:$!"; while(<FASTA>) { chomp; push(@lines, $_); } close(FASTA); # taxa数をcount (= ">"の数を数える) foreach my $line (@lines) { $ntax++ if($line =~ /\>/); } $sequence{"Name"} = shift(@lines); #最初の1配列の名前(1行目)は$sequence{"Name"}に入れる $sequence{"Name"} =~ s/\>//; # ">"を除く while ($#lines > -1) { my $data = shift(@lines); if($data =~ /\>/) { $nchar = length($sequence{"Sequence"}); # test while(length($sequence{"Name"}) < 10) { #長さが10文字まで // ここでは、nameの長さが10文字より少ないことを仮定している $sequence{"Name"} .= " "; # 後ろに" "を加える } # print $ntax, "\t", $nchar, "\n"; # test $seq_data = $sequence{"Name"} . $sequence{"Sequence"}; #nameとsequence統合 push(@seq_with_name, $seq_data); #配列 @seq_with_nameに結果入れる # print $sequence{"Name"}, $sequence{"Sequence"}, "\n"; # test $sequence{"Sequence"} = ""; # sequence中身を削除 $sequence{"Name"} = $data; #sequence_name代入 $sequence{"Name"} =~ s/\>//; # ">"を除く } else { $sequence{"Sequence"} .= $data; } } # 最後の1配列について while(length($sequence{"Name"}) < 10) { #長さが10文字まで $sequence{"Name"} .= " "; # 後ろに" "を加える } $seq_data = $sequence{"Name"} . $sequence{"Sequence"}; #nameとsequence統合 push(@seq_with_name, $seq_data); #配列 @seq_with_nameに結果入れる ## print out as ".nex" format print '#NEXUS', "\n\n"; print '[', "\n", 'Data from:', "\n", $ARGV[0], "\n", ']', "\n\n\n"; print 'begin data;', "\n ", 'dimensions ntax=', $ntax, ' nchar=', $nchar, ';', "\n"; print ' format datatype=', $datatype, ' interleave=no gap=-;', "\n"; print ' matrix', "\n"; foreach(@seq_with_name) { # test print $_, "\n"; } print ' ;', "\n"; print 'end;', "\n";
(2) fasta_to_phy.pl
#!/usr/bin/perl # fasta_to_phy.pl # 2015-04-07 Y Hashiguchi # fasta format をPHYLIP formatに変更する # fasta_to_nex.plの副産物としてできた(おまけ) # interleaveしない # sequenceの開始位置をそろえる # ntax, ncharをカウント # alignment済みのfasta file (.aln)のみ対応、これ自体はalignmentは行わない # comment outはあり ## usage ## # ./fasta_to_nex.pl [infile.fa|.aln|.fasta|.fas] > [outfile.phy] # use strict; use warnings; ### Define variables ## my $fname = $ARGV[0]; my @lines = (); # infileの各行を入れる配列 my @seq_with_name = (); #名前付きsequenceを入れる配列 my $ntax = 0; # taxa数 my $nchar = 0; # character数(gapやNも含むsequence長さ) my $seq_data = 0; # sequence with name my %sequence; #sequence nameおよびsequenceを入れるhash ## ### MAIN ### # input file (FASTA) の読み込み @linesに入れる open (FASTA, "$fname") || die "Cannot open file:$!"; while(<FASTA>) { chomp; push(@lines, $_); } close(FASTA); # taxa数をcount (= ">"の数を数える) foreach my $line (@lines) { $ntax++ if($line =~ /\>/); } $sequence{"Name"} = shift(@lines); #最初の1配列の名前(1行目)は$sequence{"Name"}に入れる $sequence{"Name"} =~ s/\>//; # ">"を除く while ($#lines > -1) { my $data = shift(@lines); if($data =~ /\>/) { $nchar = length($sequence{"Sequence"}); # test while(length($sequence{"Name"}) < 10) { #長さが10文字まで $sequence{"Name"} .= " "; # 後ろに" "を加える } # print $ntax, "\t", $nchar, "\n"; # test $seq_data = $sequence{"Name"} . $sequence{"Sequence"}; #nameとsequence統合 push(@seq_with_name, $seq_data); #配列 @seq_with_nameに結果入れる # print $sequence{"Name"}, $sequence{"Sequence"}, "\n"; # test $sequence{"Sequence"} = ""; # sequence中身を削除 $sequence{"Name"} = $data; #sequence_name代入 $sequence{"Name"} =~ s/\>//; # ">"を除く } else { $sequence{"Sequence"} .= $data; } } # 最後の1配列について while(length($sequence{"Name"}) < 10) { #長さが10文字まで $sequence{"Name"} .= " "; # 後ろに" "を加える } $seq_data = $sequence{"Name"} . $sequence{"Sequence"}; #nameとsequence統合 push(@seq_with_name, $seq_data); #配列 @seq_with_nameに結果入れる #print $sequence{"Name"}, $sequence{"Sequence"}, "\n"; #最後のsequenceをprint print $ntax, " ", $nchar, "\n"; foreach(@seq_with_name) { print $_, "\n"; }
複数ファイルを一括で変換する場合は、以下のshell scriptを使用して下さい。カレントディレクトリにあるすべての".aln"拡張子を持つFASTA形式のファイルを変換します(注意:clustal formatには対応していません! 拡張子.alnでも)
(1) FtoN.sh
#!/usr/bin/sh # FtoN.sh # FASTA -> NEXUSへのformat変換 # Current directoryに存在するすべてのfileで実行 # alignment済みのファイル (.aln)のみ、alignmentそれ自体は行わない # mrbayes blockは追加しない # 結果はphy_files directoryに入る mkdir nex_files for fname in *.aln; do fname=`echo "$fname" | sed -E 's/\.aln//g'` # 拡張子を除く # .fasta(.aln) --> .nexに変換 // fasta_to_nex.pl使用 ./fasta_to_nex.pl $fname.aln > $fname.nex mv $fname.nex nex_files done
(2) FtoP.sh
#!/usr/bin/sh # FtoP.sh # FASTA -> PHYLIPへのformat変換 # Current directoryに存在するすべてのfileで実行 # alignment済みのファイル (.aln)のみ、alignmentそれ自体は行わない # mrbayes blockは追加しない # 結果はnex_files directoryに入る mkdir phy_files for fname in *.aln; do fname=`echo "$fname" | sed -E 's/\.aln//g'` # 拡張子を除く # .fasta(.aln) --> .phyに変換 // fasta_to_phy.pl使用 ./fasta_to_phy.pl $fname.aln > $fname.phy mv $fname.phy phy_files done
ファイル形式の変換、一般的に、FASTAから別の形式への変換を行うことは多いですが、逆のパターンは少ない気がします。