跟著Science學保守元件(Conserved Elemtns)的鑒定

0.代碼來源
文章參考:
《Large-scale ruminant genome sequencing provides insights into their evolution and distinct traits》
DOI: 10.1126/science.aav6202
后面簡稱'原文'
本文很貼心的給出了整個保守元件(CE, Conserved Element)的鑒定流程以及所用到的腳本.
https://zenodo.org/record/2549147
如果用到這個代碼,請注明代碼來源并引用這篇文章


  1. 軟件的安裝
    參見: http://compgen.cshl.edu/phast

2.多基因組比對
這里也可以參考以下兩個鏈接
https://biochen.org/cn/blog/2021/%E5%A2%9E%E5%BC%BA%E7%89%88%E4%B8%A4%E5%9F%BA%E5%9B%A0%E7%BB%84%E6%AF%94%E5%AF%B9/
https://biochen.org/cn/blog/2021/%E5%A4%9A%E5%9F%BA%E5%9B%A0%E7%BB%84%E6%AF%94%E5%AF%B9/

假設已經(jīng)拿到了最后的maf文件
這里只演示一條染色體的結(jié)果


3.1 mod文件的獲取
PS: 原文獲取mod的做法較為繁瑣
具體見本文末尾 4. 一節(jié), 有完整的復現(xiàn)

這里先展示一種較為簡單的方法,
此處參考: https://biochen.org/cn/blog/2021/%E4%BD%BF%E7%94%A8PHAST%E5%88%86%E6%9E%90%E4%BF%9D%E5%AE%88%E6%80%A7/
以及官方給出的pipeline (真的比原文的做法簡單太多):
http://compgen.cshl.edu/phast/phyloP-tutorial.php

phyloFit  -i MAF  Chr1.maf  --tree  "(((((A, B), (C, D)), E), F), G)"
#輸出文件phyloFit.mod
#用作后續(xù)分析

輸出文件phyloFit.mod以用作后續(xù)分析


3.2 CE的鑒定

phastCons  Chr1.maf   phyloFit.mod   --target-coverage 0.25 --expected-length 12 --rho 0.4 --msa-format MAF --seqname Chr1  --most-conserved Chr1.CE.bed > Chr1.conserved.score.wig

輸出文件1是Chr1.CE.bed, 這個就是保守元件的bed文件, 還有一個Chr1.conserved.score.wig是CE每個bp的保守性得分
其實做到這里就已經(jīng)算是完成了, 但是可以再多做一點
比如我的進化樹包含了 A - G總共7個物種,但是A-D才是我的研究物種, 我想把CE過濾到A-D上
按照原文的做法, 有兩種過濾方式, 首先把長度小于20bp的CE都過濾掉(這一步驟本文就略去)

第一是CE的 EFG三個外群物種上是沒有序列可以比對到的
或者說只有A-D也就是研究物種中才能找到的,研究物種特有的CE

