前言 因为这一段时间很懒而且现实生活的事情又多,所以系统发育分析的正式文章教程可能要搁置一会,但是想着总得更新些东西出来,所以就以这篇文章作为正餐开始前的一叠小菜分享分享。
事实上序列串联对于刚涉及到这一块的新手来说确实也会有些迷糊,比如说串联是怎么个串联法,需要准备什么文件,文件的内容格式应该是怎样等等问题都会存在,这篇文里就针对这一点讲一讲。
更新日志 2023-04-07 简化了脚本,并完善了脚本的注释。
2023-07-04 完善了脚本,并添加了部分内容。
需要知道的知识 一些系统发育分析中的概念是最基础的,如果未作了解或了解不深可以看一下这篇文章:生命之树及其应用 。写的非常全面和具体,里面涉及到的各种术语也很专业,同时也介绍了很多常用的软件等。本文涉及到的地方就是这篇文章展望部分中第一点讲的 “超大树构建方法的革新” 中的超矩阵方法。
序列串联方法 需要准备的文件 首先按照惯例推出几个能够实现的软件:Phylosuite
、FASconCAT-G
。前者用起来非常方便但是我只下了 windows 的版本,虽然它有 linux 的版本但我也没去调查怎么用,索性就自己写了个脚本进行序列串联。
先说明需要的文件内容格式:
1 2 3 4 5 6 >tax1@seq1 ABCDEFG >tax2@seq1 ABCDEEG >tax3@seq1 ACCDEEG
这是一个由不同物种的同源基因组成的多序列比对,其中不同 tax 代表不同的物种,以 @ 作为分隔符,其后对应不同物种的同源序列名称。对应的序列是已经经过比对修剪的序列,允许 gap 存在。每个物种至多存在一条序列 。例(我随便编的):
这是一个同源序列(蛋白):
1 2 3 4 5 6 >Human@human_1215 AAABKISPLM >Mouse@mouse_98455 AAXBKISPLM >Fish@fish_1561 AAABKISPNM
这是另一个同源序列(蛋白):
1 2 3 4 5 6 >Human@human_5372 CJBSODNONVOIAA >Mouse@mouse_12389 CJBSODNNNVOIAS >Fish@fish_1001 DJBSODNBNVOIAS
串联的意思是把它们串成这样(一个比对中不一定包含所有物种,串联以后该比对不存在的物种会全部以 gap 代替 ):
1 2 3 4 5 6 >Human AAABKISPLMCJBSODNONVOIAA >Mouse AAXBKISPLMCJBSODNNNVOIAS >Fish AAABKISPNMDJBSODNBNVOIAS
串成这样以后,也要有对应的 partition 信息以供软件进行超矩阵算法。
对我而言,实现上述操作的方法有两种:
①、简化 ID 成物种编号(就是把 @ 以及后面的序列编号全删了)。
②、将处理后的序列输入 Phylosuite 处理。
编写脚本一步到位。
对于第一种方法如果序列比较少是没什么问题,因为下载到 windows 不用多久(当然如果会 phylosuite 的 Linux 端操作也会变得非常方便),但是如果涉及到的序列很多且很大那就只能自己动手丰衣足食了。
脚本
2023-07-04 引流补充:
如果是 Windows 系统:不嫌麻烦的话可以下载我基于 PyQt5 编写的 JuseKit ,其中包含序列串联功能且输出信息更完善。
如果是 Linux 系统,以下是我编写的序列串联脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 import osIQpartition = '#nexus\nbegin sets;\n' total_length = 0 total_spe_seq = {} total_num = len (os.listdir('./' )) compl_num = 0 aligns = os.listdir('./' ) aligns.sort() for align in aligns: with open (align, 'r' ) as ali: tmp_len = 0 tmp_species = [] for line in ali: if line.startswith('>' ) and line.strip() != '>' : spe_name = line.split('@' )[0 ].strip() tmp_species.append(spe_name) if spe_name not in total_spe_seq.keys(): total_spe_seq[spe_name] = '-' *total_length elif line.strip() == '>' or line.strip() == '' : continue else : if len (tmp_species) == 1 : tmp_len += len (line.strip()) total_spe_seq[spe_name] += line.strip('>' ).strip() for spe in total_spe_seq.keys(): if spe not in tmp_species: total_spe_seq[spe] += '-' *tmp_len charsetid = align.split('.' )[0 ] IQpartition += f"\tcharset {charsetid} ={total_length+1 } -{total_length+tmp_len} ;\n" total_length += tmp_len compl_num += 1 print (f"The progress is {compl_num} /{total_num} ..." ) os.mkdir("con_res" ) with open ("con_res/sequence_con.log" , 'w' ) as log: log.write("Species\tLength\n" ) for spe in total_spe_seq.keys(): if len (total_spe_seq[spe]) == total_length: log.write(f"{spe[1 :]} \t{len (total_spe_seq[spe])} AA\t+\n" ) else : log.write(f"{spe[1 :]} \t{len (total_spe_seq[spe])} AA\t-\n" ) print ("See running log in con_res/sequence_con.log" ) with open ("con_res/concatenation_ortho.fasta" , 'w' ) as f: for spe in total_spe_seq: f.write(spe + '\n' + total_spe_seq[spe] + '\n' ) with open ("con_res/IQ_partition.txt" , 'w' ) as f: f.write(IQpartition) f.write("end;" ) print ('Finished, see output at con_res.' )
原理比较简单,不过相对于其他软件的处理而言,这个脚本还可以解决 “空序列” 的问题。
运行也很简单,在存放多序列比对文件的文件夹中输入 python /path/sequence_con.py
即可(脚本不要放里面,也不要存在其他类型的文件 ,因为我没有加尾缀识别的判断语句)。
运行结束后会多出一个 con_res
的文件夹,里面有合并后的序列 concatenation_ortho.fasta
以及用于 IQtree 建树的分区信息(IQ_partition.txt),此外也有一个运行日志 sequence_con.log
,里面记录了每个物种的序列长度信息,最后一列为 +
则表示与第一个长度一致,理应上所有的物种都应该为 +
,如果出现 -
号则说明该物种的某些比对存在错误,长度与其他物种不一致。
后记 这一段时间完全放飞自我,正事没咋干摸鱼摸一堆,一方面是身不由己另一方面确实打不起什么劲,说明环境对于人的影响还是非常显著的。
相关的 python 脚本同以前一样放在了 github 里,感兴趣可以自取,若是不嫌麻烦事实上 phylosuite 也是个不错的选择(国人软件,能多引一个是一个)。