使用TEclass对TE一致性序列进行分类

软件安装

软件地址在http://www.compgen.uni-muenster.de/tools/teclass/index.hbi?, 由于TEclass这个软件已经许久没有更新了,因此还要讲解下安装步骤。

最近更新了一个2.1.3c, 经过我测试发现,应该就是把之前无法下载URL做了更新。classifiers.tar.gz无更新。

1
2
3
wget http://www.compgen.uni-muenster.de/tools/teclass/download/TEclass-2.1.3.tar.gz
tar xf TEclass-2.1.3.tar.gz
cd TEclass-2.1.3

下载依赖的软件

1
sh Download_dependencies.sh

由于代码老旧,部分内容无法自动下载,需要手动下载, 例如librf, blast. 最终要保证文件夹下有如下文件

例如blast

1
curl -o 'blast.tar.gz' ftp://ftp.ncbi.nlm.nih.gov/blast/executables/legacy.NOTSUPPORTED/2.2.26/blast-2.2.26-x64-linux.tar.gz

编译依赖的软件

1
sh Compile_dependencies.sh

安装过程

安装TEclass, 这一步可以跳过 RepBase的配置。

1
perl Configure.pl

安装预编译的分类器,这一步在TEclass的目录下运行,并解压缩

1
2
3
4
wget http://www.compgen.uni-muenster.de/tools/teclass/download/classifiers.tar.gz
mv classifiers.tar.gz classifiers/
cd classifiers
tar xf classifiers.tar.gz

测试运行

1
./TEclassTest.pl ./testfile.fa

软件使用

构建分类器

如果你想使用最新的RepBase,那么就需要自己从RepBase下载数据进行构建。

如果是单核处理器,可能要花费数周的时间,所以建议用上你的所有线程。

1
/TEclassBuild.pl -x 0  -o new_classifiers -p 99

重复序列分类

在RepeatModeler建模后,提取Unknown序列使用TEclassTest进行归类,假如输入文件命名为Modelerunknown.lib

1
TEclassTest Modelerunknown.lib

结果在Modelerunknown.lib_xxxx, xxxx是你运行日期。

1
2
3
4
Modelerunknown.lib # 输入文件
Modelerunknown.lib.html
Modelerunknown.lib.lib # 输出结果
Modelerunknown.lib.stat #结果统计

Modelerunknown.lib.lib中的fasta会有分类信息,如

1
>rnd-1_family-12#Unknown ( RepeatScout Family Size = 705, Final Multiple Alignment Size = 88, Localized to 114 out of 117 contigs )|TEclass result: LTR|forward|ORFs: 583..2355:+1

需要注意的是,TEclass的输出结果是不被RepeatMasker所识别的,需要你更改原来的#Unknown为你的预测结果才行。

其他参数:

  • -c: 训练的分类器所在路径, 默认是TEclass-2.1classifiers
  • -o: 输出结果路径,默认在当前文件下新建
  • -r: 预测输入序列的反向互补序列

参考文献: TEclass: a tool for automated classification of unknown eukaryotic transposable elements

使用Pilon对基因组进行polish

使用Pilon对基因组进行polish

软件安装

官方提供了编译好的jar包,方便使用

1
2
wget https://github.com/broadinstitute/pilon/releases/download/v1.22/pilon-1.22.jar
java -Xmx16G -jar pilon-1.22.jar

如果要顺利运行程序,要求JAVA > 1.7, 以及根据基因组大小而定的内存,一般而言是1M大小的基因对应1GB的内存。

总览

Pilon有如下作用

  1. 对初步组装进行polish
  2. 寻找同一物种不同株系间的变异,包括结构变异检测

他以FASTA和BAM文件作为输入,根据比对结果对输入的参考基因组进行提高,包括

  • 单碱基差异
  • 小的插入缺失(indels)
  • 较大的插入缺失或者block替换时间
  • 填充参考序列中的N
  • 找到局部的错误组装

最后它输出polish后的FASTA文件, 以及包含变异信息的VCF文件(可选)

分析流程

推荐使用PCR-free建库测序得到的Illumina paired-end数据,这样子避免了PCR-duplication,有效数据更多,也不需要在分析过程中标记重复。

下面步骤,假设你的组装文件为draft.fa, 质量控制后的illumina双端测序数据分别为read_1.fq.gzread_2.fq.gz

第一步:比对

1
2
3
bwa index -p index/draft draft.fa
bwa mem -t 20 index/draft read_1.fq.gz read_2.fq.gz | samtools sort -@ 10 -O bam -o align.bam
samtools index -@ 10 align.bam

第二步:标记重复(非PCR-free建库)

1
sambamba markdup -t 10 align.bam align_markdup.bam

第三步:过滤高质量比对的read

1
2
samtools view -@ 10 -q 30 align_markdup.bam > align_filter.bam
samtools index -@ 10 align_filter.bam

第三步:使用Pilon进行polish

1
2
3
4
MEMORY= #根据基因组大小而定
java -Xmx${MEMORY}G -jar pilon-1.22.jar --genome draft.fa --frags align_filer.bam \
--fix snps,indels \
--output pilon_polished --vcf &> pilon.log

关于Pilon的一些参数说明:

  • --frags表示输入的是1kb以内的paired-end文库,--jumps表示 大于1k以上的mate pair文库, --bam则是让软件自己猜测
  • -vcf: 输出一个vcf文件,包含每个碱基的信息
  • --fix: Pilon将会处理的内容,基本上选snpsindels就够了
  • --variant: 启发式的变异检测,等价于--vcf --fix all,breaks, 如果是polish不要使用该选项
  • minmq: 用于Pilon堆叠的read最低比对质量,默认是0。

阅读日志输出

这个日志文件是标准输出而不是标准错误输出,不过保险起见用&>

最开始,Pilon会输出他的版本信息(如下示例),以及将会对基因组做的调整,

1
2
3
Pilon version 1.14 Sat Oct 31 14:30:00 2015 -0400
Genome: genome.fasta
Fixing snps, indels

其中Fixing后面的含义为:

  • “snps”: 单碱基差异
  • “indels”:小的indel的差异
  • “amb”: 替换原有的N
  • “gaps”: 填充基因组的gap
  • “local”: 检测和修改错误组装
  • “all”: 上述所有
  • “none”: 不是上述的任何一种

接着Pilon会分染色体对BAM文件进行处理,根据BAM文件进行堆叠(pileup), 这个时候它会输出有效reads的深度,这里的有效reads包括未成对的read和正确成对的read。

1
2
3
Processing ctg1:1-5414473
frags align_mkdup.bam: coverage 19
Total Reads: 808985, Coverage: 19, minDepth: 5

从Pilon v1.4开始,Pilon还会输出基因组得到确认的碱基比例。

1
Confirmed 5403864 of 5414473 bases (99.80%)

后续是Pilon将会对原参考基因组做的一些调整的总体情况,如下表示纠正2个snp, 2个小的插入,4个缺失。

1
Corrected 2 snps; 0 ambiguous bases; corrected 2 small insertions totaling 12 bases, 4 small deletions totaling 6 bases

最后声明当前部分处理结束

1
Finished processing ctg1:1-5414473

如果,在--fix中选了gaps, 那么输出的内容还有如下内容。其中82048 -0 +276解释为在坐标82428处移除0个碱基,插入276个碱基。

1
2
3
4
# Attempting to fill gaps
fix gap: scaffold00001:82428-93547 82428 -0 +276 ClosedGap


参考资料

如何使用MUMmer比对大片段序列

如何使用MUMmer比对大片段序列

测序技术刚开始发展的时候,大家得到的序列都是单个基因的长度,所以一般都是逐个基因的比较,用的都是BLAST或FASTA通过逐个基因联配的方式搜索数据库。但是1999年后,越来越多的物种全基因组出现,比如说在1999年出现了_Helicobacter pylori_的第二类菌株的基因组序列,就需要研究同一物种不同品系进化过程的基因组变化,比如说基因倒置现象。传统的BLAST/FASTA就用不了,就需要用到新的工具,这就是MUMmer出现的历史背景。

那么MUMmer能用来研究什么呢?比如说细菌的不同菌株基因组中倒置现象,人和老鼠的基因组在进化上的重排现象。还有比较同一物种的不同组装结果等。MUMmer的算法基础(suffix tree)使得它的速度比BLASTZ(k-mers)快得多,但是灵敏度低,也就是检测不到比较弱的匹配,但是作者说这都是可以通过修改参数进行改善

安装

MUMmer是开源软件,因此可以通过下载源码编译的方式进行安装,同时biconda上已经有编译好的二进制版本方便用conda进行安装。目前,我个人比较推荐使用源码编译的方式进行安装。目前MUMmer已经更新到第四版,但是还在测试中,所以文章也没有发,求稳还是用3.23.

多说一句,如果在bioconda频道上搜索mummer, 会发现一个pymummer,不要以为这是mummer的源代码用python改写,它仅仅做到了通过调用系统安装的MUMmer的工具的方式运行而已,并且功能目前实在是太弱了。

1
2
3
4
5
6
7
8
9
10
# MUMmer3.23
wget https://gigenet.dl.sourceforge.net/project/mummer/mummer/3.23/MUMmer3.23.tar.gz
tar -xf MUMmer3.23.tar.gz
cd MUMmer3.23
make install
# MUMmer4.00-beta2
wget https://github.com/mummer4/mummer/releases/download/v4.0.0beta2/mummer-4.0.0beta2.tar.gz
tar xf mummer-4.0.0beta2.tar.gz
cd mummer-4.0.0beta2
./configure --prefix=$HOME/biosoft/mummer-4.0.0beta2 && make && make install

为了方便使用记得将软件路径加入PATH。

MUMmer使用方法

MUMmer的核心基于 Maximal exact matching 算法开发的mummer。其他工具(nucmer,promer)都是基于mummer的开发的流程。这些流程的分析策略分为三步:

  1. mummer在两个输入中找给定长度的极大唯一匹配( Maximal exact matching )
  2. 然后将这些匹配区域聚类成较大不完全联配区域, 作为锚定点(anchor)
  3. 最后它从每个匹配外部扩展联配, 形成有gap的联配。

Maximal exact matching

MUMmer核心是基于后缀树(suffix tree)数据结构的最大匹配路径。 根据这个算法开发出来的repeat-matchexact-tandems可以从单个序列中检测重复,mummer则是用于联配两条或两条以上的序列。由于MUMmer的其他工具基本都是基于mummer开发的,于是理解mummer就变得非常重要。

概念1:suffix tree: 表示一个字符串的所有子字符串的数据结构,比如说abc的所有子字符串就是a,ab,ac,bc,abc.
概念2:Maximal Unique Match: 指的是匹配仅在两个比较序列中各出现一次

mummer: 基于后缀树(suffix tree)数据结构,能够在两条序列中有效定位极大唯一匹配(maximal unique matches),因此它比较适用于产生一组准确匹配(exact matches)以点图形式展示,或者用来锚定从而产生逐对联配(pair-wise alignments)

大部分情况下都不会直接用到mummer,所以只要知道MUMmer历经几次升级,使得mummer可以能够只找在reference和query都唯一的匹配(第一版功能),也可以找需要在reference唯一的匹配(第二版新增),甚至不在乎是否唯一的匹配(第三版新增),参数分别为-mum,-mumreference,maxmatch

repeat-matchexact-tandems比较少用,毕竟参数也不多,似乎有其他更好的工具能用来寻找序列中的重复区。

Clustering:聚类

MUMmer的聚类算法能够比较智能地把几个独立地匹配按照顺序聚成一块。分为两种模式gapsmgaps。这两者差别在于是否允许重排,分别用于run-mummer1,run-mummer3.

gaps
mgaps

基于gapmgaps的输出,第四版还提供了annotatecombineMUMs两个工具增加联配信息。

联配构建工具

