Bioops

Bioinformatics=(ACGAAG->AK)+(#!/bin/sh)+(P(A|B)=P(B|A)*P(A)/P(B))

Nature: 染色体镶嵌性、年龄和癌症之间的关系

| Comments

5月6日的Nature同时发布了两篇研究方向非常相似的论文,揭示了染色体镶嵌性会随着年龄的增长而增加,并与癌症发生有一定关联。

一篇National Cancer Institute (NCI)Stephen Chanock领导完成。将 31,717个癌症患者和26,136健康人血液或口腔拭子的SNP芯片数据分析比较。健康人中染色体复制异常的比率随着年龄而增长,50岁以下0.23%,到了70多岁就飙到了1.91%。平均下来,癌症患者中染色体复制异常的比率比健康者高一些(0.97% VS 0.74%)。有些白血病患者被诊断出来前一年的血液样本中的染色体复制异常也比健康人普遍。

另一篇来自Gene Environment Association Studies Consortium (GENEVA)。他们分析了超5万人血液样本的SNP芯片数据,发现50岁以下人的基因组样本中,复制异常低于0.5%,而在50岁之后的人中迅速增长至2–3%。有很多复制异常都在以前发现的和血液癌症有关的位点上。虽然这些有“污点记录”的位点只占所发现的异常位点的3%,统计学分析表明,有复制异常的人得血液癌症的概率是正常人的十倍。

笔记:上面涉及到一些概率,我没仔细看文章,可能理解有错。人体细胞复制不可靠。年老的人更容易得癌症。50岁是个坎儿。生孩子要趁早。

上了火的RNA-seq

| Comments

Nature News今天的一篇评论,说是现在越来越多人使用高通量的RNA数据,但忽略了统计分析的严密性和重要性,而得到了一些值得怀疑的结论。

举了两个例子。

第一个,2010年,Harvard的Catherine DulacChristopher Gregg在Science上发了一篇文章,号称1300多个小鼠的基因都属于烙印基因(imprinted gene:两个等位基因,一个表达一个沉默)。但是Standford的Tomas Babak用同样的数据得到了不同的结果,并于2012年3月将其分析结果发表在PLoS  Genetics上。Babak认为原文章所用的统计方法会有很高的假阳性。

另一个例子就是前段时间引起巨大争议的关于RNA编辑广泛存在的那篇文章。后来又有多篇评论发表在Science上,强烈置疑该文章分析方法的可靠性。

造成这种争议的原因是什么呢?

一是RNA-Seq还没有像DNA测序一样建立起一个标准化的、错误偏差少的分析方法。

二是这些文章一般号称在生物学上某一点上取得了突破,所以一般是搞生物的来审核,缺少搞数学和统计的人把关。

个人觉得:很少有懂统计的人把生物理解的很清楚,更少有搞生物的把统计学好的,现在生物大数据时代,都需要补补课了。这两篇文章因为是有了“突破性的发现”,所以很多双眼睛在盯着,引起了怀疑。至于其他灌水文章,也不知道能有多少篇把统计方法用对的。这算是方法论的问题,只要提出来了,多探索一般能有个定论。更可怕的是搞科研的为了发文章,不惜更改数据或忽略负面数据,前几天不是有人抱怨癌症治疗的研究大部分都是在骗人么?!

希望以后有所改观,至少做到自重吧。

真核基因组注释

| Comments

测一个未知基因组(de nove sequence),要进行测序、拼接及注释。关于测序仪和拼接软件已经讲的很多了,很少有关于基因组注释的文章。一篇最近在Nature Review Genetics上的文章,A beginner’s guide to eukaryotic genome annotation,非常详细地讲解了如何做基因组注释,是一篇非常好的入门文章。

基因组拼接好后,一般要先进行重复序列的检测和注释,然后mask掉这些重复序列,再进行编码基因的预测(有时候也预测非编码RNA),最后一步是整合。因为要通过不同的方法和参考来源来预测,会得到不同的结果,整合时综合考虑预测错误和可变剪接,得到可靠的注释,这一步要一个个手工检测。

有很多软件可以做注释(可见文章内的列表),主要分为ab initio和evidence-driven两种预测方法。

现在RNA-seq技术也很成熟了,一般都是在测基因组时也要做RNA-seq,这些RNA-seq既可用于分析基因的表达,也是非常好的基因注释的参考资源。

三种小型测序仪的比较

| Comments

Nicholas Loman在Nature Biotechnology发了一篇文章,综合比较了三个小型测序仪,454 GS Junior (Roche), MiSeq (Illumina) and Ion Torrent PGM (Life Technologies),并且接受了Nature的采访

小型测序仪一般只有台式电脑大小,价格便宜、操作简单,但通量相对较小,一般用于重测序和小基因组或基因组片段的de novo测序。(BTW, 我们实验室有一台MiSeq)

正如Nicholas Loman所说,这三个测序仪都有各自的优缺点。PGM单位时间内通量高;MiSeq每个run通量高;MiSeq错误率低,454可读取最长的序列片段但通量低;PGM和454在测重复序列时容易出错,且多次重复测序仍然无法消除;MiSeq整体稳定性和质量较好。价格方面没有透露。我所了解到的是MiSeq比PGM高一点,454最贵,但PGM更新换代花费少,只需要更新一个芯片。

但是话又说回来了,现在测序技术发展非常快,远远超过了电脑行业的所谓摩尔定律。别看现在Illumina笑傲群雄,Ion Torrent正快速追赶,加上Nanopore技术的异军突起,估计会各领风骚几年。

Wellcome Trust即将推出开放期刊eLife

| Comments

Wellcome Trust基金会去年宣布计划出版一个新的可开放获取的顶尖的学术期刊系列,eLife。基金会的主管Mark Walport现在宣称eLife的发布工作已经到了最后的阶段,并希望eLife成为能和Nature和Science竞争但可免费获取的期刊系列。

eLife的发布将给“学术之春”(academic spring)活动注入一股强心剂。本来该活动是由于Elsevier高昂的订阅费而导致数学家Timothy Gowers号召学术界联合抵制Elsevier,不发表,不审核,不编辑。现在已经有9000多人签名支持,并引起了关于学术期刊免费开放的广泛讨论。

Wellcome Trust是仅次于Bill & Melinda Gates Foundation(盖茨夫妇)对科研投资最大的非政府组织,每年投入超过600万欧。

李恒获得2012年Benjamin Franklin奖

| Comments

旧闻了,但觉得有必要拿出来分享一下。

李恒因在下一代测序技术的软件开发与应用上的突出贡献,获得Bioinformatics.Org颁发的2012年Benjamin Franklin奖

李恒算是生物信息学界的一个牛人了。南大生物物理本科毕业,2006年在中科院理论物理研究所获得博士学位。读博期间师从郑伟谋,但貌似是在Sanger的Richard Durbin的指导下与BGI的王俊等人合作搞TreeFam数据库。博士毕业后理所应当地到了Richard Durbin实验室做博士后,并在此期间开发了后来名震天下的SAMtoolsBWAMAQ。而Richard Durbin也培养了另外一个Benjamin Franklin奖获得者,2005年获该奖的Ewan Birney。他工作于EBI,领导了BioperlEnsembl的开发,以及ENCODE工程。李恒后来又转到Broad InstituteDavid ReichDavid Altshuler共事,进行人类群体遗传学方面的研究,并经常在Nature和Science灌水。他在SEQanswersBioStars上也很活跃(两个论坛上的id应该都是lh3)。

2016年下一代测序技术的全球市场总额将达23.43亿刀

| Comments

MarketsandMarkets新发布了一个比较系统的关于下一代测序技术的报告,总结现状,更主要的是为了预测未来。

2011年,下一代测序技术的全球市场总额是8.425亿刀,预计会按照每年22.7%的速度递增,2016年将达到23.43亿刀。北美地区现占51.8%的市场份额,欧洲31.1%。

市场增长的主要驱动力来自于越来越便宜的测序技术以及测序被应用于越来越多的领域,如癌症、生物能源、海洋生物学,畜牧业、农业以及兽医药学。即将来临的个人基因组测序的普及,将更大地刺激对测序设备的需求。

现阶段这个领域主要的公司有 Illumina (美帝)、Life Technologies (美帝)、454 Roche (瑞士)、Oxford Nanopore Technologies (英帝)、 and Pacific Biosciences (美帝)。在目前以大规模短片段测序占主流的情况下,Illumina和Life Technologies在这一技术上竞争非常激烈。以后大片段的测序是趋势,而454 Roche和Pacific Biosciences又占有优势。当然更少不了新兴的Oxford Nanopore Technologies,利用纳米测序技术能够长片段、单细胞测序且设备非常小,有很大的潜力。

利用Bioperl进行序列输入和输出(Bioperl HOWTO翻译13)

| Comments

利用Bioperl进行序列输入和输出

英文原文

目录

作者

版权

Ewan Birney拥有此文档版权。 基于 Perl Artistic License协议有限共享。

基础

作者假定阅读此文章的读者没有用过BioPerl,也许是一个想要获取一些序列信息的生物学者;也许是一个想学习一下目前流行的所谓“生物新信息学”的IT人士。我们讲解的第一个脚本就是如何从包含一个或多个序列的序列文件中提取相关信息。

一个小建议:坚持使用Bio::SeqIO模块来处理序列。先来看一下完成任务所需要的前几行脚本:

1
2
3
4
5
6
7
8
#!/bin/perl

use strict;
use Bio::SeqIO;

my $file         = shift; # get the file name, somehow
my $seqio_object = Bio::SeqIO->new(-file => $file);
my $seq_object   = $seqio_object->next_seq;

为什么要用Bio::SeqIO?部分原因是SeqIO能识别各种不同的序列格式并从中提取然后创建相应的BioPerl对象。有些序列格式很简单,例如FASTA。fasta格式仅包含序列和一个简单的序列标识符,而不包含序列内部的一些详细的特征或信息(Feature-Annotation HOWTO里具体讲了序列的特征)。一般来说,SeqIO能识别不同的序列格式,并创建相应的对象,例如输入fasta,SeqIO会创建一个Bio::Seq对象,而输入Genbank或EMBL这种包含注释信息的序列文件,SeqIO则会创建一个Bio::Seq::RichSeq对象。

至于SeqIO针对不同格式的序列文件,到底创建了哪种对象,我们并不需要关心。SeqIO会把自动这些细节问题处理好。

十秒速览

生物信息学的工作会接触到各种格式的序列。而又有几乎同样多的程序来处理这些序列。SeqIO的优势是可以通过创建和输出序列对象的方式来处理很多不同格式的序列。可以将SeqIO想象成一个智能的文件控制系统。

背景

SeqIO系统可以处理很多复杂的序列格式。提供给Bioperl输入序列(序列可以是普通文件、标准输入输出(STDINSTDOUT)、变量等等)以及序列格式,Bioperl即可从序列中提取所有可以提取的信息。有时候并不需要说明序列格式。SeqIO可通过文件扩展名或文件内容来猜测出序列格式。如果文件没有扩展名或者文件内容不完整甚至压根输入的就不是一个文件,Bioperl直接默认是fasta格式(译者注:而这样就很可能出错)。除非明确知道所用的序列就是fasta格式,最好还是明确告知Bioperl你所输入序列的格式。

SeqIO可以接受多种形式的输入。唯一的要求是序列必须包含在Perl所规定的“句柄”中(详见IO::Handle)。大多数人使用文件句柄或者标准输入/输出(STDIN/STDOUT)。Perl还提供了如何将一段字符串转为句柄(见下文)。这样一来,几乎所有东西都可以作为SeqIO的输入,只要其中含有序列信息。SeqIO的主要工作流程就是获取一个句柄,然后依次将一条条序列信息转化为SeqI对象,若有需要则创建一个句柄以输出序列文件。SeqIO可以识别多个序列之间的分隔符,如genbank格式中的“// ”,fasta格式中的“>”,也能识别用关键字或符号标识的其他序列信息。

格式

BioPerl的SeqIO模块能识别很多序列格式并且互相转换. 表1是最新版本的SeqIO所支持的格式。(译者注:表格见原文。如前所述,SeqIO将输入的不同格式序列用相应的模块转换成相应的序列对象)

注: Bio::SeqIO需要bioperl-ext包来和Staden包中的io_lib库才能读取scf, abi, alf, pln, exp, ctf,和ztr格式的序列.

也许有些人会对上面提到的不同序列格式对应不同序列对象产生疑问,如“为了转换序列格式,如何才能把一个PrimarySeq对象转换为RichSeq对象?”答案是:这种问题压根就不用担心,SeqIO会自动转换。之所以不同的格式对应不同的对象,因为有些序列有很少信息,而有些格式又包含很多信息。(译者注:可能是避免大炮打蚊子似的浪费) 你并不需要关心SeqIO是如何转换的。列出表2,展示一下常见的序列格式和对应的序列对象,也可满足一些人的好奇心。(表格见原文。)

举例

先举个最简单的例子,如何从序列文件中提取accession number

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
# first, bring in the SeqIO module

use Bio::SeqIO;

# Notice that you do not have to use any Bio:SeqI
# objects, because SeqIO does this for you. In fact, it
# even knows which SeqI object to use for the provided
# format.

# Bring in the file and format, or die with a nice
# usage statement if one or both arguments are missing.
my $usage  = "getaccs.pl file format\n";
my $file   = shift or die $usage;
my $format = shift or die $usage;

# Now create a new SeqIO object to bring in the input
# file. The new method takes arguments in the format
# key => value, key => value. The basic keys that it
# can accept values for are '-file' which expects some
# information on how to access your data, and '-format'
# which expects one of the Bioperl-format-labels mentioned
# above. Although it is optional, it is good
# programming practice to provide > and < in front of any
# filenames provided in the -file parameter. This makes the
# resulting filehandle created by SeqIO explicitly read (<)
# or write(>).  It will definitely help others reading your
# code understand the function of the SeqIO object.

my $inseq = Bio::SeqIO->new(
                            -file   => "<$file",
                            -format => $format,
                            );
# Now that we have a seq stream,
# we need to tell it to give us a $seq.
# We do this using the 'next_seq' method of SeqIO.

while (my $seq = $inseq->next_seq) {
    print $seq->accession_number,"\n";
}

运行此脚本需要两个参数,输入序列的文件名和文件格式。上例显示了最基本的处理genbank文件的方式。其他格式,如fasta,swissprotace都是类似的,需要给bioperl提供其所支持的格式名称。(译者注:一般情况下bioperl可以自己猜测出来序列的格式,而不需提供format参数,为保险期间最好说明格式类型。)

需要注意的是,SeqIO默认是处理多个序列的。每一次调用next_seq时,返回的是下一个序列,直到返回一个undef,即文件末尾。 脚本是一个一个序列依次读取,相比一次性把所有序列读取后再处理更节省内存。undef的重要性在于,当文件达到末尾的时候,undef可终止while循环。

下例是把EMBL文件中的所有序列信息都放先在一个数组里,然后从数组里提取所需信息。

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
use strict;
use Bio::SeqIO;

my $input_file = shift;

my $seq_in  = Bio::SeqIO->new(
                              -format => 'embl',
                              -file   => $input_file,
                              );

# loads the whole file into memory - be careful
# if this is a big file, then this script will
# use a lot of memory

my $seq;
my @seq_array;
while( $seq = $seq_in->next_seq() ) {
    push(@seq_array,$seq);
}

# now do something with these. First sort by length,
# find the average and median lengths and print them out

@seq_array = sort { $a->length <=> $b->length } @seq_array;

my $total = 0;
my $count = 0;
foreach my $seq ( @seq_array ) {
    $total += $seq->length;
    $count++;
}

print "Mean length ",$total/$count," Median ",$seq_array[$count/2]->length,"\n";

现在来看如何转换序列格式。当你从一个序列文件创建一个Bio::SeqIO对象后,每次调用next_seq,Bioperl都会通过运行很多相关的脚本,来提取下一条序列的信息,并记录到一个SeqI对象中。神奇的是,next_seq一次性提取整条序列的所有信息,因为Bioperl能够理解序列的起始和终止位置,当提取完一条序列信息后自动停止,等待下一次next_seq的调用。同时,Bioperl也能识别出序列的注释信息,例如在genbank序列 LOCUS行中的DIVISION信息。 要转换格式,就是把存储序列信息的一个Bio::SeqI对象以另一种格式输出到新文件中。 这时就要用Bio::SeqIO中的另一个方法,write_seq。write_seq的工作原理与刚才所说的读取序列的过程正好相反,并通过next_seq将输入和输出的过程连接起来。Bioperl可以将一个SeqI对象按照所需格式输出到新的序列文件中。看下面的示例会更清楚一些:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use Bio::SeqIO;
# get command-line arguments, or die with a usage statement
my $usage         = "x2y.pl infile infileformat outfile outfileformat\n";
my $infile        = shift or die $usage;
my $infileformat  = shift or die $usage;
my $outfile       = shift or die $usage;
my $outfileformat = shift or die $usage;

# create one SeqIO object to read in,and another to write out
my $seq_in = Bio::SeqIO->new(
                             -file   => "<$infile",
                             -format => $infileformat,
                             );
my $seq_out = Bio::SeqIO->new(
                              -file   => ">$outfile",
                              -format => $outfileformat,
                              );

# write each entry in the input file to the output file
while (my $inseq = $seq_in->next_seq) {
    $seq_out->write_seq($inseq);
}

可以将$seq_in和$seq_out想象成两个特殊的文件句柄,并且这个文件句柄“知道”序列及其格式。用文件句柄时一般用类似<F>的操作符,而$seq_in和$seq_out则使用next_seq()方法来读取或输出序列对象,如用“$seqio->write_seq($seq_object)”相对于“print F $line”。

注:Bio::SeqIO允许使用一种办法来模仿文件句柄的输入输出(也不知道用这种方法是傻还是聪明),让<F>存储序列,“print F”则是输出序列。但这种方式对很多人来说是一种非主流想法,看起来很别扭,有时候也会引起一些不必要的困惑。

这个可通用与序列格式转换的脚本只比前面例子里提取accession号和计算序列平均长度的脚本多了几行代码。(主要增加的部分是为了从命令行获取参数)这就是Bioperl的优势所在,可以用很少的代码完成很复杂的任务。

接着,我们来看通过简单修改上面例子中的代码来展示一下SeqIO的灵活性。例如,用其他程序输出一段内容,然后用Bioperl来接受其输出的内容,处理后输出到新文件中。这里需要明确亮点,一个和Perl有关,另一个是Bioperl特有的。Perl可以通过在一个句柄的名字前加“*”号将其转换(GLOB)成一个文件句柄,以便于后面使用。 另外,Bio::SeqIO可以将前面转换后的文件句柄作为-fh的参数,以代替-file参数。下面展示的例子中,all2y.pl可以从其他程序的输出端获取内容,使用时类似于:

    >cat myseqs.fa | all2y.pl fasta newseqs.gb genbank
其代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use Bio::SeqIO;
# get command-line arguments, or die with a usage statement
my $usage     = "all2y.pl informat outfile outfileformat\n";
my $informat  = shift or die $usage;
my $outfile   = shift or die $usage;
my $outformat = shift or die $usage;

# create one SeqIO object to read in, and another to write out
# *STDIN is a 'globbed' filehandle with the contents of Standard In
my $seqin = Bio::SeqIO->new(
                            -fh     => \*STDIN,
                            -format => $informat,
                            );
my $seqout = Bio::SeqIO->new(
                             -file   => ">$outfile",
                             -format => $outformat,
                             );

# write each entry in the input file to the output file
while (my $inseq = $seqin->next_seq) {
    $seqout->write_seq($inseq);
}

有时候可能根本就用不着文件。可以直接使用 STDINSTDOUT,将输出序列做为另一程序的输入,比如:

    cat *.seq | in2out.pl EMBL Genbank | someother program
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use Bio::SeqIO;
# get command-line arguments, or die with a usage statement
my $usage     = "in2out.pl informat outformat\n";
my $informat  = shift or die $usage;
my $outformat = shift or die $usage;

# create one SeqIO object to read in, and another to write out
my $seqin = Bio::SeqIO->new(
                            -fh     => \*STDIN,
                            -format => $informat,
                            );
my $outseq = Bio::SeqIO->new(
                             -fh     => \*STDOUT,
                             -format => $outformat,
                             );

# write each entry in the input to the output
while (my $inseq = $seqin->next_seq) {
    $outseq->write_seq($inseq);
}

字符串相关

一个很常见的问题是:“如果我有一个字符串,其中包含了一系列的某格式的序列,我该如何才能把这些序列转换成Bio::Seq对象?”比如有些时候,需要用户在网页表格内输入一段序列,然后对这段序列做一些处理。可以通过把用户输入的一段字符串转化成符合Perl标准的句柄(Perl 5.8.0以后可以直接用open来完成),然后-fh参数就可设置成这个句柄,而不用设置成文件名。

下面的两个例子都不是完整的程序,只是给个基本的示例。假设通过CGI脚本获取到用户输入的序列和序列格式,并分别放到两个字符串变量中。刚才提到Bio::seqIO可通过文件后缀名识别序列格式,这里输入的序列不是文件,所以必须告知Bioperl文件格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use IO::String;   # only needed for Perl versions previous to 5.8.0
use Bio::SeqIO;

## get a string into $string somehow, with its format in $format, say from a web form.
my $string   = ">SEQ1\nacgt\n>revseq1\ntgca\n";
my $format   = "fasta";

my $stringfh = IO::String->new($string);                                         # Use this for Perl BEFORE 5.8.0
open($stringfh, "<", \$string) or die "Could not open string for reading: $!";   # Use this for Perl AFTER 5.8.0 (inclusive)

my $seqio = Bio::SeqIO-> new(
                             -fh     => $stringfh,
                             -format => $format,
                             );

while( my $seq = $seqio->next_seq ) {
    # process each seq
    print $seq->id . ' = '.$seq->seq()."\n";
}

同样道理,也可以将一个序列对象以一字符串的形式输出。示例(注意open函数内“<”和“>”的区别,“<”用于输入,“>”用于输出):

1
2
3
4
5
6
7
8
9
10
11
12
13
use IO::String;   # only needed for Perl versions BEFORE 5.8.0
use Bio::SeqIO;

my $string;
my $stringfh = IO::String->new(\$string);                                        # Use this for Perl BEFORE 5.8.0
open($stringfh, ">", \$string) or die "Could not open string for writing: $!";   # Use this for Perl AFTER 5.8.0 (inclusive)

my $seqOut = Bio::SeqIO->new(
                             -format => 'swiss',
                             -fh     => $io,
                             );
$seqOut->write_seq($seq_obj);
print $string;

更多示例

Bio::SeqIO中的-file参数可以是多个文件。也可以是一段字符串,用于表明从管道输入的内容。格式是'-file' => '命令 |'。注意后面的“|”符号。当需要处理很大的压缩文件而又没有足够空间解压缩的时候,这种办法很管用。这里给出一个从gzip压缩的genbank文件中提取序列并转换成新的fasta格式的文件,使用方法如下:
     gzip2fasta.pl gbpri1.seq.gz Genbank gbpri1.fa
下面是gzip2fasta.pl的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use Bio::SeqIO;
# get command-line arguments, or die with a usage statement
my $usage    = "gzip2fasta.pl infile informat outfile\n";
my $infile   = shift or die $usage;
my $informat = shift or die $usage;
my $outfile  = shift or die $usage;

# create one SeqIO object to read in, and another to write out
my $seqin = Bio::SeqIO->new(
                            -file   => "/usr/local/bin/gunzip -c $infile |",
                            -format => $informat,
                            );

my $seqout = Bio::SeqIO->new(
                             -file   => ">$outfile",
                             -format => 'Fasta',
                             );

# write each entry in the input to the output file
while (my $inseq = $seqin->next_seq) {
    $seqout->write_seq($inseq);
}

当然Bioperl也可一“管道输出”。使用格式是:'-file' => "| 命令"。这个时候“|”变到了命令的前面。下面举个例子,用Bioperl将一个genbank序列文件转为fasta格式的序列,但不输出文件,直接传递给WashU Blast,让其建立序列数据库。用法:

    any2wublastable.pl myfile.gb Genbank mywublastable p
any2wublastable.pl的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use Bio::SeqIO;

# get command-line arguments, or die with a usage statement
my $usage     = "any2wublastable.pl infile informat outdbname outdbtype\n";
my $infile    = shift or die $usage;
my $informat  = shift or die $usage;
my $outdbname = shift or die $usage;
my $outdbtype = shift or die $usage;

# create one SeqIO object to read in, and another to write out
my $seqin = Bio::SeqIO->new(
                            -file   => "<$infile",
                            -format => $informat,
                            );
my $seqout = Bio::SeqIO->new(
                             -file => "| /usr/local/bin/xdformat -o $outdbname -${outdbtype} -- -",
                             -format => 'Fasta',
                             );

# write each entry in the input to the output
while (my $inseq = $seqin->next_seq) {
    $seqout->write_seq($inseq);
}

可能一些有经验的读者已经意识到new方法返回的是一个引用变量(reference),引用的可以是任意格式的数据。现在来看一个用引用变量存储序列信息的例子。任务是要从一个genbank序列文件中提取出人类的序列并输出到human.gb文件,剩下的序列输出到other.gb文件。这里需要用到两个哈希数组(hash),并分别以“human”和“other”作为下标(key)。

     splitgb.pl inseq.gb
splitgb.pl的代码:

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
use Bio::SeqIO;

# get command-line argument, or die with a usage statement
my $usage  = "splitgb.pl infile\n";
my $infile = shift or die $usage;

my $inseq = Bio::SeqIO->new(
                            -file   => "<$infile",
                            -format => 'Genbank',
                            );

my %outfiles = (
                'human' => Bio::SeqIO->new(
                                           -file   => '>human.gb',
                                           -format => 'Genbank',
                                           ),
                'other' => Bio::SeqIO->new(
                                           -file   => '>other.gb',
                                           -format => 'Genbank',
                                           ),
                );

while (my $seqin = $inseq->next_seq) {
    # here we make use of the species attribute, which returns a
    # species object, which has a binomial attribute that
    # holds the binomial species name of the source of the sequence
    if ($seqin->species->binomial =~ m/Homo sapiens/) {
        $outfiles{'human'}->write_seq($seqin);
    } else {
        $outfiles{'other'}->write_seq($seqin);
    }
}

现在来看用更复杂的多维hash来存储Genbank和fasta的序列信息。

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
use Bio::SeqIO;
# get command-line argument, or die with a usage statement
my $usage  = "splitgb.pl infile\n";
my $infile = shift or die $usage;

my $inseq = Bio::SeqIO->new(
                            -file   => "<$infile",
                            -format => 'Genbank',
                            );

my %outfiles = (
                human => {
                          Genbank => Bio::SeqIO->new(
                                                     -file   => '>human.gb',
                                                     -format => 'Genbank',
                                                     ),
                          Fasta   => Bio::SeqIO->new(
                                                     -file   => '>human.fa',
                                                     -format => 'Fasta',
                                                     ),
                          },
                other => {
                          Genbank => Bio::SeqIO->new(
                                                     -file   => '>other.gb',
                                                     -format => 'Genbank',
                                                     ),
                          Fasta   => Bio::SeqIO->new(
                                                     -file => '>other.fa',
                                                     -format => 'Fasta',
                                                     ),
                          }
                );

while (my $seqin = $inseq->next_seq) {
    if ($seqin->species->binomial =~ m/Homo sapiens/) {
        $outfiles{'human'}->{'Genbank'}->write_seq($seqin);
        $outfiles{'human'}->{'Fasta'}->write_seq($seqin);
    } else {
        $outfiles{'other'}->{'Genbank'}->write_seq($seqin);
        $outfiles{'other'}->{'Fasta'}->write_seq($seqin);
    }
}

最后要说的是单行程序。Perl允许在命令行里用单行程序的方式编写脚本,而不需要放在脚本文件中。如下所示,-e后面用单引号括住脚本代码,-M后面跟所调用的模块。(译者注:-M后面没有空格,-e后面可有可无,多个模块则写多个-M。)当脚本内部也需要使用单引号时必须用q()来代替,防止混淆。下面举的例子是要找出在一个压缩的序列文件中有多少GSS序列。注:为了便于阅读,下面的代码有分行,但在命令行中一般没有写完代码不分行。(译者注:有单引号存在的时候,也可以分行,直到单引号结束再回车才会运行命令。)

perl -MBio::SeqIO -e 'my $gss=0;
my $in=Bio::SeqIO->new(q(-file)=>q(/usr/local/bin/gunzip -c gbpri1.seq.gz |), q(-format)=>q(Genbank));
while (my $seq = $in->next_seq) { $gss++ if ($seq->keywords =~ m/GSS/);}
 print "There are $gss GSS sequences in gbpri1.seq.gz\n";'

警告

因为BioPerl用一个单一而通用的数据接口来存取所有支持格式的文件,有时候Bioperl就会或多或少改变原本文件的数据结构。例如,从GenBank数据库中下载到一个genbank格式的序列,然后用bioperl转换成一个新的genbank格式的序列。用”diff origfile newfile“后会惊奇地发现两者有所不同,这时你就应该明白我第一句说的是什么了。需要记住Bioperl并不提供“往返行程”,它只是通过一个通用的数据接口来获取多种多样序列的信息,并用于其他脚本或程序从中提取所需信息。

纠错

如果所给定的文件不存在,脚本会运行出错并给出相应的错误信息。这用编程术语叫做“抛出异常”。例如:
      user@localhost ~/src/bioperl-live> perl t.pl bollocks silly
      ------------- EXCEPTION  -------------
      MSG: Could not open bollocks for reading: No such file or directory
      STACK Bio::Root::IO::_initialize_io Bio/Root/IO.pm:259
      STACK Bio::SeqIO::_initialize Bio/SeqIO.pm:441
      STACK Bio::SeqIO::genbank::_initialize Bio/SeqIO/genbank.pm:122
      STACK Bio::SeqIO::new Bio/SeqIO.pm:359
      STACK Bio::SeqIO::new Bio/SeqIO.pm:372
      STACK toplevel t.pl:9
      --------------------------------------
这种错误信息非常有用。因为可以从中可以找出出错的地方,也叫“堆栈追踪”。如上例中给出了出错的文件和与错误相关的行号。(译者注:上例中t.pl是用户自己的脚本,出错是在t.pl文件的第9行。其他都是bioperl包含的一些相关模块文件,所列行号只是和错误相关,但一般不会是bioperl本身出错。)

Bioperl会自动识别出类似的错误并终止程序运行。但最好是自己就在脚本中设置一些纠错机制。 可以通过类似下例来“捕获异常”。

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
use strict;
use Bio::SeqIO;

my $input_file  = shift;
my $output_file = shift;

# we have to declare $seq_in and $seq_out before
# the eval block as we want to use them afterwards

my $seq_in;
my $seq_out;

eval {
    $seq_in   = Bio::SeqIO->new(
                                -format => 'genbank',
                                -file   => $input_file,
                                );

    $seq_out  = Bio::SeqIO->new(
                                -format => 'fasta',
                                -file   => ">$output_file",
                                );
};
if( $@ ) { # an error occurred
    print "Was not able to open files, sorry!\n";
    print "Full error is\n\n$@\n";
    exit(-1);
}
my $seq;
while( $seq = $seq_in->next_seq() ) {
    $seq_out->write_seq($seq);
}

eval是perl的一种纠错机制,不止是BioPerl才有。如果eval {BLOCK}中的一段程序出错后,回将错误信息返回到$@变量。需要注意的是:必须提前声明变量 $seq_in$seq_out。如果在eval {}内用my声明变量,此变量只被设定在eval{}中,当在eval{}之后调用此变量是就会出错(用use strict时会提示错误并终止运行)。

提速, Bio::Seq::SeqBuilder

如果需要处理大批量的序列,且只需要从中提取很少部分信息(如只提取genbank文件中的序列),可以使用Bio::Seq::SeqBuilder来设定Bio::SeqIO只提取需要的部分信息。这样能够节省很多时间从而提升脚本的运行速度。

例如,只需要genbank文件中三类注释信息,可提升大约6倍的速度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/perl

use strict;
use Bio::SeqIO;
use Benchmark qw(:all);

my $file = "gbbct10.seq";

timethis(1, sub {
   my $in = Bio::SeqIO->new(-file => $file, -format => "genbank");
   for (1..1000) {
      my $seq = $in->next_seq;
   }
});

timethis(1, sub {
   my $in = Bio::SeqIO->new(-file => $file, -format => "genbank");
   my $builder = $in->sequence_builder();
   $builder->want_none();
   $builder->add_wanted_slot('display_id','desc','seq');
   for (1..1000) {
      my $seq = $in->next_seq;
   }
});

结果:

timethis 1: 10 wallclock secs ( 9.64 usr +  0.02 sys =  9.66 CPU) @  0.10/s (n=1)
            (warning: too few iterations for a reliable count)
timethis 1:  1 wallclock secs ( 1.63 usr +  0.00 sys =  1.63 CPU) @  0.61/s (n=1)
            (warning: too few iterations for a reliable count)
更多相关内容见HOWTO:Feature-Annotation

Bioperl入门其他部分(Bioperl HOWTO翻译12)

| Comments

(译者注:Beginners HOWTO翻译到此结束,从Searching for genes in genomic DNA部分往后都是一些有关bioperl和其他程序接口:调用其他程序并分析结果。专一性比较强,且需要对各个软件有很好的了解并正确安装和设定。个人觉得不怎么值得翻译,对此有兴趣的童鞋应该可以看懂英文然后自己研究清楚的。

后面的HOWTO都是一个个专题,会将同一个HOWTO放在单篇blog里,大部分HOWTO内容都比较长,翻译的时间可能也比较长,先发布全英文的,然后再慢慢翻译成中文,请见谅。)

Bioperl快速检索序列(Bioperl HOWTO翻译11)

| Comments

索引序列文件以用于快速检索

英文原文

索引序列是Bioperl一个非常出色的功能。你可以将需要处理的本地序列文件建立一个索引然后利用这个索引提取你所需要的序列文件。这样做最重要的原因是——速度!从有索引的大量本地序列中提取所需序列要比用Bio::DB::GenBank从远程数据库中提取快得多。也比用SeqIO快,因为SeqIO要一个一个通读每一个序列,然后才能找到所需的。灵活性是另一个原因。自己的有些序列毕竟不同于公共数据库上的序列,将自己收集的序列建立索引可用于日后快速的提取。

需要说明,在提取序列时的唯一要求是,所提供的要提取序列的id必须具有唯一性。(译者注:如果要提取所有相同有某特征序列,比如想要refseq,即id中包含“_”的序列,可以灵活变通:先输出所有id,然后选取那些有“_”的id,然后再用这些id提取序列信息。)

Bioperl有多个用于索引序列的模块,如 Bio::Index::*类和Bio::DB::Fasta。 这些模块的原理都是一样的,先索引一个或多个序列文件,然后再根据id提取序列。先以Bio::Index::Fasta为例。使用此模块时要先设定一个终端环境变量,如下:

1
2
use Bio::Index::Fasta;
$ENV{BIOPERL_INDEX_TYPE} = "SDBM_File";

可见在Perl脚本中也可以设定终端环境变量,此变量存贮在叫%ENV的特殊hash中。此设置当然也可以在终端中设定,在tcsh或csh中如下:

>setenv BIOPERL_INDEX_TYPE SDBM_File
在bash shell中设定如下:
>export BIOPERL_INDEX_TYPE=SDBM_File
BIOPERL_INDEX_TYPE是环境变量名, SDBM_File是变量的值。(译者注:SDBM是perl使用的一种文件格式,用于将hash保存在一个SDBM文件中。见这里). BIOPERL_INDEX指定索引文件所在的目录,可以通过设定此变量建立多个索引文件。(译者注:可以设定“setenv BIOPERL_INDEX /nfs/datadisk/bioperlindex/”,详见

看例子:

1
2
3
4
5
6
7
$ENV{BIOPERL_INDEX_TYPE} = "SDBM_File";
use Bio::Index::Fasta;

$file_name = "sequence.fa";
$id = "48882";
$inx = Bio::Index::Fasta->new (-filename => $file_name . ".idx", -write_flag => 1);
$inx->make_index($file_name);

在sequence.fa所在的目录下运行此脚本,将会在该目录下自动生成一个equence.fa.idx索引文件,然后可以通过下一语句提取所需序列:

1
$seq_obj = $inx->fetch($id)

默认以 >符号来识别fasta格式的序列,如果是要提取“48882”为id的序列,该序列头信息应该是类似下面的格式:

>48882 pdb|1CRA
但是,如果想按照其他字符串提取序列,比如上例中“1CRA”,可以通过id_parser改变索引id的格式,(将自定义的index格式通过一个子函数传递给id_parser),详见Bio::Index::Fasta。例如:

1
2
3
4
5
6
7
8
$inx->id_parser(\&get_id);
$inx->make_index($file_name);

sub get_id {
    $header = shift;
    $header =~ /pdb\|(\S+)/;
    $1;
}

准确地说,id_parser接受的是一个子函数的引用变量(a reference to a function)。

再来看Bio::DB::Fasta,相对Bio::Index::Fasta有些更好的功能。主要是:可以处理大批量序列 ;可以很方便地提取序列片段。示例:

1
2
3
4
5
use Bio::DB::Fasta;
($file,$id,$start,$end) = ("genome.fa","CHROMOSOME_I",11250,11333);
$db = Bio::DB::Fasta->new($file);
$seq = $db->seq($id,$start,$end);
print $seq,"\n";

此脚本将genome.fa建立索引,然后提取CHROMOSOME_I上从11250到11333的序列片段。也可以如Bio::Index::Fasta一样自定义要索引的id。(译者注:在new()中设定-makeid参数,此参数使用方法和上面的id_parser一样。详见Bio::DB::Fasta

更多的信息可见HOWTO:Local_Databases