好的,我們可以逐步分析這個 Perl 腳本的每個部分。腳本的主要功能是基于給定的 VCF 文件和參考基因組文件,設計引物并進行電子 PCR(e-PCR)分析。我們將從腳本的頭部和初始化部分開始講解。
第一部分:腳本頭部和初始化
2. 模塊加載
#use strict;
use Cwd qw(abs_path getcwd);
use Getopt::Long;
use Data::Dumper;
use FindBin qw($Bin $Script);
use File::Basename qw(basename dirname);
use Config::General;use File::Path qw(make_path remove_tree);
use File::Copy;
use File::Spec;
my $BEGIN_TIME=time();
my $version="1.0";
use Bio::SeqIO;
use Cwd qw(abs_path getcwd);
:加載Cwd
模塊,用于獲取當前工作目錄和絕對路徑。use Getopt::Long;
:用于處理命令行參數。use Data::Dumper;
:用于調試,可以打印復雜數據結構。use FindBin qw($Bin $Script);
:獲取腳本所在的目錄和腳本名稱。use File::Basename qw(basename dirname);
:用于處理文件名和路徑。use Config::General;
:用于解析配置文件。use File::Path qw(make_path remove_tree);
:用于創建和刪除目錄。use File::Copy;
:用于文件復制操作。use File::Spec;
:用于處理文件路徑。use Bio::SeqIO;
:用于讀取和處理生物序列文件(如 FASTA 格式)。
3. 命令行參數解析
my ($vcf,$flank,$fa,$epcrfa,$od,$outprefix,$PRIMER_NUM_RETURN,$PRIMER_OPT_SIZE,$PRIMER_MIN_SIZE,$PRIMER_MAX_SIZE,$PRIMER_PRODUCT_SIZE_RANGE,$PRIMER_MAX_NS_ACCEPTED);GetOptions("help|?" =>\&USAGE,"fa=s"=>\$fa,"vcf=s"=>\$vcf,"flank=s"=>\$flank,"PRIMER_MIN_SIZE=s"=>\$PRIMER_MIN_SIZE,"PRIMER_OPT_SIZE=s"=>\$PRIMER_OPT_SIZE,"PRIMER_MAX_SIZE=s"=>\$PRIMER_MAX_SIZE,"PRIMER_NUM_RETURN=s"=>\$PRIMER_NUM_RETURN,"PRIMER_PRODUCT_SIZE_RANGE=s"=>\$PRIMER_PRODUCT_SIZE_RANGE,"epcrfa=s"=>\$epcrfa,"od=s"=>\$od,"prefix=s"=>\$outprefix,
) or &USAGE;
&USAGE unless($fa and $vcf);
GetOptions
:解析命令行參數,將參數值賦給相應的變量。-fa
:輸入的參考基因組文件(FASTA 格式)。-vcf
:輸入的 VCF 文件。-flank
:indel 兩側的側翼序列長度,默認為 200。-PRIMER_MIN_SIZE
、-PRIMER_OPT_SIZE
、-PRIMER_MAX_SIZE
:引物的最小、最優和最大長度。-PRIMER_NUM_RETURN
:返回的引物對數量。-PRIMER_PRODUCT_SIZE_RANGE
:引物擴增產物的長度范圍。-epcrfa
:用于電子 PCR 的參考基因組文件。-od
:輸出目錄,默認為當前工作目錄。-prefix
:輸出文件的前綴,默認為indel
。
&USAGE
:如果用戶未提供必要的參數(-fa
和-vcf
),則調用USAGE
子程序,顯示幫助信息并退出。
4. 幫助信息
sub USAGE {my $usage=<<"USAGE";
Program: $0
Version: $version
Contact: huangls
Discription:Usage:Options:-fa <file> Input fa file, forced-vcf <file> Input indel vcf file, forced-flank 200 cut 200 ; -PRIMER_MIN_SIZE 18 Minimum acceptable length of a primer. Must be greater than 0 and less than or equal to PRIMER_MAX_SIZE-PRIMER_OPT_SIZE 20 Optimum length (in bases) of a primer. Primer3 will attempt to pick primers close to this length.-PRIMER_MAX_SIZE 23 Maximum acceptable length (in bases) of a primer. Currently this parameter cannot be larger than 35. This limit is governed by maximum oligo size for which primer3's melting-temperature is valid.-PRIMER_PRODUCT_SIZE_RANGE 100-1000 The associated values specify the lengths of the product that the userwants the primers to create, and is a space separated list of elements of the form; -PRIMER_NUM_RETURN 1 Total num primer to search -epcrfa run E-PCR to filter multi mapped primers; -od <str> Key of output dir,default cwd;-prefix <str> defoult demo;-h HelpUSAGEprint $usage;exit 1;
}
USAGE
子程序:定義了腳本的使用說明,包括所有支持的命令行參數及其說明。
總結
這一部分主要完成了以下任務:
- 腳本頭部信息和模塊加載。
- 命令行參數的解析。
- 提供幫助信息。
第二部分:默認參數設置和全局變量初始化
1. 設置默認參數值
$PRIMER_MIN_SIZE ||= 18;
$PRIMER_OPT_SIZE ||= 20;
$PRIMER_MAX_SIZE ||= 23;
$PRIMER_NUM_RETURN ||= 1;
$PRIMER_MAX_NS_ACCEPTED ||= 1;
$PRIMER_PRODUCT_SIZE_RANGE ||= "100-1000";
$od ||= getcwd;
$od = abs_path($od);
unless (-d $od) { mkdir $od; }
$outprefix ||= "indel";
- 作用:為未在命令行中指定的參數設置默認值。
PRIMER_MIN_SIZE
:引物的最小長度,默認為 18。PRIMER_OPT_SIZE
:引物的最優長度,默認為 20。PRIMER_MAX_SIZE
:引物的最大長度,默認為 23。PRIMER_NUM_RETURN
:返回的引物對數量,默認為 1。PRIMER_MAX_NS_ACCEPTED
:引物中允許的最大N
(未知堿基)數量,默認為 1。PRIMER_PRODUCT_SIZE_RANGE
:引物擴增產物的長度范圍,默認為100-1000
。od
:輸出目錄,默認為當前工作目錄。outprefix
:輸出文件的前綴,默認為indel
。
getcwd
和abs_path
:獲取當前工作目錄的絕對路徑,并確保輸出目錄存在。
2. 初始化全局變量
my %indel_length_range = ('mi' => 2, 'ma' => 5);
my %ref = ();
my %ref_len = ();
%indel_length_range
:定義了 indel 長度的范圍,mi
表示最小長度,ma
表示最大長度。%ref
和%ref_len
:用于存儲參考基因組序列及其長度。
3. 讀取參考基因組文件
my $in = Bio::SeqIO->new(-file => "$fa", -format => 'Fasta');
while (my $seq = $in->next_seq()) {$ref{$seq->id} = $seq;$ref_len{$seq->id} = $seq->length;
}
$in->close();
Bio::SeqIO
:用于讀取 FASTA 格式的參考基因組文件。$seq->id
:獲取序列的 ID(通常是染色體編號)。$seq->length
:獲取序列的長度。- 作用:將參考基因組序列及其長度存儲到
%ref
和%ref_len
哈希表中,方便后續使用。
總結
這一部分主要完成了以下任務:
- 為未指定的參數設置默認值。
- 初始化全局變量,用于存儲參考基因組序列及其長度。
- 讀取參考基因組文件,并將其存儲到哈希表中。
第三部分:VCF 文件的讀取和處理
1. 處理 VCF 文件路徑
$fa = abs_path($fa);
$epcrfa ||= $fa;
$epcrfa = abs_path($epcrfa);
- 作用:
- 將輸入的參考基因組文件路徑(
$fa
)轉換為絕對路徑。 - 如果未指定用于電子 PCR 的參考基因組文件(
$epcrfa
),則默認使用$fa
。 - 確保
$epcrfa
也是絕對路徑。
- 將輸入的參考基因組文件路徑(
2. 打開 VCF 文件
if ($vcf =~ /gz$/) {open IN, "gzip -dc $vcf|" or die "$! $vcf";
} else {open IN, "$vcf" or die "$! $vcf";
}
- 作用:
- 檢查 VCF 文件是否為 gzip 壓縮文件(通過文件擴展名
.gz
判斷)。 - 如果是壓縮文件,使用
gzip -dc
命令解壓并讀取內容。 - 如果不是壓縮文件,直接打開文件。
- 如果文件無法打開,程序將終止并報錯。
- 檢查 VCF 文件是否為 gzip 壓縮文件(通過文件擴展名
3. 初始化變量
$flank ||= 200;
my %ssr_pos = ();
my %SSR = ();
my %genotype = ();unless (-d "$od/split") { mkdir "$od/split"; }
open OUT, ">$od/split/p_in_0.txt" or die "$!";
open SH, ">$od/primer3.sh" or die "$!";
$flank
:設置 indel 兩側的側翼序列長度,默認為 200。%ssr_pos
和%SSR
:用于存儲 SSR(簡單序列重復)的位置信息和 SSR 序列。%genotype
:用于存儲每個 indel 的基因型信息。mkdir "$od/split"
:創建一個目錄用于存放 Primer3 的輸入文件。open OUT
和open SH
:分別打開兩個文件句柄,用于寫入 Primer3 的輸入文件和 Shell 腳本。
4. 讀取 VCF 文件內容
while (my $line = <IN>) {chomp $line;next if $line =~ /^##/;# next if $line =~ /Scaffold/i;my @tmp = split(/\t/, $line);if ($line =~ /^#C/) {@{$genotype{head}} = @tmp[7 .. $#tmp];next;}my ($ref_len, $alt_len) = (length $tmp[3], length $tmp[4]);my $indel_len = abs($ref_len - $alt_len);my $indel_len_s = $alt_len - $ref_len;my $ID = "$tmp[0]_$tmp[1]_$indel_len";$ssr_pos{$ID} = "$tmp[0]\t$tmp[1]\t$tmp[3]\t$tmp[4]\t$indel_len_s";$tmp[7] =~ s/^.*ANNOVAR_DATE=[^;]+;//;@{$genotype{$ID}} = @tmp[7 .. $#tmp];my $seq = "";my $indel_len_target = $indel_len;if ($alt_len > 1) {$seq = &get_target_fa($tmp[0], $tmp[1] - $flank, $tmp[1] + $flank, $flank, $tmp[4]);$indel_len_target = 1;} else {$seq = &get_target_fa($tmp[0], $tmp[1] - $flank, $tmp[1] + $flank + $indel_len, $flank);}
- 作用:
- 逐行讀取 VCF 文件內容。
- 跳過以
##
開頭的注釋行。 - 如果是列頭行(以
#C
開頭),提取樣本信息并存儲到%genotype{head}
中。 - 對于每個 indel 變異:
- 計算參考堿基(
REF
)和變異堿基(ALT
)的長度。 - 計算 indel 的長度(
indel_len
)和符號(indel_len_s
)。 - 構造一個唯一的 ID(
$ID
),格式為染色體編號_位置_indel長度
。 - 將 indel 的位置信息存儲到
%ssr_pos
中。 - 提取該 indel 的基因型信息并存儲到
%genotype
中。 - 調用
get_target_fa
函數獲取 indel 兩側的側翼序列($seq
)。 - 如果
ALT
是插入變異(長度 > 1),將目標長度設置為 1;否則,目標長度為 indel 的實際長度。
- 計算參考堿基(
5. 檢測 SSR 并生成 Primer3 輸入文件
if ($seq) {my ($is_have_ssr, $ssr) = &has_ssr($ID, $seq);if ($is_have_ssr) {$SSR{$ID} = join(",", @{$ssr});} else {$SSR{$ID} = "--";}print OUT "SEQUENCE_ID=$ID\n";print OUT "SEQUENCE_TEMPLATE=$seq\n";printf OUT ("SEQUENCE_TARGET=%d,%d\n", $flank + 1, $indel_len_target);print OUT "PRIMER_TASK=pick_detection_primers\n";print OUT "PRIMER_PICK_LEFT_PRIMER=1\n";print OUT "PRIMER_PICK_RIGHT_PRIMER=1\n";print OUT "PRIMER_NUM_RETURN=$PRIMER_NUM_RETURN\n";print OUT "PRIMER_MAX_END_STABILITY=250\n";print OUT "PRIMER_MIN_SIZE=$PRIMER_MIN_SIZE\n";print OUT "PRIMER_OPT_SIZE=$PRIMER_OPT_SIZE\n";print OUT "PRIMER_MAX_SIZE=$PRIMER_MAX_SIZE\n";print OUT "PRIMER_PRODUCT_OPT_SIZE=125\n";print OUT "PRIMER_OPT_GC_PERCENT=50\n";print OUT "PRIMER_MIN_TM=50\n";print OUT "PRIMER_OPT_TM=55\n";print OUT "PRIMER_MAX_TM=65\n";print OUT "PRIMER_MAX_NS_ACCEPTED=1\n";print OUT "PRIMER_FIRST_BASE_INDEX=1\n";print OUT "PRIMER_MIN_GC=40.0\nPRIMER_MAX_GC=60.0\n";print OUT "PRIMER_PRODUCT_SIZE_RANGE=$PRIMER_PRODUCT_SIZE_RANGE\n";printf OUT ("SEQUENCE_INTERNAL_EXCLUDED_REGION=%d,%d\n", $flank + 1, $indel_len_target);print OUT "=\n";$n++;if ($n > 100) {$n = 0;$num++;close(OUT);open OUT, ">$od/split/p_in_$num.txt" or die "$!";print SH "primer3_core -p3_settings_file=/share/work/biosoft/primer3/latest/default_settings.txt -default_version=1 -output=$od/split/${num}primers.txt $od/split/p_in_$num.txt\n";}
}
- 作用:
- 如果成功獲取了側翼序列(
$seq
),則調用has_ssr
函數檢查該序列是否包含 SSR。 - 如果存在 SSR,將 SSR 信息存儲到
%SSR
中;否則,存儲--
。 - 生成 Primer3 的輸入文件內容,包括序列 ID、模板序列、目標區域等信息。
- 每處理 100 個 indel,將 Primer3 輸入文件分批保存到不同的文件中,并生成對應的 Shell 命令行。
- 這樣可以避免單個 Primer3 輸入文件過大,提高運行效率。
- 如果成功獲取了側翼序列(
總結
這一部分主要完成了以下任務:
- 處理 VCF 文件路徑,確保文件可以正確讀取。
- 初始化相關變量,用于存儲 SSR 和基因型信息。
- 逐行讀取 VCF 文件,提取 indel 信息,并獲取 indel 兩側的側翼序列。
- 檢測 SSR,并生成 Primer3 的輸入文件。
- 將 Primer3 輸入文件分批保存,生成對應的 Shell 命令行。
第四部分:運行 Primer3 和電子 PCR(e-PCR)
1. 關閉文件句柄并生成 Primer3 腳本
close(OUT);
close(IN);
close(SH);#system("sh $od/primer3.sh");
system("parallel -j 10 <$od/primer3.sh");
system("cat $od/split/*primers.txt >$od/$outprefix.primers");
- 作用:
- 關閉所有打開的文件句柄。
- 使用
parallel
命令并行運行 Primer3,提高效率。-j 10
表示同時運行 10 個任務。 - 將所有分批生成的 Primer3 輸出文件合并為一個文件,命名為
$outprefix.primers
。
2. 解析 Primer3 輸出文件
$/ = "=\n";
my %Pseq = ();open IN, "$od/$outprefix.primers" or die "$!";
open OUT, ">$od/$outprefix.primers.xls" or die "$!";
print OUT "#SEQUENCE_ID\tPRIMER_LEFT_SEQUENCE\tPRIMER_RIGHT_SEQUENCE\tPRIMER_PAIR_PRODUCT_SIZE\tPRIMER_LEFT_TM\tPRIMER_RIGHT_TM\tPRIMER_LEFT_GC_PERCENT\tPRIMER_RIGHT_GC_PERCENT\tSSR\tSSR_TYPE\n";
while (my $line = <IN>) {chomp $line;my @field = split(/\n/, $line);my %primers = &get_hash(@field);next if !defined($primers{"PRIMER_PAIR_NUM_RETURNED"}) or $primers{"PRIMER_PAIR_NUM_RETURNED"} == 0;if ($primers{"PRIMER_PAIR_NUM_RETURNED"} == 1) {$Pseq{"$primers{SEQUENCE_ID}"} = [$primers{"PRIMER_LEFT_0_SEQUENCE"}, $primers{"PRIMER_RIGHT_0_SEQUENCE"}];print OUT join("\t", ($primers{"SEQUENCE_ID"}, $primers{"PRIMER_LEFT_0_SEQUENCE"}, $primers{"PRIMER_RIGHT_0_SEQUENCE"}, $primers{"PRIMER_PAIR_0_PRODUCT_SIZE"}, $primers{"PRIMER_LEFT_0_TM"}, $primers{"PRIMER_RIGHT_0_TM"}, $primers{"PRIMER_LEFT_0_GC_PERCENT"}, $primers{"PRIMER_RIGHT_0_GC_PERCENT"}, $SSR{$primers{"SEQUENCE_ID"}})) . "\n";} else {for my $i (0 .. ($primers{"PRIMER_PAIR_NUM_RETURNED"} - 1)) {$Pseq{"$primers{SEQUENCE_ID}.$i"} = [$primers{"PRIMER_LEFT_${i}_SEQUENCE"}, $primers{"PRIMER_RIGHT_${i}_SEQUENCE"}];print OUT join("\t", ("$primers{SEQUENCE_ID}.$i", $primers{"PRIMER_LEFT_${i}_SEQUENCE"}, $primers{"PRIMER_RIGHT_${i}_SEQUENCE"}, $primers{"PRIMER_PAIR_${i}_PRODUCT_SIZE"}, $primers{"PRIMER_LEFT_${i}_TM"}, $primers{"PRIMER_RIGHT_${i}_TM"}, $primers{"PRIMER_LEFT_${i}_GC_PERCENT"}, $primers{"PRIMER_RIGHT_${i}_GC_PERCENT"}, $SSR{$primers{"SEQUENCE_ID"}})) . "\n";}}
}
$/ = "\n";
close(OUT);
- 作用:
- 設置輸入記錄分隔符
$/
為=\n
,以便正確解析 Primer3 的輸出文件。 - 打開 Primer3 輸出文件和結果文件。
- 遍歷 Primer3 輸出文件的每一部分(以
=
分隔),解析引物設計結果。 - 調用
get_hash
函數將 Primer3 輸出轉換為哈希表。 - 如果某個序列沒有設計出引物,則跳過。
- 如果設計出了一對引物,將其存儲到
%Pseq
中,并將相關信息寫入結果文件。 - 如果設計出了多對引物,將每對引物的信息分別存儲和寫入結果文件。
- 最后,將輸入記錄分隔符恢復為默認值
\n
。
- 設置輸入記錄分隔符
3. 運行電子 PCR(e-PCR)
print "e-PCR -w9 -f 1 -m100 $od/$outprefix.primers.xls D=$PRIMER_PRODUCT_SIZE_RANGE $epcrfa N=0 G=0 T=3 > $od/$outprefix.epcr.out\n";
system("e-PCR -w9 -f 1 -m100 $od/$outprefix.primers.xls D=$PRIMER_PRODUCT_SIZE_RANGE $epcrfa N=0 G=0 T=3 > $od/$outprefix.epcr.out");
- 作用:
- 構造 e-PCR 命令行,運行 e-PCR 檢查引物的特異性。
- 參數說明:
-w9
:允許最多 9 個錯配。-f 1
:只考慮正鏈。-m100
:最大產物長度為 100。D=$PRIMER_PRODUCT_SIZE_RANGE
:引物產物長度范圍。$epcrfa
:用于 e-PCR 的參考基因組文件。N=0
:不允許未定義的核苷酸(N
)。G=0
:不允許間隙。T=3
:使用 3 個核苷酸的窗口進行匹配。
- 將 e-PCR 的輸出保存到
$od/$outprefix.epcr.out
文件中。
4. 解析 e-PCR 輸出文件
open IN, "$od/$outprefix.epcr.out" or die "$!";
open OUT, ">$od/$outprefix.primers.result.xls" or die "$!";
my %P = ();
while (my $line = <IN>) {chomp $line;my @tmp = split(/\t/, $line);next if $tmp[6] + $tmp[7] > 1;$tmp[5] =~ s#/.*$##;$P{$tmp[1]}{"$tmp[1]_$tmp[3]_$tmp[4]"} = [$tmp[1], $ssr_pos{$tmp[1]}, $Pseq{$tmp[1]}->[0], $Pseq{$tmp[1]}->[1], $tmp[5], @tmp[6 .. $#tmp], @{$genotype{$tmp[1]}}];
}
close(IN);
print OUT "#PRIMER_ID\tCHROM\tPOS\tREF\tALT\tINDEL_LENGTH\tPRIMER_LEFT_SEQUENCE\tPRIMER_RIGHT_SEQUENCE\tPRIMER_PAIR_PRODUCT_SIZE\tMISM\tGAPS\tPRIMER_LEFT_TM\tPRIMER_RIGHT_TM\tPRIMER_LEFT_GC_PERCENT\tPRIMER_RIGHT_GC_PERCENT\tHAS_SSR\t" . join("\t", @{$genotype{head}}) . "\n";for my $id (sort keys %P) {my @ps = (keys %{$P{$id}});if (@ps == 1) {print OUT join("\t", @{$P{$id}{$ps[0]}}) . "\n";}
}
close(OUT);
- 作用:
- 打開 e-PCR 輸出文件和最終結果文件。
- 遍歷 e-PCR 輸出文件的每一行,解析引物的匹配結果。
- 跳過匹配到多個位置的引物(
$tmp[6] + $tmp[7] > 1
)。 - 提取引物的相關信息,并存儲到
%P
哈希表中。 - 將最終結果寫入
$od/$outprefix.primers.result.xls
文件,包括引物 ID、染色體位置、引物序列、產物長度、錯配數、間隙數、引物退火溫度、GC 含量、是否含有 SSR 以及基因型信息。
總結
這一部分主要完成了以下任務:
- 關閉文件句柄并生成 Primer3 腳本。
- 解析 Primer3 輸出文件,提取引物設計結果。
- 運行電子 PCR(e-PCR),檢查引物的特異性。
- 解析 e-PCR 輸出文件,生成最終的引物結果文件。
好的,接下來我們分析腳本的第五部分:生成 README 文件和清理臨時文件。
第五部分:生成 README 文件和清理臨時文件
1. 生成 README 文件
open OUT, ">$od/readme.txt" or die "$!";
my $readme = <<"README";
*primers.result.xls
PRIMER_ID 引物ID (命名規則:indel所在來源序列_indel所在位置start_indel所在位置長度)
CHROM 所在染色體
POS 所在染色體位置
REF 參考基因組堿基
ALT 變異堿基
INDEL_LENGTH indel長度(負數表示缺失,正數表示插入)
PRIMER_LEFT_SEQUENCE-- 左引物
PRIMER_RIGHT_SEQUENCE-- 右引物
PRIMER_PAIR_PRODUCT_SIZE-- 引物產物長度
MISM-- Total number of mismatches for two primers(ePCR)
GAPS-- Total number of gaps for two primers(ePCR)
PRIMER_LEFT_TM-- 退火溫度
PRIMER_RIGHT_TM-- 退火溫度
PRIMER_LEFT_GC_PERCENT-- GC含量
PRIMER_RIGHT_GC_PERCENT-- GC含量
HAS_SSR-- indel周圍是否含有SSR -- 表示不含有SSR
INFO vcf注釋信息 參照變異檢測說明FORMAT vcf注釋信息 參照變異檢測說明 http://www.omicsclass.com/article/6 AD,"Allelic depths for the ref and alt alleles in the order listed"DP,"Approximate read depth (reads with MQ=255 or with bad mates are filtered)"GQ,"Genotype Quality"GT,"Genotype" 0表示和參考基因型相同(REF),1表示變異基因型(ALT)。PL,"Normalized, Phred-scaled likelihoods for genotypes as defined in the VCF specification"
樣品基因型 信息,用":"隔開與FORMAT列對應方法:
1.提取indel左右各$flank bp序列,用primer3設計引物[2]
2.用Epcr ,在參考基因組上電子PCR,去除有多處比對的引物,保證引物擴增的特異性[3]
3.檢測indel附近是否有SSR[1][1] MISA:Exploiting EST databases for the development and characterization of gene-derived SSR-markers in barley (Hordeum vulgare L.).
[2] Primer3: Untergasser A, Cutcutache I, Koressaar T, Ye J, Faircloth BC, Remm M, Rozen SG (2012) Primer3 - new capabilities and interfaces. Nucleic Acids Research 40(15):e115
[3] Schuler, G. D. (1997). Sequence Mapping by Electronic?PCR. Genome Research, 7(5), 541–550.READMEprint OUT $readme;
close(OUT);
- 作用:
- 打開一個文件句柄,準備寫入 README 文件。
- 構造一個字符串
$readme
,包含對輸出文件格式和內容的詳細說明。 - 寫入 README 文件,解釋每個字段的含義,包括引物 ID、染色體位置、引物序列、產物長度、錯配數、間隙數、退火溫度、GC 含量、SSR 信息以及 VCF 注釋信息。
- 說明了腳本運行的方法和引用的工具(如 Primer3 和 e-PCR)。
- 關閉 README 文件。
2. 清理臨時文件
print "head -1 $od/$outprefix.primers.result.xls >$od/head && cat $od/$outprefix.primers.result.xls|grep -v '#' |sort -k2,2 -k3,3n >$od/$outprefix.primers.result.xls.sorted && cat $od/head $od/$outprefix.primers.result.xls.sorted >$od/$outprefix.primers.result.xls && rm $od/head $od/$outprefix.primers.result.xls.sorted\n";
system "head -1 $od/$outprefix.primers.result.xls >$od/head && cat $od/$outprefix.primers.result.xls|grep -v '#' |sort -k2,2 -k3,3n >$od/$outprefix.primers.result.xls.sorted && cat $od/head $od/$outprefix.primers.result.xls.sorted >$od/$outprefix.primers.result.xls && rm $od/head $od/$outprefix.primers.result.xls.sorted";
- 作用:
- 使用
head
命令提取結果文件的第一行(表頭)。 - 使用
grep
命令過濾掉以#
開頭的注釋行。 - 使用
sort
命令按染色體編號和位置對結果進行排序。 - 將排序后的結果重新組合為一個完整的文件。
- 刪除臨時文件(如
head
文件和排序后的臨時文件)。
- 使用
總結
這一部分主要完成了以下任務:
- 生成 README 文件,詳細說明輸出文件的格式和內容。
- 清理臨時文件,確保結果文件是有序且整潔的。
第六部分:輔助函數的定義
1. get_hash
函數
sub get_hash {my @info = @_;my %result = ();for my $i (@info) {next if $i =~ /^\s*$/;my ($k, $v) = split(/=/, $i);$result{$k} = $v;}return %result;
}
- 作用:
- 將 Primer3 的輸出(以
=
分隔的鍵值對)解析為一個哈希表。 - 遍歷輸入的每一行,跳過空行。
- 使用
split
函數將每一行按=
分隔為鍵和值。 - 將鍵值對存儲到哈希表
%result
中。 - 返回解析后的哈希表。
- 將 Primer3 的輸出(以
2. get_target_fa
函數
sub get_target_fa {my $id = shift;my $posU = shift;my $posD = shift;if ($posU <= 0) {$posU = 1;}my $seqobj = $ref{$id};my $len = $ref_len{$id};return $seqobj->subseq($posU, $len) if $posD > $len;my $tri = $seqobj->subseq($posU, $posD);return $tri;
}
- 作用:
- 從參考基因組中提取指定區域的序列。
- 參數:
$id
:染色體編號。$posU
:起始位置。$posD
:結束位置。
- 如果起始位置
$posU
小于等于 0,則將其設置為 1。 - 使用
Bio::Seq
對象$seqobj
提取子序列。 - 如果結束位置
$posD
超過了染色體長度$len
,則提取從$posU
到染色體末尾的序列。 - 否則,提取從
$posU
到$posD
的序列。 - 返回提取的序列。
3. has_ssr
函數
sub has_ssr {my ($id, $seq) = @_;my @SSR;my %typrep = ('2' => '5','5' => '4','3' => '4','6' => '4','1' => '8','4' => '4');my $amb = 200; # interruptions (max_difference_between_2_SSRs)my @typ = sort { $a <=> $b } keys %typrep;my $max_repeats = 1; # count repeatsmy $min_repeats = 1000; # count repeatsmy (%count_motif, %count_class); # countmy ($number_sequences, $size_sequences, %ssr_containing_seqs, %count_motifs); # stores number and size of all sequences examinedmy $ssr_in_compound = 0;my ($nr, %start, @order, %end, %motif, %repeats); # store info of all SSRs from each sequence$seq =~ s/[\d\s>]//g; # remove digits, spaces, line breaks, etc.$id =~ s/^\s*//g; $id =~ s/\s*$//g;#$id =~ s/\s/_/g; # replace whitespace with "_"$number_sequences++;$size_sequences += length $seq;for (my $i = 0; $i < scalar(@typ); $i++) { # check each motif classmy $motiflen = $typ[$i];my $minreps = $typrep{$typ[$i]} - 1;if ($min_repeats > $typrep{$typ[$i]}) { $min_repeats = $typrep{$typ[$i]}; }; # count repeatsmy $search = "(([acgt]{$motiflen})\\2{$minreps,})";while ($seq =~ /$search/ig) { # scan whole sequence for that classmy $motif = uc $2;my $redundant; # reject false type motifs [e.g. (TT)6 or (ACAC)5]for (my $j = $motiflen - 1; $j > 0; $j--) {my $redmotif = "([ACGT]{$j})\\1{" . int($motiflen / $j - 1) . "}";$redundant = 1 if ($motif =~ m/$redmotif/);}next if $redundant;$motif{++$nr} = $motif;my $ssr = uc $1;$repeats{$nr} = length($ssr) / $motiflen;$end{$nr} = pos($seq);$start{$nr} = $end{$nr} - length($ssr) + 1;# count repeats$count_motifs{$motif{$nr}}++; # counts occurrence of individual motifs$motif{$nr}{$repeats{$nr}}++; # counts occurrence of specific SSR in its appearing repeat$count_class{$typ[$i]}++; # counts occurrence in each motif classif ($max_repeats < $repeats{$nr}) { $max_repeats = $repeats{$nr}; };}}if (!$nr) {return (0, \@SSR);} # no SSRs$ssr_containing_seqs{$nr}++;@order = sort { $start{$a} <=> $start{$b} } keys %start; # put SSRs in right ordermy $i = 0;my $count_seq; # countsmy ($start, $end, $ssrseq, $ssrtype, $size);while ($i < $nr) {my $space = $amb + 1;if (!$order[$i + 1]) { # last or only SSR$count_seq++;my $motiflen = length($motif{$order[$i]});$ssrtype = "p" . $motiflen;$ssrseq = "($motif{$order[$i]})$repeats{$order[$i]}";$start = $start{$order[$i]}; $end = $end{$order[$i++]};next;}if (($start{$order[$i + 1]} - $end{$order[$i]}) > $space) {$count_seq++;my $motiflen = length($motif{$order[$i]});$ssrtype = "p" . $motiflen;$ssrseq = "($motif{$order[$i]})$repeats{$order[$i]}";$start = $start{$order[$i]}; $end = $end{$order[$i++]};next;}my ($interssr);if (($start{$order[$i + 1]} - $end{$order[$i]}) < 1) {$count_seq++; $ssr_in_compound++;$ssrtype = 'c*';$ssrseq = "($motif{$order[$i]})$repeats{$order[$i]}($motif{$order[$i + 1]})$repeats{$order[$i + 1]}*";$start = $start{$order[$i]}; $end = $end{$order[$i + 1]};} else {$count_seq++; $ssr_in_compound++;$interssr = lc substr($seq, $end{$order[$i]}, ($start{$order[$i + 1]} - $end{$order[$i]}) - 1);$ssrtype = 'c';$ssrseq = "($motif{$order[$i]})$repeats{$order[$i]}$interssr($motif{$order[$i + 1]})$repeats{$order[$i + 1]}";$start = $start{$order[$i]}; $end = $end{$order[$i + 1]};#$space -= length $interssr}while ($order[++$i + 1] and (($start{$order[$i + 1]} - $end{$order[$i]}) <= $space)) {if (($start{$order[$i + 1]} - $end{$order[$i]}) < 1) {$ssr_in_compound++;$ssrseq .= "($motif{$order[$i + 1]})$repeats{$order[$i + 1]}*";$ssrtype = 'c*';$end = $end{$order[$i + 1]};} else {$ssr_in_compound++;$interssr = lc substr($seq, $end{$order[$i]}, ($start{$order[$i + 1]} - $end{$order[$i]}) - 1);$ssrseq .= "$interssr($motif{$order[$i + 1]})$repeats{$order[$i + 1]}";$end = $end{$order[$i + 1]};#$space -= length $interssr}}$i++;} continue {push @SSR, "$ssrseq";}my $has_ssr = @SSR;return ($has_ssr, \@SSR);
}
- 作用:
- 檢測給定序列中是否存在簡單序列重復(SSR)。
- 參數:
$id
:序列 ID。$seq
:待檢測的 DNA 序列。
- 使用正則表達式匹配不同類型的 SSR(如單核苷酸重復、二核苷酸重復等)。
- 檢測到 SSR 后,記錄其位置、重復次數和類型。
- 如果檢測到多個 SSR,會檢查它們之間的距離是否超過閾值(
$amb
),并相應地分類為復合 SSR 或簡單 SSR。 - 返回一個布爾值(是否檢測到 SSR)和一個包含 SSR 信息的數組引用。
總結
這一部分定義了三個輔助函數:
get_hash
:解析 Primer3 的輸出,將其轉換為哈希表。get_target_fa
:從參考基因組中提取指定區域的序列。has_ssr
:檢測序列中是否存在 SSR,并返回相關信息。
這些函數在腳本的主邏輯中被多次調用,用于處理數據和生成引物設計所需的輸入。