基于上述两个工具,作者编写了4个工作流程,方便实际使用。

  • nucmer: 由Perl写的流程,用于联配很相近(closely related)核酸序列。它比较适合定位和展示高度保守的DNA序列。注意,为了提高nucmer的精确性,最好把输入序列先做遮盖(mask)避免不感兴趣的序列的联配,或者修改单一性限制降低重复导致的联配数。
  • promer:也是Perl写的流程,它以翻译后的氨基酸序列进行联配,工作原理同nucmer.
  • run-mummer1,run-mummer3: 两者是基于cshell写的流程,用于两个序列的常规联配,和promer,nucmer类似,只不过能够自动识别序列类型。它们擅长联配相似度高的DNA序列,找到它们的不同,也就是适合找SNP或者纠错。前者用于1v1无重排,后者1v多有重排

重点介绍一下nucmer的使用。reference和query文件都需要时fasta格式,每个都可以有多条序列。

1
nucmer [options] <reference> <query file>

参数我将其分为五个部分,匹配算法,聚类,外延、其他和新增

匹配:

1
2
3
--mum, --mumreference(默认), --maxmatch
--minmatch/-l: 单个匹配最小长度
--forwoard/-f, --reverse/-r: 只匹配正链或只匹配负链。

聚类:

1
2
3
4
--mincluster/-c: 用于聚类的匹配最低长度,默认65
--maxgap/-g: 两个相邻匹配间的最大gap长度,默认90
--diagdiff/-D: 一个聚类中两个邻接匹配,最大对角差分,默认5
--diagfactor/-d: 也是和对角差分相关参数,只不过和gap长度有关,默认0.12

外延:

1
2
3
--breaklen/-b: 在对联配两端拓展式,在终止后继续延伸的程度,默认200
--[no]extend:是否外延,默认是
--[no]optimize:是否优化,默认是。即在联配分数较低时不会立刻终止,而是回顾整条联配,看能否苟延残喘一会。

其他:

1
2
3
4
--depend: 显示依赖信息后退出
--coords: 调用show-coords输出坐标信息
--prefix/-p: 输出文件的前缀
--[no]delta: 是否输出delta文件,默认是

新增

1
2
3
4
5
6
7
# 在第四版新增的参数
--threads/-t: 多核心
---delta=PATH: 指定位置,而不是当前
--sam-short=PATH:保存为SAM短格式,不保存匹配的序列,也就是第十列为*
--sam-long=PATH: 保存为SAM长格式,保存匹配的序列
--save=PREFIX:保存suffix array
--load=PREIFX:加载suffix array

运行后得到一个delta格式的文件,它的作用是记录每个联配的坐标,每个联配中的插入和缺失的距离。下面逐行进行解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/home/username/reference.fasta /home/username/query.fasta # 两个比较文件的位置
PROMER # 程序运行类型: NUCMER或PROMER
>tagA1 tagB1 3000000 2000000 # 一组联配(可以有多个小匹配),ref的fastaID,qry的fastaID,ref序列长度,qry序列长度
1667803 1667078 1641506 1640769 14 7 2 # 第一小组 ref起始,ref结束,qry起始,qry结束,错误数(不相同碱基+indel碱基数),相似错误(非正匹配得分) 终止密码子(NUCMER为0)。 如果结束大于起始,表示在负链。
-145 # qry的145有插入
-3 # qry的145+3=148有插入
-1 # qry的145+3+1=149有插入
40 # qry的145+3+1+40=149有缺失
0 # 表示当前匹配结束
1667804 1667079 1641507 1640770 10 5 3 # 第二小组
-146
-1
-1
-34
0

用法举例

两个完整度高的基因组

比较常见的用法是把一条连续的序列和另一条连续的序列比。比如说两个细菌的菌株,直接用mummer

1
2
3
4
5
6
wget http://mummer.sourceforge.net/examples/data/H_pylori26695_Eslice.fasta
wget http://mummer.sourceforge.net/examples/data/H_pyloriJ99_Eslice.fasta
mummer -mum -b -c H_pylori26695_Eslice.fasta H_pyloriJ99_Eslice.fasta > 26695_J99.mums
# -mum: 计算在两个序列中唯一的最大匹配数
# -b: 计算正向和反向匹配数
# -c: 报告反向互补序列相对于原始请求序列的位置

或者是高度相似序列,不含重排

1
2
3
run-mummer1 ref.fasta qry.fasta ref_qry
# 仅报告负链匹配序列
run-mummer1 ref.fasta qry.fasta ref_qry -r

或者是高度相似序列,存在重排现象

1
run-mummer3 ref.fasta qry.fasta ref_qry

以上的run-mummer*比较关注序列的不同之处,那么对于相似度没有那么高的两个序列,就需要用到nucmernucmer关注序列的相似之处,所以它允许重排,倒置和重复现象。nucmer允许多对多的比较方式,当然比较常用的是多对一的比较。

1
2
3
nucmer --maxgap=500 --mincluster=100 --prefix=ref_qry ref.fasta qry.fasta
## --maxgap: 两个match间最大gap为500
##--minclster: 至少要有100个match才能算做一簇

注意一点: 第四版中run-mummer1, run-mummer3已经被废弃了,就是尽管保留了,但是没有对它做任何升级的意思。

如果是有点差异的两个序列,可以用翻译的氨基酸序列进行比较

1
promer --prefix=ref_qry ref.fasta qry.fasta
两个基因草图

上面都是两条序列间的比较,但是研究植物的人更容易遇到的是两个物种的基因组都只有scafold级别,甚至是contig级别。那么就可以使用nucmerpromer构建序列间的可能联配。

1
2
3
4
5
# 首先过滤低于1kb的序列
bioawk -c fastx '{if (length($seq) > 1000) print ">"$name "\n"$seq}' ~/reference/genome/rice_contigs/HP1 > HP103_1kb.fa
bioawk -c fastx '{if (length($seq) > 1000) print ">"$name "\n"$seq}' ~/reference/genome/rice_contigs/HP119.fa > HP119_1kb.fa
# 处理,时间会比较久,因为分别有20109,17877条contig
nucmer --prefix HP103_HP119 HP103_1kb.fa HP119_1kb.fa &
一个基因草图对一个完整基因组

这里可以比较一下水稻日本晴基因组和其他地方品种

1
2
3
nucmer  --prefix IRGSP1_DHX2 ~/reference/genome/IRGSP1.0/IRGSP-1.0_genome.fasta ~/reference/genome/rice_contigs/DHX2.fa
# 第四版提供SAM输出和多核支持
~/biosoft/mummer-4.0.0beta2/bin/nucmer -t 15 --sam-short=SAM_OUT/DHX2 ~/reference/genome/IRGSP1.0/IRGSP-1.0_genome.fasta ~/reference/genome/rice_contigs/DHX2.fa &

在第四版中新增了一个dnadiff,进一步封装nucmer和其他数据整理工具,基本上没啥参数,而输出很齐全,非常的人性化。在不知如何开始的时候,可以无脑用这个。

1
2
3
4
# 已有delta文件
dnadiff -d IRGSP1_DHX2.delta
# 未有delta文件
dnadiff IRGSP1_DHX2 ~/reference/genome/IRGSP1.0/IRGSP-1.0_genome.fasta ~/reference/genome/rice_contigs/DHX2.fa

数据整理

之前得到的数据还需要用delta-filter,show-coordsshow-tilling进行进一步整理才能用于后续的分析。后续操作基于上面的基因草图和完成基因组比较结果。

最初的比对结果保留了最多的信息,需要用delta-filter进行一波过滤,除去不太合适的部分。过滤选项有

  • -i: 最小的相似度 [0,100], 默认0
  • -l: 最小的匹配长度 默认0.
  • -u: 最小的联配唯一度 [0,100], 默认0
  • -o: 最大重叠度,针对-r-q设置。 [0,100], 默认100
  • -g: 1对1全局匹配,不允许重排
  • -1: 1对1联配,允许重排,是-r-q的交集
  • -m: 多对对联配,允许重排,是-r-q的合集。
  • -q: 仅保留每个query在reference上的最佳位置,允许多条query在reference上重叠
  • -r: 仅保留每个reference在query上的最佳位置,允许多条reference在query上重叠

以上顺序是-i -l -u -q -r -g -m -1.光看参数估计不太明白,来一波图解。referece的一个片段可以联配到query的多个片段上,同样的query的一个片段也可以联配到reference的多个片段上,那么如何取舍呢?

多对多

通过-i,-l可以先过滤一些比较短,并且相似度比较低的匹配情况。进一步,计算长度和相似度的乘积(加权最长增加子集),对于-q而言就是保留左2,对于-r则是保留右3. 这就是传说中的三角关系,这种关系可以用-m保留或者用-q消灭。

比如说我想看contig和reference两者唯一匹配,并且长度在1000,相似度大于90.

1
delta-filter -i 89 -l 1000 -1 IRGSP1_DHX2.delta > IRGSP1_DHX2_i89_l1000_1.delta.filter

如何才能验证上面参数运行的结果是符合要求的呢?毕竟数据分析第一原则“不要轻易相信分析结果,需要多次验证才能使用”。

可以先用show-coord以人类可读的格式显示匹配的坐标。

1
2
3
show-coords -r IRGSP1_DHX2_i89_l1000_1.delta.filter > IRGSP1_DHX2_i89_l1000_1.coord
# -r:以refID排序,相对的,还有-q,以queryID排序
less IRGSP1_DHX2_i89_l1000_1.coord

不难发现这个位置锚定的非常不错,至少暂时看起来没有重叠之处

coord信息

show-aligns看某一个匹配的序列比对情况。

1
show-aligns IRGSP1_DHX2_i89_l1000_1.delta.filter chr01 DHX2_00006753 | less

alignment

针对reference有很长的组装序列的情况,还可以用show-tilling将contig回贴到reference上,如果装了gnuplot还能用mummerplot可视化点图.show-tiling会尝试根据contig和reference匹配信息构建出tiling path(不好翻译呀。。),不怎么用得到。

show-snps可以根据delta文件整理出SNP信息,我表示也没有怎么用到。

SAMtools:SAM格式的处理利器

SAM格式介绍

SAM全称是Sequence Alignment/Map, 是目前最常用的存放比对或联配数据的格式。无论是重测序,还是转录组,还是表观组,几乎所有流程都会产生SAM/BAM文件作为中间步骤,然后是后续专门的分析过程。

以一个简单的例子介绍.第一幅图表示read和参考基因组比对可能出现的情况。r001/2表示paired end数据。r003是嵌合read,r004则是原序列打断后比对结果。

原始数据

经过专门的比对软件,如BWA,BOWTIE2等,得到的SAM文件如下所示,需要研究的就是如下这几行。

比对后存放形式

术语和概念

在学习SAM格式之前,请确认自己是否对如下概念有清楚的认识|

  • read: 测序仪返回的原始序列.一个read可以包括多个segment。read之间的先后顺序表示被测序仪读到的时间前后关系.
  • segment: 一段连续的序列或子序列
  • linear alignment: 线性联配表示一个read比对到单个参考序列,可以存在插入,缺失,跳过(skip),剪切(clip), 但是不存在方向改变的情况(比如说一部分和正向链联配,另一个位置则是和负向链联配)。最简单的判断的方式就是,一个linear alignment只用一行记录。
  • chimeric alignment: 嵌合联配需要多行记录。比如说r003第一个记录是后6个匹配,第二个记录则是反向序列的后5个匹配。第一个被称之为”representative”,其他都是”supplementary”
  • read alignment: 无论是linear alignment, 还是chimeric alignment, 只要能完整表示一个read,都成为是read alignment
  • multiple mapping: 由于存在重复区,一个read 可能比对到参考基因组的不同区域。其中一个被认为是primary,其他都是secondary.
  • 两个系统|1-based coordinate system(SAM,VCF,GFF,wiggle)和0-based coordinate system(BAM, BCFv2, BED, PSL).自行用R和Python感受一下两者的不同。

