如何用Bash将Newick格式进化树文件转换为指定表格?
Newick进化树转制表符分隔表格的解决方案
问题背景
现有Newick格式进化树文件input.txt,内容如下:
(((((((hg38:0.00390111,panTro4:0.00466345):0.0067608,ponAbe2:0.0116062):0.00867419,((((rheMac3:0.00199139,macFas5:0.00136397):0.00219754,papAnu2:0.00373049):0.00221139,chlSab2:0.00690005):0.00434788,(nasLar1:0.00415921,rhiRox1:0.00361872):0.0075705):0.0149329):0.0129667,(calJac3:0.025809,saiBol1:0.0245054):0.0316131):0.0521649,tarSyr2:0.113368):0.00737652,(micMur1:0.0695349,otoGar3:0.105996):0.0356137):0.00510281,mm10:0.304925);
尝试用Bash转换为制表符分隔表格时,出现物种名与数值粘连、分支未按物种组合命名的问题。期望输出满足:
- 内部分支用子节点物种/分支名的组合命名(如
hg38-panTro4) - 进化距离与对应分支/物种精准对应
- 无明确子节点的根分支用带编号的
branch_*标识
解决脚本
编写newick2table.awk脚本,利用栈结构解析Newick的嵌套节点:
#!/usr/bin/awk -f BEGIN { FS = "[(),:]"; print "分支名称\t进化距离"; branch_count = 0; } { sub(/;$/, "", $0); stack_ptr = 0; for (i=1; i<=NF; i++) { if ($i == "") continue; if ($i ~ /^[0-9.]+$/) { if (stack_ptr > 0) { branch_name = stack[stack_ptr]; stack_ptr--; } else { branch_name = "branch_" ++branch_count; } printf "%s\t%s\n", branch_name, $i; } else { stack[++stack_ptr] = $i; if (stack_ptr >= 2) { combined = stack[stack_ptr-1] "-" stack[stack_ptr]; stack_ptr -= 2; stack[++stack_ptr] = combined; } } } if (stack_ptr > 0) { printf "branch_%d\t%s\n", ++branch_count, stack[stack_ptr]; } }
运行方式
执行以下命令生成表格:
awk -f newick2table.awk input.txt
脚本说明
- 字段分割:用
[(),:]作为分隔符,拆分Newick字符串中的节点名和进化距离 - 栈处理逻辑:
- 遇到物种/分支名时压入栈,当栈中有两个元素时,将其组合为
A-B格式的父分支名,替换原有的两个元素 - 遇到进化距离时,从栈顶取出对应的分支名,输出制表符分隔的行
- 遇到物种/分支名时压入栈,当栈中有两个元素时,将其组合为
- 根分支处理:解析完成后若栈中仍有剩余节点,自动生成带编号的
branch_*标识
示例输出
分支名称 进化距离 hg38-panTro4 0.0067608 hg38-panTro4-ponAbe2 0.00867419 rheMac3-macFas5 0.00219754 rheMac3-macFas5-papAnu2 0.00221139 rheMac3-macFas5-papAnu2-chlSab2 0.00434788 nasLar1-rhiRox1 0.0075705 ...
内容的提问来源于stack exchange,提问作者Jontexas
相关产品推荐
相关产品推荐