第二是CE在外群物種中也有, 但是在研究物種中是 '保守的' 或者 '加速進化的' (基于看不懂的LRT test一大堆, 參考http://compgen.cshl.edu/phast/help-pages/phyloP.txt)


3.3 過濾CE (具體用到的腳本在本文末尾或者從zendo上自己下載)
3.3.1 首先是得到第一種CE:
修改腳本maf_bed_filter_Type1.pl
把這個腳本的標注出來的這一行, 修改為maf文件中外群物種的具體名稱


修改我高亮的地方
perl maf_bed_filter_Type1.pl Chr1.CE.bed Chr1.maf ./
#會生成work.out, 這個就是外群沒有,研究物種特有的CE,但是格式不是bed格式

#下面就是把work.out轉(zhuǎn)為bed文件
perl work_out2bed.pl work.out Chr1 ./ 
#輸出文件是Chr1.bed, 這就是第一種CE了


#做一下長度過濾, 低于20bp的扔掉
for i in {1..28}
do
awk '{if($3-$2>19)print}' Chr${i}.bed > Chr${i}.tmp && rm Chr${i}.bed && rename .tmp .Type1.bed *
done

3.3.2 其次是第二種CE
修改腳本01.convertMaf2List.pl
第一個紅色箭頭修改為maf文件作為參考基因組的物種的具體名稱
第二個紅色箭頭修改為maf文件的所有物種的名稱


修改紅色箭頭所示地方

修改mod文件 phyloFit.mod
在研究物種的祖先節(jié)點處加上標識, 這里表示我把我的研究物種的祖先節(jié)點命名為'Node'


修改紅色箭頭所示的地方

文件修改完畢,開始跑后續(xù)

perl   01.convertMaf2List.pl  Chr1.maf   Chr1
#輸出的Chr1.maf.lst用作后續(xù)

phyloP --subtree Node --msa-format MAF --features Chr1.CE.bed -method LRT --mode CONACC phyloFit.mod Chr1.maf > Chr1.phyloP.bed
#--subtree Node 這里就是前面提及的研究物種的祖先節(jié)點
#--features Chr1.CE.bed 最開始鑒定出來的CE
#-method LRT  大概是用了什么統(tǒng)計檢驗, 但我看不懂
#--mode CONACC  這個模式下除了能看研究物種相比于外群物種保守, 還能看研究物種相比于外群物種快速進化的

#最后輸出Chr1.phyloP.bed

輸出文件Chr1.phyloP.bed長這樣:


Chr1.phyloP.bed

最后一列如果小于0, 表示研究物種相比于外群物種快速進化的CE
最后一列如果大于0,研究物種相比于外群物種保守的CE

最后再卡一下顯著性閾值和做一下p值校正, 這里就不再贅述

 head -n 1 Chr10.phyloP.bed > head

for i in {1..28}
do
awk '{if($9<0.05 && $9>0)print}' Chr${i}.phyloP.bed > Chr${i}.tmp && cat head Chr${i}.tmp > Chr${i}.phyloP.conservation.bed && rm Chr${i}.tmp
done

for i in {1..28}             
do
awk '{if($9>-0.05 && $9<0)print}' Chr${i}.phyloP.bed > Chr${i}.tmp && cat head Chr${i}.tmp > Chr${i}.phyloP.acceleration.bed && rm Chr${i}.tmp 
done

for i in {1..28}
do
awk '{if($3-$2>19)print}' Chr${i}.phyloP.acceleration.bed > Chr${i}.tmp && cat head Chr${i}.tmp > ../Acceleration/Chr${i}.acceleration.CE.bed && rm Chr${i}.tmp
done

for i in {1..28}
do
awk '{if($3-$2>19)print}' Chr${i}.phyloP.conservation.bed > Chr${i}.tmp && cat head Chr${i}.tmp > ../Type2/Chr${i}.Type2.bed && rm Chr${i}.tmp          
done


#####
#使用wigToBigWig將wig文件轉(zhuǎn)換為二進制的bigWig文件后,就能在Genome Browser中展示了
#wigToBigWig in.wig chrom.sizes out.bw

for i in {1..28}
do         
/data/01/user164/software/wigToBigWig Chr${i}.CE.wig Golani.Chr.v4.length Chr${i}.CE.bw
done

#假設給定一條序列比如lncRNA,我們想計算它的平均phastCons分數(shù)
#可以使用bigWigAverageOverBed實現(xiàn)
#bigWigAverageOverBed in.bw in.bed out.tab

for i in {1..28}
do
/data/01/user164/software/bigWigAverageOverBed Chr${i}.CE.bw /data/01/user164/workspace_for_whole_object/spalax_SV/10.CE/Ruminant.Pipe.9spp/CE.bed/Chr${i}.CE.bed Chr${i}.tmp;
awk '{print $1"\t"$2"\t"$4"\t"$5}' Chr${i}.tmp > Chr${i}.CE.score; rm Chr${i}.tmp;
done

cat *.CE.score | sort -Vk 1 > all.CE.score
awk '{if($2>19)print}' all.CE.score > all.CE.dayu20bp.score

4.原文的做法
4.1 4d.nonconserved.mod文件的獲取
其實和我前文中相比沒有太大改變, 只不過原文中用了4d位點
那么首先從maf文件中提取4D位點:
這里參考了: http://compgen.cshl.edu/phast/phastCons-HOWTO.html

#依然是使用phast包內(nèi)置的軟件
msa_view  Chr1.maf  --in-format MAF  --4d  --features Chr1.gff  > Chr1.4d-codons.ss
msa_view Chr1.4d-codons.ss --in-format SS --out-format SS --tuple-size 1 > Chr1.4d-sites.ss
#對每條染色體重復這個操作
for i in {1..10}
do
msa_view  split_maf/Chr/Chr${i}.maf --in-format MAF --4d --features gff/Chr${i}.gff > 4d.site/Chr${i}.4d.ss
msa_view 4d.site/Chr${i}.4d-codons.ss  --in-format SS --out-format SS --tuple-size 1 > 4d.site/Chr${i}.4d-sites.ss
done

msa_view --unordered-ss --out-format SS --aggregate go,ca,ju,ga,Mus,Rat,Hamster,Squirrel,Rabbit Chr1.4d-sites.ss,Chr2.4d-sites.ss,Chr3.4d-sites.ss,Chr4.4d-sites.ss,Chr5.4d-sites.ss,Chr6.4d-sites.ss,Chr7.4d-sites.ss,Chr8.4d-sites.ss,Chr9.4d-sites.ss,Chr10.4d-sites.ss > all-4d.sites.ss

phyloFit --tree species.tree -i SS all-4d.sites.ss --out-root 4d.nonconserved
#用上述流程即可



#以上是標準的流程, 由于我的maf文件存在一些問題
#故進行修改
for i in {1..28}
do
msa_view split_maf/Chr/Chr${i}.maf --in-format MAF --4d --features gff/Chr${i}.gff > 9spp.4d.site/Chr${i}.tmp1

msa_view 9spp.4d.site/Chr${i}.tmp1 --in-format SS --out-format SS --tuple-size 1 > 9spp.4d.site/Chr${i}.tmp2

msa_view 9spp.4d.site/Chr${i}.tmp2 --in-format SS --out-format FASTA > 9spp.4d.site/Chr${i}.tmp3

samtools faidx 9spp.4d.site/Chr${i}.tmp3   

for c in {go,ca,ga,ju,Mus,Rat,Hamster,Squirrel,Rabbit}
do
samtools faidx 9spp.4d.site/Chr${i}.tmp3 $c >> 9spp.4d.site/Chr${i}.tmp4      
done

mv 9spp.4d.site/Chr${i}.tmp4 9spp.4d.site/Chr${i}.4d-sites.fasta      
msa_view 9spp.4d.site/Chr${i}.4d-sites.fasta --in-format FASTA --out-format SS > 9spp.4d.site/Chr${i}.4d-sites.ss
done
msa_view --u
nordered-ss --out-format SS --aggregate go,ca,ju,ga,Mus,Rat,Hamster,Squirrel,Rabbit Chr1.4d-sites.ss,Chr2.4d-sites.ss,Chr3.4d-sites.ss,Chr4.4d-sites.ss,Chr5.4d-sites.ss,Chr6.4d-sites.ss,Chr7.4d-sites.ss,Chr8.4d-sites.ss,Chr9.4d-sites.ss,Chr10.4d-sites.ss > all-4d.sites.ss
phyloFit --tree species.tree -i SS all-4d.sites.ss --out-root 4d.nonconserved
##

這一套操作下來, 得到文件: 4d.nonconserved.mod

4.2 estimating rho

for i in {1..10}
do
mkdir Chr${i} && cd Chr${i}
msa_split Chr${i}.maf --in-format MAF  --windows 1000000,0 --out-root split --out-format SS --min-informative 1000 --between-blocks 5000  #切割maf文件
done


#以單條染色體為例, 每條染色體重復以下操作
ls *.ss > ss.list
for ss in `cat ss.list`;do phastCons --estimate-rho $ss --no-post-probs $ss 4d.nonconserved.mod ;done
#4d.nonconserved.mod就是4.1的輸出文件

ls *.cons.mod >all.cons.mod.list
ls *.noncons.mod > all.noncons.mod.list
phyloBoot --read-mods all.cons.mod.list --output-average Chr1.ave.cons.mod
phyloBoot --read-mods all.noncons.mod.list --output-average Chr1.ave.noncons.mod

###
20250328更新
phyloBoot有些版本好像不能識別mod.list文件
所以得手動把所有的mod文件都放進命令行中:
phyloBoot --read-mods mod1,mod2,mod3... --output-average Chr1.ave.cons.mod

phastCons --most-conserved Chr1.CE.bed --score Chr1.maf Chr1.ave.cons.mod,Chr1.ave.noncons.mod \> Chr1.wig
#以單條染色體為例, 每條染色體重復以上操作
#如此原文的CE鑒定部分就結(jié)束, 后面對CE進行分類/過濾與本文的 3.3 一節(jié)相同

#區(qū)別在于用到的mod文件, 原文是用的4d位點生成的4D.nonconserced.mod
phyloP --subtree Node --msa-format MAF --features 1.HCE.bed --method LRT --mode CONACC 4D.nonconserced.mod 1.maf > Chr1.phyloP.bed

區(qū)別在于用到的mod文件, 原文是用的4d位點生成的4D.nonconserced.mod
phyloP --subtree Node --msa-format MAF --features 1.HCE.bed --method LRT --mode CONACC 4D.nonconserced.mod 1.maf > Chr1.phyloP.bed


5.原文中提供的腳本
vim maf_bed_filter_Type1.pl

use warnings;
use strict;
my $bed_file = $ARGV[0];#"/public/home/linzeshan/project/01.conserve/Type_one_re_fileter/new_method/work/29.bed";
my $maf_file = $ARGV[1];#"../data/maf2list/29/29.maf.lst";
my $work_dir = $ARGV[2];

my @arr = ("Mus","Rat","Hamster","Squirrel","Rabbit");  #外群物種
my $species = {};
foreach my $arr(@arr){
    $species->{$arr} = 1;
}

open BED,$bed_file or die $!;
open MAF,$maf_file or die $!;

my $word = <MAF>;
my @first_line = split(/\t/,$word);
my $num = @first_line;
my @locate_arr;

for(my $i = 0;$i<$num;$i++){
    push (@locate_arr,$i) if (exists ($species->{$first_line[$i]}));
}
foreach my $j(@locate_arr){
    print $j."\t";
}

open OUT,">$work_dir/work.out" or die $!;
open ERR,">$work_dir/work.err" or die $!;

while(<BED>){
    my @array = split(/\t/,$_);
    my $pause = "nn";
    for(my $i=$array[1];$i<=$array[2];$i++){
        next if $i == 0;
        my $chu = 1;
        while(1){
            my $nt;
            if ($pause ne "nn"){
                $nt = $pause;
                $pause = "nn";
            }
            else {
                $nt = <MAF>;
            }
            my @nt = split(/\t/,$nt);
            if ($i>$nt[1]){
                next;
            }
            elsif($i == $nt[1]){
                foreach my $pocky(@locate_arr){
                    if ($nt[$pocky] ne "-"){
                    $chu = 0;
                    }
                }
                last;
            }
            else{
                $pause = $nt;
                print ERR "worng bed $i maf $nt[1]\n";
                last;
            }
        }
        print OUT "$i\t+\n" if $chu == 1;
        print OUT "$i\t-\n" if $chu == 0;
    }
}

vim work_out2bed.pl

my $file = $ARGV[0];
my $chr = $ARGV[1];
my $work_dir = $ARGV[2];
open IN,$file or die $!;
open OUT,">$work_dir/$chr.bed" or die $!;
my $over = 1;my $start=0;my $end=0;my $s_e = 1;
while(<IN>){
    chomp;
    my @array = split(/\t/,$_);
    #print $array[0]."\t"."..".$array[1]."..\n";last;}=p
    if ($array[1] eq "-"){
        $end = $start if $end == 0;
        print OUT "$chr\t$start\t$end\n" unless $start == 0;
        $start = 0;$end = 0;
        $over = 1;
        next;
    }
    else{
        if ($over == 1){
            $start = $array[0];
            $end = $array[0];
            $over = 0;
        }
        else{
            if ($array[0] > $end+1){
                $end = $start if $end == 0;
                print OUT "$chr\t$start\t$end\n" unless $start == 0;
                $start = 0;$end = 0;
                $start = $array[0];
                $end = $array[0];
            }
            else{
                $end = $array[0];
            }
        }
    }
}

vim 01.convertMaf2List.pl

#! /usr/env perl
use strict;
use warnings;

my $maf=$ARGV[0];
my $output=$ARGV[1].".maf.lst";
my $ref="golani";
my @species=("go","ga","ca","ju","Mus","Rat","Hamster","Jac","Squirrel");
open O,">$output";
open E,">no_ref.maf";
#open O,"| gzip - > $output";
my @head=("chr","pos",@species);
my $head=join "\t",@head;
print O "$head\n";

my $control=0;
my $content="";
open I,"cat $maf |";
while(<I>){
    next if(/^#/);
    if(/^a\s+score=/){
        $content=$_;
        while(<I>){
            if(/^s\s+/){
    $content.=$_;
            }
            else{
    last;
            }
        }
        &analysis($content);
    }
    # last if($control++>=0);
}
close I;
close O;

sub analysis{
    my $content=shift;
    my @line=split(/\n/,$content);
    my $head=shift @line;
    $head=~/score=([\d\.]+)/;
    my $score=$1;my $all_strand;
    # print "$score\n";
    my %pos;
    my $isRefFound=0;
    my $ref_chr="NA";
    foreach my $line(@line){
        my @a=split(/\s+/,$line);
        my ($s,$chr,$start,$alignment_length,$strand,$sequence_length,$sequence)=@a;my $all_strand = $strand;
        $chr=~/^([^\.]+)\.(.*)/;
        my $species=$1;
        $chr=$2;
        if($species eq $ref){
            $ref_chr=$chr;
            $isRefFound=1;
            my @base=split(//,$sequence);
            if($strand eq "+"){
    my $pos=$start;
    for(my $i=0;$i<@base;$i++){
        if($base[$i] ne "-"){
            $pos++;
            $pos{$i}=$pos;
        }
    }
            }
            if($strand eq "-"){
    my $pos=$start;
    for(my $i=0;$i<@base;$i++){
        if($base[$i] ne "-"){
            $pos++;
            my $real_pos = $sequence_length-1-($pos-1)+1;
            $pos{$i}=$real_pos;
        }
    }
            }
        }
    }
    if($isRefFound == 0){
        print E $content;
        next;   
#        die "$ref not found!\nspecies name should be added before chr such as chr01 should be cattle.chr01\n";
    }
    my %data;
    foreach my $line(@line){
        my @a=split(/\s+/,$line);
        my ($s,$chr,$start,$alignment_length,$strand,$sequence_length,$sequence)=@a;
        $chr=~/^([^\.]+)\.(.*)/;
        my $species=$1;
        $chr=$2;
        my @base=split(//,$sequence);
        $sequence =~ tr/ATCGRYMK/TAGCYRKM/ if ($strand eq "-");
        for(my $i=0;$i<@base;$i++){
            next if(!exists $pos{$i});
            my $pos=$pos{$i};
            $data{$pos}{$species}=$base[$i];
        }
    }
    my @output_line;
    foreach my $pos(sort {$a<=>$b} keys %data){
        @output_line=($ref_chr,$pos);
        foreach my $species(@species){
    my $base="-";
    if(exists $data{$pos}{$species}){
        $base = $data{$pos}{$species};
    }
    push @output_line,$base;
            }
        my $output_line=join "\t",@output_line;
        print O "$output_line\n";
    }
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容