chimeric alignment 可能是结构变异,基因融合,参考序列误组装,RNA-Seq,实验protocol等因素造成。对于chimeric alignment的里面每一个linear alignment而言,由于相互之前不存在重叠,故而联配质量较高,适合用于SNP/INDEL calling.相反, multiple mapping则是因为重复造成(read越长出现的概率越低), 相互之间存在重叠,仅有其中一条有最优的匹配,其他联配质量过低会被SNP/INDEL caller忽略。

第一部分| SAM Header(非强制)

这个部分能够被/^@[A-Z][A-Z](t[A-Za-z][A-Za-z0-9]:[ -~]+)+$//^@COt.*/这两个表达式进行匹配。比如说你随便有一个BAM文件(包含header),就能被这个表达式进行匹配。

1
2
samtools view -h S43S1-M_H3K5FDMXX_L1_sort.bam 
| awk '$0 ~ /^@[A-Z][A-Z](t[A-Za-z][A-Za-z0-9]:[ -~]+)+$/ { print $0}'

header

其中第一行@HD,表示参考基因组的排序情况. 然后@SQ则是参考基因组的每一条序列的具体信息,命名和长度。@PG记录运行的命令,以便你检查代码。对于GATK还需要提供@RG给出每个read所在group的信息,只要保证是独一即可。

第二部分| 联配必要信息

第二部分具体记录每一个read的联配结果,一共有11+n列。我将第二张图的信息复制保存到test.sam中,仅仅看第一行

1
2
3
4
5
6
7
8
9
10
11
12
13
samtools view test.sam | head -n1 | tr 't' 'n' | nl
1 r001 # QNAME: read信息
2 99 # FLAG: 信息量大
3 ref # RNAME: 参考序列
4 7 # POS:比对到的位置
5 30 # MAPQ: 比对质量
6 8M2I4M1D3M # CIGAR: 信息量大
7 = # RNEXT: 配对read所在序列,=表示同一条序列
8 37 # PNEXT: 配对read所在位置
9 39 # TLENT: 观察到的模板长度
10 TTAGATAAAGGATACTG # SEQ: segment序列
11 * # QUAL: segment的质量
# *表示信息不存在

简单解释TLENT: 通过IGV可视化展示克制,TLENT相当于read发现了参考序列那些区域。如果是PE数据还可以推断出文库平均大小。

一个PE数据
IGV展示

详细介绍FLAG: FLAG的主要目的就是用较少的记录长度表示当前记录的序列的匹配情况。相当于开关,仅有有无两个状态,有某个数值就表示序列符合某个情况。

flag 代表 具体含义
1(0x1) PAIRED 代表这个序列采用的是PE双端测序
2(0x2) PROPER_PAIR 代表这个序列和参考序列完全匹配,没有插入缺失
4(0x4) UNMAP 代表这个序列没有mapping到参考序列上
8(0x8) MUNMAP 代表这个序列的另一端序列没有比对到参考序列上,比如这条序列是R1,它对应的R2端序列没有比对到参考序列上
16(0x10) REVERSE 代表这个序列比对到参考序列的负链上
32(0x20) MREVERSE 代表这个序列对应的另一端序列比对到参考序列的负链上
64(0x40) READ1 代表这个序列是R1端序列, read1;
128(0x80) READ2 代表这个序列是R2端序列,read2;
256(0x100) SECONDARY 代表这个序列不是主要的比对,一条序列可能比对到参考序列的多个位置,只有一个是首要的比对位置,其他都是次要的
512(0x200) QCFAIL 代表这个序列在QC时失败了,被过滤不掉了(# 这个标签不常用)
1024(0x400) DUP 代表这个序列是PCR重复序列(#这个标签不常用)
2048(0x800) SUPPLEMENTARY 代表这个序列是补充的比对(#这个标签具体什么意思,没搞清楚,但是不常用)

举例说明,比如说实例中的99=64+32+2+1, 也就是这个记录所代表的read是来自于双端测序R1,且匹配的非常好,对应的另一条链匹配到了负链(自己是正链)。而147=128+16+2+1则是表示这个记录来自于双端测序的R2,完全匹配到负链. 如果是163和83,你会发现163=147-16+32, 83=99-32+16,也就是刚好和前面的不同,也就是说R1匹配负链,R2匹配正链。如果是81和161,由于161=163-2,81=83-2. 表明这些read不是完全匹配,存在插入缺失

那么问题来了,如下是我某一次比对的flag的统计情况,你能看出什么来

小测试

常见的FLAGs:

  • 其中一条reads没有map上: 73, 133, 89 121, 165, 181, 101, 117, 153, 185, 59, 137
  • 两条reads都没有map上: 77,141
  • 比对上了,方向也对,也在插入大小(insert size)内: 99, 147, 83, 163
  • 比对上了,也在插入大小(insert size)内, 但是反向不对:67, 131, 115, 179
  • 单一配对,就是插入大小(insert size)不对: 81, 161, 97, 145, 65, 129, 113, 177

FLAG仅仅存储比对的大致情况,每条比对上的read的实际情况则是要用CIGAR进行记录. 依旧举几个例子,比如说,这是双端测序的一条read比对情况,其中一个是117表示没有匹配上,所以记录就是*,另一个是185表示这条序列完美匹配,所以记录是150M.

1
2
ST-E00600:109:H3K5FALXX:2:1103:17996:34788      117     Chr1    38      0       *       =       38      0       TTTATACACTATGATTTTCAAAGTGAGAATCCGGTTTGTGGTTTATTGTTTTAGGTATTTAGTTATTAATGTATTTTGGATTTATTGATTTAGTGTTTTAGTGATTAATTATTCATTGTTTTAGTGTTTATGGTTTAGTGTTTAGGGTTT  J-7-J------JJJ7JJJ-J-J---JJ-----JJJJJ--J-JJJJ-----JJ--JJJJJJ-J--JJJ7JJ-7-J-J-777JJJJ777JJ7JJ77J7JJJJ7777JJ77777JJJ777J77J77J7JJJJ77JJJJJJJ7JJJJJJFFFAA  MC:Z:150M       AS:i:0  XS:i:0
ST-E00600:109:H3K5FALXX:2:1103:17996:34788 185 Chr1 38 60 150M = 38 0 CATTAATCCCTAAATCCCTAAATCTTTAAATCCTACATCCATGAATCCCTAAATAACTAATTCCCTAAACCCGAAACCTGTTTCTCTGGTTGAAAATCATTGTGTATATAATGATAATTTTATCGTTTTTATGTAATTGCTTATTGTTTT J-JJ7JJJ-JJJ7JJ--JJJ--JJ-JJJJJJ-JJJJJJ--J-JJJJJJJJJ--JJ-JJJJJJJ-JJJJ--J----J-J--JJJJJJ777JJJ77J7JJJJJJJ7JJJJJ7JJJJJ77JJJJJJ7JJ7JJJ7JJJJJJJJJJJJJJFFF<A NM:i:4 MD:Z:1C53C22G69G1 AS:i:136 XS:i:0

来一个复杂的例子69H10M3I31M37H,表示150bp的读长,先删掉69个碱基,后面是10个匹配,后面相比较参考基因组有3个插入,随后是31个匹配,最后再剔除37个基因,通过IGV查看在参考基因组的情况如下图所示。

IGV查看FLAGS

我还发现这段区域存在特别多的clip,加载GFF查看注释信息后发现这是内含子区域。

IGV检查

实际上,CIGAR一共有9个字符,分别是M(alignment match),I(insertion),D(deletion),N(skip),S(soft clip),H(hard clip),P(padding),=(sequence match), X(sequence mismatch).值得提醒就是M表示序列能够联配,但是存在碱基不一致,=表示碱基相同。S和H一般用于read前后出现大部分的错配,但是中间能够联配的情况,其中S表示序列会出现在SEQ中,H则不会出现在SEQ列中。

第三部分,可选信息

除了之前的11列必须要有的信息外,后面的其他列都是不同的比对软件自定义的额外信息,称之为标签(TAG)。标签的格式一般为TAG:TYPE:VALUE,比如说NM:i:4 MD:Z:1C53C22G69G1 AS:i:136 XS:i:0。这部分内容见http://samtools.github.io/hts-specs/SAMtags.pdf. 介绍几个比较常见的标签

  • NM: 编辑距离(edit distance)
  • MD: 错配位置/碱基(mismatching positions/bases)
  • AS: 联配得分(Alignment score)
  • BC: 条码序列(barcode sequence)
  • XS: 次优联配得分(suboptimal alignment score)

能用于处理SAM格式的工具们

后续演示所用数据通过如下方法获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# efetch下载参考基因组
mkdir -p ~/biostar/refs/ebola
cd ~/biostar
efetch -db=nuccore -format=fasta -id=AF086833 > ~/refs/ebola/1976.fa
REF=~/biostar/refs/ebola/1976.fa
# 构建索引
bwa index $REF
bowtie2-build $REF $REF
# 获取10000行的fastq PE数据
mkdir -p ~/biostar/fastq
cd ~/biostar/fastq
fastq-dump -X 10000 --split-files SRR1972739
R1=~/biostar/fastq/SRR1972739_1.fastq
R2=~/biostar/fastq/SRR1972739_2.fastq

处理SAM的命令行工具有samtools,bamtools,picard,sambamba,samblaster等,其中samtoolsbamtoolspicard比较全能,功能中存在重叠,更多是互补,而sambambasamblaster则是运行速度更快,功能不太全。

使用SAMtools创建SAM,BAM和CRAM

SAM格式是目前用来存放大量核酸比对结果信息的通用格式,也是人类能够“直接”阅读的格式类型,而BAM和CRAM是为了方便传输,降低存储压力将SAM进行压缩得到的格式形式。 为了高效处理SAM文件,李恒写了配套的SAMtools, 文章在2009年发表在bioinformatics上,由于samtools的版本经常更新,如果有些工具用不了,你或许要更新版本了。

如果不加任何其他参数,比对软件就能得到“标准”的SAM格式的文件。

1
2
bwa mem $REF $R1 $R2 > bwa.sam
bowtie2 -x $REF -1 $R1 -2 $R2 > bowtie.sam

原始SAM格式体积又大,没有排序,不利于后续的分析操作,所以需要经过几步的格式转换成为BAM。1.3版本之后的samtools可以一步进行格式转换和排序.

,BAM格式必须要建立索引才能快速读取指定位置的信息。

1
2
3
4
5
6
7
# 1.3版本前
samtools view -bS bwa.sam > bwa.bam
samtools sort bwa.bam > bwa_sorted.bam
samtools index bwa_sorted.bam
# 1.3版本后
samtools sort bwa.sam > bwa_sorted.bam
samtools index bwa_sorted.bam

CRAM是比BAM压缩更加高压的格式,原因是它是基于一个参考序列,这样子就能去掉很多冗余的内容。

1
2
samtools sort --reference $REF -O cram bwa.sam > bwa.cram
samtools index bwa.cram

这一小节学习了两个samtools子命令:sortindex,前者能一边排序一边进行格式转换,后者则是对BAM进行索引。

使用SAMtool查看/过滤/转换SAM/BAM/CRAM文件

上一节得到的SAM/BAM/CRAM文件都可以用samtools的view进行更加复杂的操作,只不过要注意读取CRAM格式需要提供参考序列,不然打不开。

1
2
samtools view bwa_sorted.bam
samtools view -T $REF bwa.cram

samtools的view在增加额外参数后能实现更多的操作,比如说SAM和BAM/CRAM之间的格式转换(-b, -c, -T),过滤或提取出目标联配(-t,-L ,-r,-R,-q,-l,-m,-f,-F,-G), 举几个例子说明

1
2
3
4
5
6
# 保留mapping quality 大于 10的结果
samtools view -q 10 bwa_sorted.bam -b -o bwa_sorted_mq10.bam
# 统计结果中恰当配对的结果(0x3 3 PARIED,PROPER_PAIR)
samtools view -c -f 3 bwa_sorted.bam
# 或反向选择
samtools view -c -F 3 bwa_sorted.bam

使用PrettySam更好的可视化SAM文件

尽管我上面说SAM是适合人类阅读的数据,但是直接读SAM还是挺费脑子的。GitHub上有一个PrettySam能够更好的展示SAM/BAM文件,虽然感觉没多大实际效果,但是有利于我们方便了解SAM格式,项目地址为http://lindenb.github.io/jvarkit/PrettySam.html.

他的安装比较麻烦,需要JDK版本为1.8且是Oracle, 以及GNU Make >=3.81, curl/wget, git 和 xslproc.安装如下

1
2
3
4
git clone "https://github.com/lindenb/jvarkit.git"
cd jvarkit
make prettysam
cp dist/prettysam.jar ~/usr/jars/

使用起来非常简单,效果也比较酷炫,比较适合演示用。

1
java -jar usr/jars/prettysam.jar ~/biostar/ebola.sam --colors

PrettySam

为SAM/BAM添加Read Groups

使用GATK分析BAM文件时需要BAM文件的header里有RG部分,@RG至少由三个记录(ID,LB,SM)组成,需要根据实际情况增加。RG可以在前期比对时添加RG部分,也可以在后续处理时增加

1
2
3
4
5
6
TAG='@RG\tID:xzg\tSM:Ebola\tLB:patient_100'
# Add the tags during alignment
bwa mem -R $TAG $REF $R1 $R2 | samtools sort > bwa.bam
samtools index bwa.bam
# Add tags with samtools addreplacerg
samtools addreplacerg -r $TAG bwa_sorted.bam -o bwa_sorted_with_rg.bam

参考资料

使用Snakemake搭建分析流程

目前已有的框架

A review of bioinformatics pipeline framework 的作者对已有的工具进行很好的分类

工具推荐

作者的看法:

  1. implicit,也就是Make rule语法更适合用于整合不同执行工具
  2. 基于配置的流程更加稳定,也比较适合用于集群分配任务。

最后作者建议是:

  • 如果实验室既不是纯粹的生物学试验(不需要workbench这种UI界面),也不需要高性能基于类的流程设计, 不太好选, 主要原则是投入和产出比
  • 如果实验室进行的是重复性的研究,那么就需要对数据和软件进行版本控制, 建议是 configuration-based pipelines
  • 如果实验室做的是探索性的概念证明类工作(exploratory proofs-of-concept),那么需要的是 DSL-based pipeline。
  • 如果实验室用不到高性能计算机(HPC),只能用云服务器,就是server-based frameworks.

目前已有的流程可以在awesome-pipeline 进行查找。

就目前来看,pipeline frameworks & library 这部分的框架中 nextflow 是点赞数最多的生物学相关框架。只可惜nextflow在运行时需要创建fifo,而在NTFS文件系统上无法创建,所以我选择 snakemake , 一个基于Python写的DSL流程框架。

环境准备

为了能够顺利完成这部分的教程,请准备一个Linux环境,如果使用Windows,则按照biostarhandbook(一)分析环境和数据可重复 部署一个虚拟机,并安装miniconda3。

如下步骤会下载所需数据,并安装所需要的软件,并且启动工作环境。

1
2
3
4
5
6
7
wget https://bitbucket.org/snakemake/snakemake-tutorial/get/v3.11.0.tar.bz2
tar -xf v3.11.0.tar.bz2 --strip 1
cd snakemake-snakemake-tutorial-623791d7ec6d
conda env create --name snakemake-tutorial --file environment.yaml
source activate snakemake-tutorial
# 退出当前环境
source deactivate

当前环境下的所有文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
├── data
│   ├── genome.fa
│   ├── genome.fa.amb
│   ├── genome.fa.ann
│   ├── genome.fa.bwt
│   ├── genome.fa.fai
│   ├── genome.fa.pac
│   ├── genome.fa.sa
│   └── samples
│   ├── A.fastq
│   ├── B.fastq
│   └── C.fastq
├── environment.yaml
└── README.md

基础:一个案例流程

如果你编译过软件,那你应该见过和用过make, 但是你估计也没有仔细想过make是干嘛用的。Make是最常用的软件构建工具,诞生于1977年,主要用于C语言的项目,是为了处理编译时存在各种依赖关系,尤其是部分文件更新后,Make能够重新生成需要更新的文件以及其对应的文件。

Snakemake和Make功能一致,只不过用Python实现,增加了许多Python的特性,并且和Python一样非常容易阅读。下面将使用Snakemake写一个变异检测流程。

第一步:序列比对

Snakemake非常简单,就是写各种rule来完成不同的任务。我们第一条rule就是将序列比对到参考基因组上。如果在命令行下就是bwa mem data/genome.fa data/samples/A.fastq | samtools view -Sb - > mapped_reads/A.bam。 但是按照Snakemake的规则就是下面的写法。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 用你擅长的文本编辑器
vim Snakefile
# 编辑如下内容
rule bwa_map:
input:
"data/genome.fa",
"data/samples/A.fastq"
output:
"mapped_reads/A.bam"
shell:
"""
bwa mem {input} | samtools view -Sb - > {output}
"""

解释一下:这几行定义了一个规则(rule),在这个规则下,输入(input)有两个,而输出(output)只有一个,在shell中运行命令,只不过里面的文件都用{}形式替代。伪执行一下:snakemake -np mapped_reads/A.bam检查一下是否会出错,真实运行情况如下(不带规则,默认执行第一个规则):

run snakemake

第二步:推广序列比对规则

如果仅仅是上面这样子处理一个文件,还无法体现snakemake的用途,毕竟还不如手动敲代码来的方便。snakemake的一个有点在于它能够使用文件名通配的方式对一类文件进行处理。将上面的A改成{sample},就可以将符合*.fastq的文件处理成*.bam.

1
2
3
4
5
6
7
8
9
10
rule bwa_map:
input:
"data/genome.fa",
"data/samples/{sample}.fastq"
output:
"mapped_reads/{sample}.bam"
shell:
"""
bwa mem {input} | samtools view -Sb - > {output}
"""

那么,用snakemake -np mapped_reads/{A,B,C}.bam,就会发现,他非常机智的就比对了B.fastqC.fastq而不会再比对一遍A.fastq, 也不需要你写一堆的判断语句去手动处理。

规则统配

当然,如果你用touch data/samples/A.fastq改变A.fastq的时间戳,他就会认位A.fastq文件发生了改变,那么重复之前的命令就会比对A.fastq。

第三步:比对后排序

比对后的文件还需要进一步的排序,才能用于后续分析,那么规则该如何写呢?

1
2
3
4
5
6
7
8
rule samtools_sort:
input:
"mapped_reads/{sample}.bam"
output:
"sorted_reads/{sample}.bam"
shell:
"samtools sort -T sorted_reads/{wildcards.sample}"
" -O bam {input} > {output}"

以之前的输出作为输出文件名,输出到另一个文件夹中。和之前的规则基本相同,只不过这里用到了wildcards.sample来获取通配名用作-T的临时文件的前缀sample实际名字。

运行snakemake -np sorted_reads/B.bam,你就会发现他就会非常智能的先比对再排序。这是因为snakemake会自动解决依赖关系,并且按照依赖的前后顺序进行执行。

第四步: 建立索引和对任务可视化

这里我们再写一个规则,对之前的排序后的BAM文件建立索引。

1
2
3
4
5
6
7
rule samtools_index:
input:
"sorted_reads/{sample}.bam"
output:
"sorted_reads/{sample}.bam.bai"
shell:
"samtools index {input}"

目前已经写了三个规则,那么这些规则的执行和依赖关系如何呢? snakemake提供了--dag选项用于dot命令进行可视化

1
snakemake --dag sorted_reads/{A,B}.bam.bai | dot -Tsvg > dag.svg

运行流程

第五步:基因组变异识别

基因组变异识别需要整合之前所有的BAM文件,你可能会打算这样写

1
2
3
4
5
6
7
8
9
10
11
12
rule bcftools_call:
input:
fa="data/genome.fa",
bamA="sorted_reads/A.bam"
bamB="sorted_reads/B.bam"
baiA="sorted_reads/A.bam.bai"
baiB="sorted_reads/B.bam.bai"
output:
"calls/all.vcf"
shell:
"samtools mpileup -g -f {input.fa} {input.bamA} {input.bamB} | "
"bcftools call -mv - > {output}"

这样写的却没有问题,但是以后每多一个样本就需要多写一个输入,太麻烦了。这里就体现出Snakemake和Python所带来的特性了,我们可以用列表推导式的方法搞定。

1
["sorted_reads/{}.bam".format(sample) for sample in ["A","B"]]

进一步,可以在规则外定义SAMPLES=["A","B"],则规则内的输入可以写成bam=["sorted_reads/{}.bam".format(sample) for sample in SAMPLES]. 由于列表推导式比较常用,但是写起来有点麻烦,snakemake定义了expand进行简化, 上面可以继续改写成expand("sorted_reads/{sample}.bam", sample=SAMPLES)

那么最后的规则就是

1
2
3
4
5
6
7
8
9
10
11
SAMPLES=["A","B"]
rule bcftools_call:
input:
fa="data/genome.fa",
bam=expand("sorted_reads/{sample}.bam", sample=SAMPLES),
bai=expand("sorted_reads/{sample}.bam.bai", sample=SAMPLES)
output:
"calls/all.vcf"
shell:
"samtools mpileup -g -f {input.fa} {input.bam} | "
"bcftools call -mv - > {output}"

小练习: 请用snakemake生成当前的DAG图。

第六步:编写报告

上面都是在规则里执行shell脚本,snakemake的一个优点就是可以在规则里面写Python脚本,只需要把shell改成run,此外还不需要用到引号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
rule report:
input:
"calls/all.vcf"
output:
"report.html"
run:
from snakemake.utils import report
with open(input[0]) as vcf:
n_calls = sum(1 for l in vcf if not l.startswith("#"))

report("""
An example variant calling workflow
===================================

Reads were mapped to the Yeast
reference genome and variants were called jointly with
SAMtools/BCFtools.

This resulted in {n_calls} variants (see Table T1_).
""", output[0], T1=input[0])

这里还用到了snakemake的一个函数,report,可以对markdown语法进行渲染生成网页。

第七步:增加目标规则

之前运行snakemake都是用的snakemake 目标文件名, 除了目标文件名外,snakemake还支持规则名作为目标。通常我们按照习惯定义一个all规则,来生成结果文件。

1
2
3
rule all:
input:
"report.html

基础部分小结:

总结下学习过程,知识点如下:

  • Snakemake基于规则执行命令,规则一般由input, output,shell三部分组成。
  • Snakemake可以自动确定不同规则的输入输出的依赖关系,根据时间戳来判断文件是否需要重新生成
  • Snakemake以{sample}.fa形式进行文件名通配,用{wildcards.sample}获取sample的实际文件名
  • Snakemake用expand()生成多个文件名,本质是Python的列表推导式
  • Snakemake可以在规则外直接写Python代码,在规则内的run里也可以写Python代码。
  • Snakefile的第一个规则通常是rule all,因为默snakemake默认执行第一条规则

进阶:对流程进一步修饰

在基础部分中,我们完成了流程的框架,下一步则是对这个框架进行不断完善,比如说编写配置文件,声明不同rule的消耗资源,记录运行日志等。

第一步: 声明所需进程数

对于一些工具,比如说bwa,多进程或者多线程运行能够大大加速计算。snakemake使用threads来定义当前规则所用的进程数,我们可以对之前的bwa_map增加该指令。

1
2
3
4
5
6
7
8
9
rule bwa_map:
input:
"data/genome.fa",
"data/samples/{sample}.fastq"
output:
"mapped_reads/{sample}.bam"
threads:8
shell:
"bwa mem -t {threads} {input} | samtools view -Sb - > {output}"

声明threads后,Snakemake任务调度器就会在程序运行的时候是否并行多个任务。这主要和参数中的--cores相关。比如说

1
snakemake --cores 10

由于总体上就分配了10个核心,于是一次就只能运行一个需要消耗8个核心的bwa_map。但是当其中一个bwa_map运行完毕,这个时候snakemaek就会同时运行一个消耗8个核心的bwa_map和没有设置核心数的samtools_sort,来保证效率最大化。因此对于需要多线程或多进程运行的程序而言,将所需的进程单独编码,而不是硬编码到shell命令中,能够更有效的使用资源。

第二步:配置文件

之前的SAMPLES写在了snakefile,也就是意味这对于不同的项目,需要对snakefile进行修改,更好的方式是用一个配置文件。配置文件可以用JSON或YAML语法进行写,然后用configfile: "config.yaml"读取成字典,变量名为config。

config.yaml内容为:

1
2
3
samples:
A: data/samples/A.fastq
B: data/samples/B.fastq

YAML使用缩进表示层级关系,其中缩进必须用空格,但是空格数目不重要,重要的是所今后左侧对齐。上面的YAML被Pytho读取之后,以字典保存,形式为{'samples': {'A': 'data/samples/A.fastq', 'B': 'data/samples/B.fastq'}}

而snakefile也可以改写成

1
2
3
4
5
6
7
8
9
10
11
12
configfile: "config.yaml"
...
rule bcftools_call:
input:
fa="data/genome.fa",
bam=expand("sorted_reads/{sample}.bam", sample=config["samples"]),
bai=expand("sorted_reads/{sample}.bam.bai", sample=config["smaples])
output:
"calls/all.vcf"
shell:
"samtools mpileup -g -f {input.fa} {input.bam} | "
"bcftools call -mv - > {output}"

虽然sample是一个字典,但是展开的时候,只会使用他们的key值部分。

关于YAML格式的教程,见阮一峰的博客:http://www.ruanyifeng.com/blog/2016/07/yaml.html

第三步:输入函数

既然已经把文件路径都存入到配置文件中,那么可以进一步的改写之前的bwa_map里的输入部分。也就是从字典里面提取到存放的路径。最开始我就是打算这样写

1
2
3
4
5
6
7
8
9
rule bwa_map:
input:
"data/genome.fa",
config['samples']["{sample}"]
output:
"mapped_reads/{sample}.bam"
threads:8
shell:
"bwa mem -t {threads} {input} | samtools view -Sb - > {output}"

毕竟”{sample}”从理论上应该得到sample的名字。但是snakemake -np显示出现错误

1
2
KeyError in line 11 of /home6/zgxu/snakemake-snakemake-tutorial-623791d7ec6d/Snakefile:
'{sample}'

这可能是{sample}的形式只能在匹配的时候使用,而在获取值的时候应该用基础第三步的wildcards.sample形式。于是继续改成config["samples"][wildcards.sample]。然而还是出现了错误。

1
name 'wildcards' is not defined

为了理解错误的原因,并找到解决方法,我们需要理解Snakemake工作流程执行的一些原理,它执行分为三个阶段

  • 初始化阶段,工作流程会被解析,所有规则都会被实例化
  • DAG阶段,也就是生成有向无环图,确定依赖关系的时候,所有的通配名部分都会被真正的文件名代替。
  • 调度阶段,DAG的任务按照顺序执行

也就是说在初始化阶段,我们是无法获知通配符所指代的具体文件名,必须要等到第二阶段,才会有wildcards变量出现。也就是说之前的出错的原因都是因为第一个阶段没通过。这个时候就需要输入函数推迟文件名的确定,可以用Python的匿名函数,也可以是普通的函数

1
2
3
4
5
6
7
8
9
rule bwa_map:
input:
"data/genome.fa",
lambda wildcards: config["samples"][wildcards.sample]
output:
"mapped_reads/{sample}.bam"
threads: 8
shell:
"bwa mem -t {threads} {input} | samtools view -Sb - > {output}"

第四步:规则参数

有些时候,shell命令不仅仅是由input和output中的文件组成,还需要一些静态的参数设置。如果把这些参数放在input里,则会因为找不到文件而出错,所以需要专门的params用来设置这些参数。

1
2
3
4
5
6
7
8
9
10
11
rule bwa_map:
input:
"data/genome.fa",
lambda wildcards: config["samples"][wildcards.sample]
output:
"mapped_reads/{sample}.bam"
threads: 8
params:
rg="@RG\tID:{sample}\tSM:{sample}"
shell:
"bwa mem -R '{params.rg}' '-t {threads} {input} | samtools view -Sb - > {output}"

写在rule中的params的参数,可以在shell命令中或者是run里面的代码进行调用。

第五步: 日志文件

当工作流程特别的大,每一步的输出日志都建议保存下来,而不是输出到屏幕,这样子出错的时候才能找到出错的所在。snakemake非常贴心的定义了log,用于记录日志。好处就在于出错的时候,在log里面定义的文件是不会被snakemake删掉,而output里面的文件则是会被删除。继续修改之前的bwa_map.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
rule bwa_map:
input:
"data/genome.fa",
lambda wildcards: config["samples"][wildcards.sample]
output:
"mapped_reads/{sample}.bam"
params:
rg="@RG\tID:{sample}\tSM:{sample}"
log:
"logs/bwa_mem/{sample}.log"
threads: 8
shell:
"(bwa mem -R '{params.rg}' -t {threads} {input} | "
"samtools view -Sb - > {output}) 2> {log}"

这里将标准错误重定向到了log中。

第六步:临时文件和受保护的文件

由于高通量测序的数据量通常很大,因此很多无用的中间文件会占据大量的磁盘空间。而特异在执行结束后写一个shell命令清除不但写起来麻烦,而且也不好管理。Snakemake使用temp()来将一些文件标记成临时文件,在执行结束后自动删除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
rule bwa_map:
input:
"data/genome.fa",
lambda wildcards: config["samples"][wildcards.sample]
output:
temp("mapped_reads/{sample}.bam")
params:
rg="@RG\tID:{sample}\tSM:{sample}"
log:
"logs/bwa_mem/{sample}.log"
threads: 8
shell:
"(bwa mem -R '{params.rg}' -t {threads} {input} | "
"samtools view -Sb - > {output}) 2> {log}"

修改之后的代码,当samtools_sort运行结束后就会把”mapped_reads”下的BAM删掉。同时由于比对和排序都比较耗时,得到的结果要是不小心被误删就会浪费大量计算时间,最后的方法就是用protected()保护起来

1
2
3
4
5
6
7
8
rule samtools_sort:
input:
"mapped_reads/{sample}.bam"
output:
protected("sorted_reads/{sample}.bam")
shell:
"samtools sort -T sorted_reads/{wildcards.sample} "
"-O bam {input} > {output}"

最后,snakemake就会在文件系统中对该输出文件写保护,也就是最后的权限为-r--r--r--, 在删除的时候会问你rm: remove write-protected regular file ‘A.bam’?.

进阶部分小结

  • 使用threads:定义不同规则所需线程数,有利于snakemake全局分配任务,最优化任务并行
  • 使用configfile:读取配置文件,将配置和流程分离
  • snakemake在DAG阶段才会知道通配的具体文件名,因此在input和output出现的wildcards就需要推迟到第二步。
  • log里定义的日志文件,不会因任务失败而被删除
  • params定义的参数,可以在shell和run中直接调用
  • temp()中的文件运行结束后会被删除,而protected()中的文件会有写保护,避免意外删除。

高级:实现流程的自动部署

上面的分析流程都是基于当前环境下已经安装好要调用的软件,如果你希望在新的环境中也能快速部署你的分析流程,那么你需要用到snakmake更高级的特性,也就是为每个rule定义专门的运行环境。

全局环境

我建议你在新建一个snakemake项目时,都先用conda create -n 项目名 python=版本号创建一个全局环境,用于安装一些常用的软件,例如bwa、samtools、seqkit等。然后用如下命令将环境导出成yaml文件

1
conda env export -n 项目名 -f environment.yaml

那么当你到了一个新的环境,你就可以用下面这个命令重建出你的运行环境

1
conda env create -f environment.yaml

局部环境

当然仅仅依赖于全局环境或许还不够,对于不同的规则(rule)可能还有Python2和Python3的区别,所以你还得为每个规则创建环境。

snakemake有一个参数--use-conda,会解析rule中的conda规则,根据其提供的yaml文件安装特定版本的工具,以基础第一步的序列比对为例,

1
2
3
4
5
6
7
8
9
10
11
12
13
rule bwa_map:
input:
"data/genome.fa",
"data/samples/A.fastq"
output:
"mapped_reads/A.bam"
conda:
"envs/map.yaml"
shell:
"""
mkdir -p mapped_reads
bwa mem {input} | samtools view -Sb - > {output}
"""

随后在snakemake执行的目录下创建envs文件夹,增加map.yaml, 内容如下

1
2
3
4
5
6
7
8
9
10
11
name: map
channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
- defaults
dependencies:
- bwa=0.7.17
- samtools=1.9
show_channel_urls: true

注意: YAML文件的name行不是必要的,但是建议加上。

那么当你用snakmake --use-conda执行时,他就会在.snakemake/conda下创建专门的conda环境用于处理当前规则。对于当前项目,该conda环境创建之后就会一直用于该规则,除非yaml文件发生改变。

如果你希望在实际运行项目之前先创建好环境,那么可以使用--create-envs-only参数。

由于默认情况下,每个项目运行时只会在当前的.snakemake/conda查找环境或者安装环境,所以在其他目录执行项目时,snakemake又会重新创建conda环境,如果你担心太占地方或者环境太大,安装的时候太废时间,你可以用--conda-prefix指定专门的文件夹。

一定要使用最新的snakemake和最新的conda。因为conda在启动环境的命令发生过变化,从source activate改成了conda activate

代码总结

最后的代码如下

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
configfile: "config.yaml"


rule all:
input:
"report.html"


rule bwa_map:
input:
"data/genome.fa",
lambda wildcards: config["samples"][wildcards.sample]
output:
temp("mapped_reads/{sample}.bam")
params:
rg="@RG\tID:{sample}\tSM:{sample}"
log:
"logs/bwa_mem/{sample}.log"
threads: 8
shell:
"(bwa mem -R '{params.rg}' -t {threads} {input} | "
"samtools view -Sb - > {output}) 2> {log}"


rule samtools_sort:
input:
"mapped_reads/{sample}.bam"
output:
protected("sorted_reads/{sample}.bam")
shell:
"samtools sort -T sorted_reads/{wildcards.sample} "
"-O bam {input} > {output}"


rule samtools_index:
input:
"sorted_reads/{sample}.bam"
output:
"sorted_reads/{sample}.bam.bai"
shell:
"samtools index {input}"


rule bcftools_call:
input:
fa="data/genome.fa",
bam=expand("sorted_reads/{sample}.bam", sample=config["samples"]),
bai=expand("sorted_reads/{sample}.bam.bai", sample=config["samples"])
output:
"calls/all.vcf"
shell:
"samtools mpileup -g -f {input.fa} {input.bam} | "
"bcftools call -mv - > {output}"


rule report:
input:
"calls/all.vcf"
output:
"report.html"
run:
from snakemake.utils import report
with open(input[0]) as vcf:
n_calls = sum(1 for l in vcf if not l.startswith("#"))

report("""
An example variant calling workflow
===================================

Reads were mapped to the Yeast
reference genome and variants were called jointly with
SAMtools/BCFtools.

This resulted in {n_calls} variants (see Table T1_).
""", output[0], T1=input[0])

执行snakemake

写完Snakefile之后就需要用snakemake执行。snakemake的选项非常多,这里列出一些比较常用的运行方式。

运行前检查潜在错误:

1
2
3
4
5
6
snakemake -n
snakemake -np
snakemake -nr
# --dryrun/-n: 不真正执行
# --printshellcmds/-p: 输出要执行的shell命令
# --reason/-r: 输出每条rule执行的原因

直接运行:

1
2
3
4
snakemake
snakemake -s Snakefile -j 4
# -s/--snakefile 指定Snakefile,否则是当前目录下的Snakefile
# --cores/--jobs/-j N: 指定并行数,如果不指定N,则使用当前最大可用的核心数

强制重新运行:

1
2
3
4
5
6
snakemake -f
# --forece/-f: 强制执行选定的目标,或是第一个规则,无论是否已经完成
snakemake -F
# --forceall/-F: 也是强制执行,同时该规则所依赖的规则都要重新执行
snakemake -R some_rule
# --forecerun/-R TARGET: 重新执行给定的规则或生成文件。当你修改规则的时候,使用该命令

可视化:

1
2
3
4
5
snakemake --dag  | dot -Tsvg > dag.svg
snakemake --dag | dit -Tpdf > dag.pdf
# --dag: 生成依赖的有向图
snakemake --gui 0.0.0.0:2468
# --gui: 通过网页查看运行状态

集群执行:

1
2
3
4
5
snakemake --cluster "qsub -V -cwd -q 投递队列" -j 10
# --cluster /-c CMD: 集群运行指令
## qusb -V -cwd -q, 表示输出当前环境变量(-V),在当前目录下运行(-cwd), 投递到指定的队列(-q), 如果不指定则使用任何可用队列
# --local-cores N: 在每个集群中最多并行N核
# --cluster-config/-u FILE: 集群配置文件

参考资料

LTR_retriever:一个更加准的LTR整合分析工具

背景篇

在植物基因组中,I类转座因子,LTR-RT(LTR retrotransposons)是基因组扩张的主要原因。完整的LTR长度在855000 bp之间,下图图A表示的是一个完整的LTR-RT,灰色框表示TSD(target site duplications), 红色三角形表示LTR motif(长度在2bp左右), 蓝色框表示LTR。LTR中间序列长度在1,00015,000之间波动。

LTR-RT结构

完整的LTR-RT主要归为两大类: Gypsy和Copia。如果LTR中间的序列不包含开放阅读框(ORF), 那么所属的LTR-RT就无法独立的转座。

安装篇

LTR_retriever不是一个独立的工具,他的主要作用就是整合 LTRharvest, LTR_FINDER, MGEScan 3.0.0, LTR_STRUC, 和 LtrDetector的结果,过滤其中的假阳性LTR-RT,得到高质量的LTR-RT库。

LTR_retriever托管在GitHub, https://github.com/oushujun/LTR_retriever, 下载LTR_retriever本体

1
git clone https://github.com/oushujun/LTR_retriever.git

之后修改LTR_retriever下的paths, 提供BLAST+, RepeatMasker, HMMER, CDHIT这些工具的路径。

1
2
3
4
5
BLAST+=/your_path_to/BLAST+2.2.30/bin/
RepeatMasker=/your_path_to/RepeatMasker4.0.0/
HMMER=/your_path_to/HMMER3.1b2/bin/
CDHIT=/your_path_to/CDHIT4.6.1/
BLAST=/your_path_to/BLAST2.2.26/bin/ #not required if CDHIT provided

更加方便的安装方法用Bioconda安装好cd-hit repeatmasker, 然后下载LTR_retriever:

1
2
3
4
5
6
7
conda create -n LTR_retriever
source activate LTR_retriever
conda install -c conda-forge perl perl-text-soundex
conda install -c bioconda cd-hit
conda install -c bioconda/label/cf201901 repeatmasker
git clone https://github.com/oushujun/LTR_retriever.git
./LTR_retriever/LTR_retriever -h

此外你还需要额外安装LTRharvest, LTR_FINDERMGEScan_LTR

由于MGEScan_LTR装起来比我想象中麻烦,所以本文就仅使用LTRharverst和LTR_FINDER

使用篇

尽管LTR_retriever支持多个LTR工具的输入,但其实上LTRharverst和LTR_FINDER的结果就已经很不错了。

以拟南芥的基因组序列为例,分别使用LTRharverst和LTR_FINDER来寻找拟南芥中潜在LTR序列,之后用LTR_retreiver来合并结果。

1
2
3
4
5
6
7
8
9
10
11
12
#LTRharvest
gt suffixerator \
-db TAIR10.fa \
-indexname TAIR10 \
-tis -suf -lcp -des -ssp -sds -dna
gt ltrharvest \
-index TAIR10 \
-similar 90 -vic 10 -seed 20 -seqids yes \
-minlenltr 100 -maxlenltr 7000 -mintsd 4 -maxtsd 6 \
-motif TGCA -motifmis 1 > TAIR10.harvest.scn &
# LTR_FINDER
ltr_finder -D 15000 -d 1000 -L 7000 -l 100 -p 20 -C -M 0.9 TAIR10.fa > TAIR10.finder.scn &

LTR_retriever支持单个候选的LTR,

1
LTR_retriever -genome TAIR10.fa -inharvest TAIR10.harvest.scn

也支持多个候选LTR输入

1
LTR_retriever -genome TAIR10.fa -inharvest TAIR10.harvest.scn -infinder TAIR10.finder.scn -threads 20

输出文件如下

运行结果

其他测试

LAI值是作者提出用于衡量基因组完整度参数。比较2个LTR输入和1个LTR输入的LAI值,后者是15.62,前者是14.47,这也意味这个值其实是受到输入的候选LTR数目影响,但最终结果应该稳定在一个阈值内。

我测试了多个物种在两种软件下找到的LTR,以及最终pass留下的LTR, 发现最终能够pass,数量都相对较少。同时限速步骤就是LTR_finder 和 LTRharvest。

物种 基因组大小 LTR_finder LTRharvest Pass LAI 测序技术
A. lyrata 206M 1456 1017 1044 20.39 Sanger
A. thaliana (TAIR10) 120 M 207 550 184 15.62 Sanger
B. rapa (2.5) 391M 1251 3182 520 0 PacBio + 二代20Kb 40Kb文库
B. rapa (3.0) 353 M 3515 3635 1968 7.16 PacBio + BioNano + Hi-C
C.rubella 135 M 643 600 144 10.96 454 + Sanger
A. alpina 336 M 3840 3107 2556 11.01 PacBio + BioNano + Hi-C
某物种A 454 M 5384 2789 4294 17.89 PacBio

还有一个有趣的现象,B. rapa 3.0版本尽管是最近用三代加Hi-C组装的基因,但是以LAI的标准,只能算是Draft级别, 当然也比2.5版本好出不少。

当然作者也对很多物种的多个版本组装进行了比较,下图来自于 Assessing genome assembly quality using the LTR Assembly Index (LAI)

基因组评估

如果使用该软件记得引用下面两篇文献

  • LTR_retriever: A Highly Accurate and Sensitive Program for Identification of Long Terminal Repeat Retrotransposons
  • Assessing genome assembly quality using the LTR Assembly Index (LAI)

HiC-Pro:Hi-C数据预处理高效工具

HiC-Pro是一个高效率的Hi-C数据预处理工具,能够应用于dilution Hi-C, in situ Hi-C, DNase Hi-C, Micro-C, capture-C, capture Hi-C 和 HiChip 这些数据。

HiC-Pro的工作流程如下, 简单的说就是先双端测序各自比对,然后进行合并,根据合并的结果筛选有效配对。之后有效配对用于构建contact maps.

工作流程

安装方法

HiC-Pro依赖于如下的软件

  • Bowtie2(>2.2.2), 用于序列比对
  • Python2.7, 并安装 Pysam, bx-python, numpy, scipy
  • R, RColorBrewer + ggplot2
  • samtools > 1.1
  • GNU sort, 支持 -V, 按照version进行排序

如果有root权限,更加推荐使用Singularity,比Conda更简单。

1
2
3
4
# 下载
wget https://zerkalo.curie.fr/partage/HiC-Pro/singularity_images/hicpro_latest_ubuntu.img
# 使用
singularity exec /opt/biosoft/HiC-Pro/hicpro_latest_ubuntu.img HiC-Pro -h

没有Root的安装方法: 为了保证环境的干净,我用conda进行了一个环境进行安装

1
2
conda create -y -n hic-pro python=2.7 pysam bx-python numpy scipy samtools bowtie2
conda activate hic-pro

以2.11.1版本为例进行介绍,最新的版本在https://github.com/nservant/HiC-Pro/releases检查

1
2
3
wget https://github.com/nservant/HiC-Pro/archive/v2.11.1.tar.gz
tar -zxvf v2.11.1.tar.gz
cd HiC-Pro-2.11.1

因为我希望把HiC-Pro安装到~/opt/bisofot下,所以我需要修改当前目录下的config-install.txt中的PREFIX部分,

1
PREFIX =  /home/xzg/opt/bisofot

如果服务器支持任务投递,可以修改CLUSTER_SYS部分, 设置为TORQUE, SGE, SLURM 或 LSF,

我的miniconda的安装目录是~/miniconda3, 所以hic-pro环境的实际路径是~/miniconda3/envs/hic-pro

1
2
make configure
make install

安装结束之后,/home/xzg/opt/bisofot文件夹下就出现了HiC-Pro_2.11.1,之后的软件调用方式为

1
~/opt/biosfot/HiC-Pro_2.11.1/bin/HiC-Pro -h

如果没有出现Error 就说明安装成功了。

处理流程

让我们新建一个项目文件夹,以一个测试数据集为例进行介绍。

下载测试数据并解压缩,该数据来自于Dixon et al. 2012 , 使用HindIII 进行酶切

1
2
mkdir -p hic-pro && cd hic-pro
wget https://zerkalo.curie.fr/partage/HiC-Pro/HiCPro_testdata.tar.gz && tar -zxvf HiCPro_testdata.tar.gz

之后将测序结果移动或者软连接到fastq文件夹下

1
2
3
4
mkdir -p fastq
mv test_data/* fastq
ls fastq
# dixon_2M dixon_2M_2

创建注释文件

为了处理原始数据,HiC-Pro需要三个注释文件

  • BED文件,记录可能的酶切位点
  • table文件,记录每条contig/scaffold/chromosome的长度
  • bowtie2索引

其中BED文件和table文件必须要放在HiC-Pro_2.11.1/annotations目录下,该文件夹下已经有了人类hg19和小鼠mm10。 我们以GRCh38为例, 介绍如何创建这三个注释信息

1
2
3
4
5
6
7
8
9
10
11
# 切换目录
cd ~/opt/biosfot/HiC-Pro_2.11.1/annotation
# 下载GRCh38的序列
wget ftp://ftp.ensembl.org/pub/release-97/fasta/homo_sapiens/dna/Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz
gunzip Homo_sapiens.GRCh38.dna.primary_assembly.fa.gz
# BED
~/opt/biosoft/HiC-Pro_2.11.1/bin/utils/digest_genome.py -r HindIII -o GRCh38_HindIII.bed Homo_sapiens.GRCh38.dna.primary_assembly.fa
# chromosome size
seqkit fx2tab -nl Homo_sapiens.GRCh38.dna.primary_assembly.fa | awk '{print $1"\t"$2}' > GRCh38.chrom.size
# bowtie2 index
bowtie2-build --threads 20 Homo_sapiens.GRCh38.dna.primary_assembly.fa GRCh38

配置HiC-Pro

拷贝HiC-Pro的配置文件到项目文件夹下

1
cp ~/opt/biosfot/HiC-Pro_2.11.1/config-hicpro.txt .

修改配置文件config-hicpro.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
# 线程数
N_CPU = 80
# bowtie2索引, 绝对路径
BOWTIE2_IDX_PATH = /home/xzg/opt/biosfot/HiC-Pro_2.11.1/annotation
# bowtie2索引时的前缀
REFERENCE_GENOME = GRCh38
# 参考基因组各染色体长度
# 绝对路径
GENOME_SIZE = /home/xzg/opt/biosfot/HiC-Pro_2.11.1/annotationGRCh38.chrom.size
# 酶切位点
# 绝对路径
GENOME_FRAGMENT = /home/xzg/opt/biosfot/HiC-Pro_2.11.1/annotationGRCh38_HindIII.bed
LIGATION_SITE = AAGCTAGCTT

对于LIGATION_SITE,不同酶切位点对应的序列为HindIII(AAGCTAGCTT), MboI(GATCGATC) , DpnII(GATCGATC), NcoI(CCATGCATGG)。

我们要修改的参数其实就是上面几个。当然该配置文件还有许多参数可以修改,具体见https://github.com/nservant/HiC-Pro/blob/master/doc/MANUAL.md

运行如下代码,启动分析项目

1
~/opt/biosoft/HiC-Pro_2.11.1/bin/HiC-Pro -i fastq -o results -c config-hicpro.txt

HiC-Pro会新建一个工作目录,results, 之后会遍历fastq目录,寻找其中的fastq文件,将其软连接到results下的rawdata, 之后就开始用bowtie2比对以及后续的分析。

测试数据代码运行到Run ICE Normalization就中断了,可能是用的参考基因组和原来的教程(hg19)不一样, 不过我自己的数据集是没有问题的。

最后的结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ tree -L 2 results 
results
├── bowtie_results # 比对之后的输出
│   ├── bwt2
│   ├── bwt2_global
│   └── bwt2_local
├── config-hicpro.txt
├── hic_results
│   ├── data # 有效配对
│   ├── matrix # contact maps
│   ├── pic # 可视化质控信息
│   └── stats #文字版质控信息
├── logs # 各种日志
│   ├── dixon_2M
│   └── dixon_2M_2
├── rawdata -> /home/xzg/project/Tutorial/hic-pro/fastq
└── tmp

一个关键的结果就是data文件里的以*.validPairs*结尾的文件,有7+1列,

1
read_name chr_reads1  pos_reads1  strand_reads1  chr_reads2  pos_reads2  strand_reads2  fragment_size [allele_specific_tag] 

此外,HiC-Pro提供了一个脚本用于将输出的allValidPairs转成JABT的输入

1
2
3
4
~/HiC-Pro_2.11.1/bin/utils/hicpro2juicebox.sh \
-i hic_results/data/dixon_2M/dixon_2M.allValidPairs \
-g /home/xzg/opt/biosfot/HiC-Pro_2.11.1/annotation/GRCh38.chrom.size \
-j ~/opt/biosoft/juicer/scripts/common/juicer_tools.jar

最终会输出一个以.hic结尾的文件。

参考资料

「基因组注释」使用RepeatModeler从头注释基因组的重复序列

RepeatModeler可用来从头对基因组的重复序列家族进行建模注释,它的核心组件是RECON和RepatScout。

使用方法

以拟南芥的参考基因组为例,假设基因组的名字为”Athaliana.fa”

第一步:为RepeatModeler创建索引数据库

1
2
3
BuildDatabase -name ath -engine ncbi Athaliana.fa
# -engine ncbi: 表示使用rmblast
# -name aht: 表示数据库的名字为ath

这一步其实认为调用了makeblastdb,结果文章和makeblastdb一致

第二步:运行RepeatModeler

1
2
3
4
RepeatModeler -database ath -engine ncbi -pa 10 &> ath.out &
# -database 要和上一步一致
# -engine 要和上一步一致
# -pa 表示线程数

运行中的的文件存放在RM_.xxx文件夹下

1
2
3
4
5
6
7
8
9
10
11
RM_82213.MonOct151054032018
├── consensi.fa
├── consensi.fa.classified
├── consensi.fa.masked
├── families-classified.stk
├── families.stk
├── round-1
├── round-2
├── round-3
├── round-4
└── round-5

运行结束后,就得到了ath-families.faath-families.stk。 前者是找到的重复序列,后者是Stockholm格式的种子联配文件(seed alignment file), 可以用util/dfamConsensusTool.pl上传到Dfam_consensus数据库中。

1
2
grep -i Unkown ath-families.fa
# 没有结果,全都归类,毕竟拟南芥

RM_.xxxconsensi.fa.classifiedath-families.fa内容一样,也是FASTA格式的文件,,只不过每个序列的ID会标注它来自于哪个重复序列家族,如果无法归类,则用”Unkown”标注。

你可以将ath-families.fa分ModelerID.lib和Modelerunknown.lib,

1
2
seqkit grep -nrp Unknown ath-families.fa > Modelerunknown.lib
seqkit grep -vnrp Unknown ath-families.fa > ModelerID.lib

其中Modelerunknown.lib用RepeatMasker或TEclass进一步注释,如果能够被分类则从Modelerunknown.lib,移动到ModelerID.lib

这里用TEclass进行分类,软件安装使用参考使用TEclass对TE一致性序列进行分类.

1
TEclassTest Modelerunknown.lib

这一步其实无法运行,因为没有输入。

第三步:过滤基因片段

许多文章都没有这样子做,因此这一步完全可以不用看

RepeatModeler找到的重复序列进一步在植物蛋白数据库(不包括转座子蛋白)进行搜索,如果和植物蛋白匹配,或者在序列的侧翼50bp以内,就将该重复序列剔除。这一步可用工具是ProtExcluder
ProtExcluder的安装需要HMMER3, 方法如下

首先一定要装HMMER3.0,然后安装方法为

1
2
3
4
5
6
7
8
wget http://eddylab.org/software/hmmer/hmmer-3.0.tar.gz
tar xf hmmer-3.0.tar.gz
cd hmmer-3.0
./configure --prefix=$HOME/opt/biosoft/hmmer-3.0
make && make install
cd easel
./configure --prefix=$HOME/opt/biosoft/hmmer-3.0
make && make install

后续安装的ProtExcluder1.1非常坑爹,他居然认为hmmer的运行文件是放在binaries目录下,所以你还需要去~/opt/biosoft/hmmer-3.0把bin文件夹改成binaries

然后安装ProtExcluder1.1

1
2
3
4
5
tar zxf  ProtExcluder1.1.tar.gz
mv ProtExcluder1.1 ~/opt/biosoft
cd ~/opt/biosoft/ProtExcluder1.1
./Installer.pl -m ~/opt/biosoft/hmmer-3.0 -p P ~/opt/biosoft/ProtExcluder1.1/
# 注意运行路径后一定要有"/"

然后将找到的重复序列用blastx比对到植物的蛋白数据库中,你可以到RefSeq上进行下载。

1
blastx -query ath-families.fa -db /path/to/refseq-plant/db/plant.protein -num_threads 70 > ath-families.blastx &

最后运行ProtExcluder.pl

1
/path/to/ProtExcluder.pl -f 50   ath-families.blastx  ath-families.fa 

从理论上说结果是”XXXnoProtFinal”,但这个破软件各种报错,而且报错信息信息量太少,直接放弃这个破软件了。

考虑到目前看了很多文献也没人说要过滤,所以这一步就放弃吧

注1: 一般而言RepeatModeler在一周内就能运行完,物种小一点,服务器好一点,基本上一天就行了
注2: 一般而言,同源注释所用的重复序列库的数据比较可靠,但不一定全,而我们自己建立的重复序列库比较全,但是未必准。
注3: SwissProt的植物蛋白数据库的下载地址为:ftp://ftp.uniprot.org/pub/databases/uniprot/current_release/knowledgebase/taxonomic_divisions,而NCBI的Refseq植物蛋白数据库下载地址为ftp://ftp.ncbi.nih.gov/refseq/release/plant/

利用3D-DNA流程组装基因组

利用3D-DNA流程组装基因组

使用二代数据或三代数据得到contig后,下一步就是将contig提升到染色体水平。有很多策略可以做到这一点,比如说遗传图谱,BioNano(看运气), HiC, 参考近源物种。

如果利用HiC进行准染色体水平,那么目前常见的组装软件有下面几个

  • HiRise: 2015年后的GitHub就不再更新
  • LACHESIS: 发表在NBT,2017年后不再更新
  • SALSA: 发表在BMC genomics, 仍在更新中
  • 3D-DNA: 发表在science,仍在更新中
  • ALLHiC: 发表在Nature Plants, 用于解决植物多倍体组装问题

对于二倍体物种而言,目前3D-DNA应该是组装效果最好的一个软件。

工作流程

使用3D-DNA做基因组组装的整体流程如下图,分别为组装,Juicer分析Hi-C数据,3D-DNA进行scaffolding,使用JBAT对组装结果进行手工纠正,最终得到准染色体水平的基因组。

总体流程

基因组组装可以是二代测序方法,也可以是三代测序组装方法,总之会得到contig。

Juicer的工作流程见下图,输入原始的fastq文件,处理得到中间文件.hic, 之后对.hic文件用于下游分析,包括

  • Arrowhead: 寻找存在关联的区域
  • HiCCUPS: 分析局部富集peaks
  • MotifFinder: 用于锚定peaks
  • Persons: 计算观测/期望的皮尔森相关系数矩阵
  • Eigenvector: 确定分隔

juicer工作流程

之后Juicer的输出结果给3D-DNA,分析流程见下图。3D-DNA先根据Hi-C数据分析contig中的misjoin,对其进行纠错。之后通过四步,分别是Polish, Split, Seal和Merge, 得到最终的基因组序列

3d-dna流程

软件安装

在安装之前,确保服务器上有了下面这些依赖软件工具

  • LastZ(仅在杂合基因组的二倍体模式下使用)
  • Java >= 1.7
  • GNU Awk >= 4.02
  • GNU coreutils sort > 8.11
  • Python >= 2.7
  • scipy, numpy, matplotlib
  • GNU Parallel >=20150322 (不必要,但是强力推荐)
  • bwa

我们需要安装两个软件,一个是3D-DNA,另一个是juicer。

CPU版本的juicer安装

1
2
3
4
5
6
7
8
mkdir -p ~/opt/biosoft/
cd ~/opt/biosoft
git clone https://github.com/theaidenlab/juicer.git
cd juicer
ln -s CPU scripts
cd scripts/common
wget https://hicfiles.tc4ga.com/public/juicer/juicer_tools.1.9.9_jcuda.0.8.jar
ln -s juicer_tools.1.9.9_jcuda.0.8.jar juicer_tools.jar

然后用~/opt/biosoft/juicer/scripts/juicer.sh -h检查是否有帮助信息输出

3D-DNA安装也很容易,只需要从Github上将内容克隆到本地即可

1
2
cd ~/opt/biosoft
git clone https://github.com/theaidenlab/3d-dna.git

sh ~/opt/biosoft/3d-dna/run-asm-pipeline.sh -h查看是否有帮助文档输出。

参数详解

以CPU版本的为例,juicer.sh的参数如下

1
2
3
4
Usage: juicer.sh [-g genomeID] [-d topDir] [-s site] [-a about] [-R end]
[-S stage] [-p chrom.sizes path] [-y restriction site file]
[-z reference genome file] [-D Juicer scripts directory]
[-b ligation] [-t threads] [-r] [-h] [-f] [-j]

参数说明

  • -g: 定义一个物种名
  • -s: 酶切类型, HindIII(AAGCTAGCTT), MboI(GATCGATC) , DpnII(GATCGATC), NcoI(CCATGCATGG)
  • -z : 参考基因组文件
  • -y: 限制性酶切位点可能出现位置文件
  • -p: 染色体大小文件
  • -C: 将原来的文件进行拆分,必须是4的倍数,默认是90000000, 即22.5M reads
  • -S: 和任务重运行有关,从中途的某一步开始,”merge”, “dedup”, “final”, “postproc” 或 “early”
  • -D: juicer的目录,我们安装在~/opt/biosoft/,所以设置为~/opt/biosoft/juicer
  • -a: 实验的描述说明,可以不用设置
  • -t: 线程数

juicer.sh还有AWS, LSF, PBS, SLURM版本,由于我的服务器是单主机,无法进行测试讲解。

如果你的基因组不是复杂基因组,比如说高杂合,高重复序列,或者Hi-C数据测太少,那么3d-dna的流程更加简单, run-asm-pipeline.sh -h只有四个参数需要改

  • -i|--input: 过滤长度低于给定阈值的contig/scaffold, 默认是15000
  • -r|--round: 基因组中misjoin的纠错轮数,默认是2,当基因组比较准确时,设置为0,然后在JABT中调整会更好
  • -m|--mode: 是否调用merge模块,当且仅当在杂合度比较高的情况下使用,也就是组装的单倍型基因组明显偏大
  • -s|--stage: 从polish, split, seal, merge 或finalize 的某一个阶段开始

但是,一旦基因组复杂起来,那么需要调整的参数就非常多了, run-asm-pipeline.sh --help会输出更多的信息,你需要根据当前结果去确定每个阶段的参数应该如何调整。

最终的输出文件最关键的是下面三类:

  • .fasta: 以FINAL标记的是最终结果
  • .hic: 各个阶段都会有输出结果,用于在JABT中展示
  • .assembly: 各个阶段都会有输出,一共两列,存放contig的组装顺序

分析过程

假如你现在目录下有2个文件夹,reference

  • reference: 存放一个genome.fa, 为组装的contigs
  • fastq: 存放HiC二代双端测序结果,read_R1_fastq.gz, read_R2_fastq.gz

注意,genome.fa中的序列一定得是80个字符分隔的情况,也就是多行FASTA。

增加一个新的基因组

第一步: 为基因组建立BWA索引

1
2
cd reference
bwa index genome.fa

第二步: 根据基因组构建创建可能的酶切位点文件

1
python ~/opt/biosoft/juicer/misc/generate_site_positions.py DpnII genome genome.fa

第三步: 运行如下命令, 获取每条contig的长度

1
2
3
awk 'BEGIN{OFS="\t"}{print $1, $NF}' genome_DpnII.txt > genome.chrom.size
# 返回上级目录
cd ..

运行juicer

保证当前目录下有fastq和reference文件夹,然后运行如下命令,一定要设置-z,-p,-y这三个参数

1
2
3
4
5
6
7
8
~/opt/biosoft/juicer/scripts/juicer.sh \
-g genome \
-s MboI \
-z reference/genome.fa \
-y reference/genome_DpnII.txt \
-p reference/genome.chrom.size \
-D ~/opt/biosoft/juicer \
-t 40 &> juicer.log &

你可能会好奇为啥这里出现两个酶,DpnII和MboI。这是因为DpnI, DpnII, MboI, Sau3AI, 识别相同的序列,GATC,仅仅是对甲基化敏感度不同。

输出的结果文件都在aligned目录下,其中”merged_nodups.txt”就是下一步3D-DNA的输入文件之一

运行3d-dna

3d-dna的运行也没有多少参数可以调整,如果对组装的信心高,就用-r 0, 否则用默认的-r 2就行了。

1
~/opt/biosoft/3d-dna/run-asm-pipeline.sh -r 2 reference/genome.fa aligned/merged_nodups.txt &> 3d.log &

然后在Juicer-Tools中对结果进行可视化,对可能的错误进行纠正

最后输出文件中,包含FINAL就是我们需要的结果。

使用juicerbox进行手工纠错

关于juicerbox的用法,我已经将原视频搬运到哔哩哔哩, 见https://www.bilibili.com/video/av65134634

最常见的几种组装错误:

  • misjoin: 切割
  • translocations: 移动
  • inversions: 翻转
  • chromosome boundaries: 确定染色体的边界

这些错误的判断依赖于经验,所以只能靠自己多试试了。

最后输出genome.review.assembly用于下一步的分析

再次运行3d-dna

根据JABT手工纠正的结果, genome.review.assembly, 使用run-asm-pipeline-post-review.sh重新组装基因组。

1
2
~/opt/biosoft/3d-dna/run-asm-pipeline-post-review.sh \
-r genome.review.assembly genome.fa aligned/merged_nodups.txt &> 3d.log &

个人使用评价

juicer的代码个人感觉不是特别的好,至少以下几个地方都需要改,

  • 临时文件不会去及时删除
  • bwa得到的SAM文件处理方式有待优化,使用BAM能更快的并行计算
  • 参数命令的判断很差,用-z判断字符串是否为0,而不是用-f或-d去判断文件是否存在,这个我已经提了一个issue,希望能改吧
  • Linux的sort支持多线程,但是没看到用
  • 脚本中有些限速步骤的awk代码,不知道什么时候能改成更高效的处理

前两条导致了运行过程中要占用大量的硬盘,所以不准备2T左右的硬盘,很容易出错。第三条是一些报错不会及时停止运算,也不容易排查。估计公司从效率角度出发,应该是写了很多脚本来替换原来的awk脚本了

另外,juicer在多倍体物种上表现很差,建议使用ALLHiC

参考资料

假如你不小心设置了错误的-p参数,也不是特别的要紧,因为之后在最后阶段(final) 才会遇到了下面这个报错

1
2
3
4
Could not find chromosome sizes file for: reference/genome.chrom.size
***! Can't find inter.hic in aligned/inter_30.hic
***! Error! Either inter.hic or inter_30.hic were not created
Either inter.hic or inter_30.hic were not created. Check aligned for results

即便遇到了这个报错也不要紧,因为inter.hic 和 inter_30.hic在3d-dna流程中用不到,所以不需要解决。

如果需要解决的话,有两个解决方案,一种重新运行命令,只不过多加一个参数-S final, 就会跳过之前的比对,合并和去重步骤,直接到后面STATISTICS环节。但是这样依旧会有一些不必要的计算工作,所以另一种方法就是运行原脚本必要的代码

1
2
3
4
5
6
7
8
9
10
11
juiceDir=~/opt/biosoft/juicer
outputdir=aligned
genomePath=reference/genome.chrom.size
site_file=reference/genome_DpnII.txt
ligation=GATCGATC
# output is inter.hic
${juiceDir}/scripts/common/juicer_tools pre -f $site_file -s $outputdir/inter.txt -g $outputdir/inter_hists.m -q 1 $outputdir/merged_nodups.txt $outputdir/inter.hic $genomePath
# output is inter_30.txt
${juiceDir}/scripts/common/statistics.pl -s $site_file -l $ligation -o $outputdir/inter_30.txt -q 30 $outputdir/merged_nodups.txt
# output is inter_30.hic
${juiceDir}/scripts/common/juicer_tools pre -f $site_file -s $outputdir/inter_30.txt -g $outputdir/inter_30_hists.m -q 30 $outputdir/merged_nodups.txt $outputdir/inter_30.hic $genomePath

样本足够多时别用DESeq2,用非参数检验都行

果子老师做过一个非常惊人的举动,用DESeq2处理1225例样本的TCGA数据,在没有使用DESeq多线程参数parallel的情况下,跑了将近40个小时。

那么问题来了,在那么大的样本量的情况下,应该用DESeq2进行数据处理吗?我的结论是不应该,DESeq2的适用场景是小样本的差异表分析,降低假阳性。当你的样本量足够多的时候,我们其实有更好的选择。

这里以果子老师的数据为例,来对比DESeq2的结果和我的分析结果进行比较.

加载DESeq2结果

1
2
3
4
5
6
load(file="dds_very_long.Rdata")
library(DESeq2)
deseq2_result <- results(dds)
table(deseq2_result$padj < 0.01)
# FALSE TRUE
# 23997 25072

下面我分析时的数据预处理 部分,

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
options(stringsAsFactors = FALSE)
# 加载数据
load(file = "BRCA_RNASEQ_exprdf.Rdata")

# 提取表达量矩阵
expr_mt <- as.matrix(expr_df[,-1])
row.names(expr_mt) <- expr_df$gene_id
colnames(expr_mt) <- colnames(expr_df)[-1]

# 根据文库大小标准化
expr_mt <- expr_mt / rep(colSums(expr_mt), each=nrow(expr_mt)) * 1e6
# 过滤地表达基因
expr_mt <- expr_mt[rowSums(expr_mt > 0) > (ncol(expr_mt) / 3), ]

# 统计癌症和癌旁
TCGA_id <- colnames(expr_mt)
table(substring(TCGA_id,14,15))
### 我们发现了7个转移的样本,本次分析,我们关注的是癌症和癌旁,先把转移的样本去掉
### 原发和转移的对比作为家庭作业

TCGA_id <- TCGA_id[substring(TCGA_id,14,15)!="06"]

### 创建metadata
sample <- ifelse(substring(TCGA_id,14,15)=="01","cancer","normal")
sample <- factor(sample,levels = c("normal","cancer"),ordered = F)
metadata <- data.frame(TCGA_id,sample)

下一步,利用非参数检验方法, wilcox.test,关于非参数检验的缘起可以看「女士品茶」的第16章摆脱参数

威尔科克森注释着计算t检验和方法分析的公式,意识到这些不同寻常的极端数值会对结果产生极大的影响,导致“学生”的t检验偏小。 … 如果异常值体现了某种因素对系统数据的系统性污染,那么使用非参数方法只会让事情变得更糟。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# wilcox.test差异分析 ---------------------------------------------------------
cancer_sample <- metadata[metadata$sample == "cancer", "TCGA_id"]
normal_sample <- metadata[metadata$sample == "normal", "TCGA_id"]

cancer_mt <- expr_mt[,colnames(expr_mt) %in% cancer_sample ]
normal_mt <- expr_mt[,colnames(expr_mt) %in% normal_sample ]

# 计算logFoldChanges
logFC <- log2(rowMeans(as.matrix(cancer_df)) / rowMeans(as.matrix(normal_df)))

library(future.apply)
plan(multiprocess)
p_values <- future_lapply(seq(nrow(cancer_df)), function(x){
res <- wilcox.test(x = cancer_mt[x,], y = normal_mt[x,])
res$p.value
})

p <- unlist(p_values)
p.adj <- p.adjust(p, method = "fdr")

table(p.adj < 0.01)
# FALSE TRUE
# 10997 24030

我们得到了24,030个校正后p值小于0.01的基因,而DESeq2是25,072个。如果比较全部的基因的话,韦恩图上可以发现,绝大部分基因都是相同的。

总体比较

但是通常情况下,我们会更去关注一些变化比较大且p值显著的基因,用这些基因去做下游的富集分析。所以,下一步就是看看后面富集分析结果两者有什么区别。

我们用Y叔的clusterProfiler,去分析倍数变化4倍,矫正p值小于0.01的基因

1
2
3
4
5
6
7
8
9
10
11
# 提取基因
library(clusterProfiler)
library(org.Hs.eg.db)

org <- org.Hs.eg.db
diffgene1 <- row.names(expr_mt)[p.adj < 0.01 & abs(logFC) > 2]
diffgene1 <- substr(diffgene1, 1, 15)
diffgene2 <- row.names(deseq2_result)[deseq2_result$padj < 0.01 &
! is.na(deseq2_result$padj) &
abs(deseq2_result$log2FoldChange) > 2]
diffgene2 <- substr(diffgene2, 1, 15)

GO富集分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
library(clusterProfiler)
library(org.Hs.eg.db)

org <- org.Hs.eg.db
diffgene1 <- row.names(expr_mt)[p.adj < 0.01 & abs(logFC) > 2]
diffgene1 <- substr(diffgene1, 1, 15)
diffgene2 <- row.names(deseq2_result)[deseq2_result$padj < 0.01 &
! is.na(deseq2_result$padj) &
abs(deseq2_result$log2FoldChange) > 2]
diffgene2 <- substr(diffgene2, 1, 15)
ego1 <- enrichGO(diffgene1,
OrgDb = org,
keyType = "ENSEMBL",
ont = "BP"
)
ego2 <- enrichGO(diffgene2,
OrgDb = org,
keyType = "ENSEMBL",
ont = "BP"
)

merge_result <- merge_result(list(wilcox=ego1,DESeq2=ego2))
dotplot(merge_result,showCategory= 20 )

比较20个GO词条

从点图中,你可以认为这两个分析结果是一致。

综上,当你在样本量足够多(两组都不少于10吧),其实没有去用DESeq2这些复杂的工具,用基础的统计学检验方法就能得到很好的结果了。

在样本量比较小的时候,用复杂的模型是无奈之举,它有很多假设成分在,尤其是你还想从无重复的实验设计中算p值。当你样本量够多的时候,用最简单的模型其实就会有很好的结果。

本次分析用到的数据可以通过在微信公众号搜索 果子学生信 后台回复 “果子学统计” ,就可以拿到了