WGS全流程的学习笔记

Part1 数据下载

先去Korean Personal Genome Project下载了编号为KPGP-00001的数据。

先说一下KPGP吧,中文名叫韩国个人基因组计划,这里面的数据都是可以免费下载的。

image
image
image

nohup wget  -c -r -nd -np -k -L -p   ftp://ftp.kobic.re.kr/pub/KPGP/2015_release_candidate/WGS/KPGP-00001  1>/dev/null  2>&1 &

简单的说一下这个命令中的几个知识点:

1.nohup

nohup命令可以在你退出帐户之后继续运行相应的进程。nohup就是不挂起的意思( no hang up)

2.&

当在前台运行某个作业时,终端被该作业占据;可以在命令后面加上& 实现后台运行

一般情况下,两者同时使用:

nohup command &

ps all 可以查所有后台任务

这样就不用管它了

下载完成后的数据量如下

image

一般大型的文件的下载需要将其md5文件一起下载,来检验下载的文件是否下载完全


md5sum KPGP-00001_L1_R1.fq.gz >md5tmp1.txt

cat md5tmp1.tx

cat KPGP-00001_L1_R1.fq.gz.md5

如果结果一致就可以判断下载完全

此时的目录应该如下:

image

Part2 测序reads的质控


cat fastqc.sh

#!/bin/bash

for i in $(seq 1 6)

do

fastqc /home/ubuntu/WGS_new/input/KPGP-00001_L${i}_R1.fq.gz /home/ubuntu/WGS_new/input/KPGP-00001_L${i}_R2.fq.gz -o /home/ubuntu/WGS_new/output/fastqc_result && echo "KPGP-00001_L${i} fasqtc is done" >fastqc${i}.log

done

nohup bash fastqc.sh &

由于测序数据有6个lane,而且又是pair-end测序,所以用到multiqc来归纳汇总。

cd ~/WGS_new/output/fastqc_result
multiqc *.zip 

这一步之后产生的文件如下

├── input
│   ├── KPGP-00001_L1_R1.fq.gz
│   ├── KPGP-00001_L1_R2.fq.gz
│   ├── KPGP-00001_L2_R1.fq.gz
│   ├── KPGP-00001_L2_R2.fq.gz
│   ├── KPGP-00001_L3_R1.fq.gz
│   ├── KPGP-00001_L3_R2.fq.gz
│   ├── KPGP-00001_L4_R1.fq.gz
│   ├── KPGP-00001_L4_R2.fq.gz
│   ├── KPGP-00001_L5_R1.fq.gz
│   ├── KPGP-00001_L5_R2.fq.gz
│   ├── KPGP-00001_L6_R1.fq.gz
│   ├── KPGP-00001_L6_R2.fq.gz
│   └── nohup.out
├── output
│   └── fastqc_result
│       ├── KPGP-00001_L1_R1_fastqc.html
│       ├── KPGP-00001_L1_R1_fastqc.zip
│       ├── KPGP-00001_L2_R1_fastqc.html
│       ├── KPGP-00001_L2_R1_fastqc.zip
│       ├── KPGP-00001_L2_R2_fastqc.html
│       ├── KPGP-00001_L2_R2_fastqc.zip
│       ├── KPGP-00001_L3_R1_fastqc.html
│       ├── KPGP-00001_L3_R1_fastqc.zip
│       ├── KPGP-00001_L3_R2_fastqc.html
│       ├── KPGP-00001_L3_R2_fastqc.zip
│       ├── KPGP-00001_L4_R1_fastqc.html
│       ├── KPGP-00001_L4_R1_fastqc.zip
│       ├── KPGP-00001_L4_R2_fastqc.html
│       ├── KPGP-00001_L4_R2_fastqc.zip
│       ├── KPGP-00001_L5_R1_fastqc.html
│       ├── KPGP-00001_L5_R1_fastqc.zip
│       ├── KPGP-00001_L5_R2_fastqc.html
│       ├── KPGP-00001_L5_R2_fastqc.zip
│       ├── KPGP-00001_L6_R1_fastqc.html
│       ├── KPGP-00001_L6_R1_fastqc.zip
│       ├── KPGP-00001_L6_R2_fastqc.html
│       ├── KPGP-00001_L6_R2_fastqc.zip
│       ├── multiqc_data
│       │   ├── multiqc_data.json
│       │   ├── multiqc_fastqc.txt
│       │   ├── multiqc_general_stats.txt
│       │   ├── multiqc.log
│       │   └── multiqc_sources.txt
│       └── multiqc_report.html
└── script
    ├── fastqc1.log
    ├── fastqc2.log
    ├── fastqc3.log
    ├── fastqc4.log
    ├── fastqc5.log
    ├── fastqc6.log
    ├── fastqc.sh
    └── nohup.out

此处的质量控制指的是原始数据的质量控制,接下来了解一下质控相关的知识
(此处有借鉴微信公众号:解螺旋的矿工的文章)
说到质量控制,先了解什么是质量值
碱基质量值就是能够用来定量描述碱基好坏程度的一个数值。它该如何才能恰当地描述这个结果呢?我们试想一下,如果测序测得越准确,这个碱基的质量就应该越高;反之,测得越不准确,质量值就应该越低。也就是说可以利用碱基被测错的概率来描述它的质量值,错误率越低,质量值就越高。
假定碱基的测序错误率为p_error,质量值为Q
有公式:
Q = -10log(p_error)
如果该碱基的测序错误率是0.01,那么质量值就是20(俗称Q20),如果是0.001,那么质量值就是30(俗称Q30)。Q20和Q30的比例常常被我们用来评价某次测序结果的好坏,比例越高就越好。
现在一般都是使用Phred33这个体系。
基本上可以从下面几个方面来了解原始数据的质量值:
1.reads各位置的碱基质量分布
在做read质量值分析的时候,FastQC并不单独查看具体某一条read中碱基的质量值,而是将Fastq文件中所有的read数据都综合起来一起分析。如下图,来自KPGP-00001_L1_R1

image.png

这个图的横轴是read上碱基的位置,纵轴是碱基质量值。
我们可以看到read上的每一个位置都有一个黄色的箱型图表示在该位置上所有碱基的质量分布情况。
2.碱基总体质量值分布
fastqc还会提供一个碱基总体的质量分布如下:
image.png

只要大部分都高于20,那么就比较正常
另外,Q20和Q30的比例是我们衡量测序质量的一个重要指标。一般来说,对于二代测序,最好是达到Q20的碱基要在95%以上(最差不低于90%),Q30要求大于85%(最差也不要低于80%)
3.reads各个位置上碱基比例分布
image.png

这个是为了分析碱基的分离程度。何为碱基分离?我们知道AT配对,CG配对,假如测序过程是比较随机的话(随机意味着好),那么在每个位置上A和T比例应该差不多,C和G的比例也应该差不多,如上图所示,两者之间即使有偏差也不应该太大,最好平均在1%以内,如果过高,除非有合理的原因,比如某些特定的捕获测序所致。
4.GC含量分布图
image.png

GC含量指的是G和C这两中碱基占总碱基的比例。二代测序平台或多或少都存在一定的测序偏向性,我们可以通过查看这个值来协助判断测序过程是否足够随机。对于人类来说,我们基因组的GC含量一般在40%左右。因此,如果发现GC含量的图谱明显偏离这个值那么说明测序过程存在较高的序列偏向性,结果就是基因组中某些特定区域被反复测序的几率高于平均水平,除了覆盖度会有偏离之后,将会影响下游的变异检测和CNV分析。图中的GC含量约在39%,处于正常范围。
5.N含量分布图
image.png

N在测序数据中一般是不应该出现的,如果出现则意味着,测序的光学信号无法被清晰分辨,如果这种情况多的话,往往意味着测序系统或者测序试剂的错误。图中接近0%。
6.接头序列
image.png

在测序之前需要构建测序文库,测序接头就是在这个时候加上的,其目的一方面是为了能够结合到flowcell上,另一方面是当有多个样本同时测序的时候能够利用接头信息进行区分。当测序read的长度大于被测序的DNA片段时,就会在read的末尾测到这些接头序列。一般的WGS测序是不会测到这些接头序列的,因为构建WGS测序的文库序列(插入片段)都比较长,约几百bp,而read的测序长度都在100bp-150bp这个范围。不过在进行一些RNA测序的时候,由于它们的序列本来就比较短很多只有几十bp长(特别是miRNA),那么就很容易会出现read测通的现象,这个时候就会在read的末尾测到这些接头序列。
image.png

最后,如果测序质量很差的情况下,则需要切除测序接头序列和read的低质量序列
工具有:SOAPnuke、cutadapt、untrimmed等,但是,常用的一般是SOAPnuke、cutadapt、untrimmed等。

Part3 比对(mapping)

step1

mkdir /home/ubuntu/WGS_new/input/genome
cd /home/ubuntu/WGS_new/input/genome
wget  http://hgdownload.cse.ucsc.edu/goldenPath/hg38/bigZips/hg38.fa.gz 

#对下载的基因组建立索引,下面是建索引的脚本
#!/bin/bash
bwa index -a bwtsw -p /home/ubuntu/WGS_new/input/genome/hg38 /home/ubuntu/WGS_new/input/genome/Homo_sapiens_assembly38.fasta && echo "bwa index of hg38 is done"

#运行脚本
nohup bash bwa_index.sh &

索引构建完毕后的目录如下:

├── input
│   ├── genome
│   │   ├── hg38.amb
│   │   ├── hg38.ann
│   │   ├── hg38.bwt
│   │   ├── hg38.fa
│   │   ├── hg38.pac
│   │   ├── hg38.sa
│   │   └── nohup.out
│   ├── KPGP-00001_L1_R1.fq.gz
│   ├── KPGP-00001_L1_R2.fq.gz
│   ├── KPGP-00001_L2_R1.fq.gz
│   ├── KPGP-00001_L2_R2.fq.gz
│   ├── KPGP-00001_L3_R1.fq.gz
│   ├── KPGP-00001_L3_R2.fq.gz
│   ├── KPGP-00001_L4_R1.fq.gz
│   ├── KPGP-00001_L4_R2.fq.gz
│   ├── KPGP-00001_L5_R1.fq.gz
│   ├── KPGP-00001_L5_R2.fq.gz
│   ├── KPGP-00001_L6_R1.fq.gz
│   ├── KPGP-00001_L6_R2.fq.gz
│   └── nohup.out
├── output
│   └── fastqc_result
│       ├── KPGP-00001_L1_R1_fastqc.html
│       ├── KPGP-00001_L1_R1_fastqc.zip
│       ├── KPGP-00001_L2_R1_fastqc.html
│       ├── KPGP-00001_L2_R1_fastqc.zip
│       ├── KPGP-00001_L2_R2_fastqc.html
│       ├── KPGP-00001_L2_R2_fastqc.zip
│       ├── KPGP-00001_L3_R1_fastqc.html
│       ├── KPGP-00001_L3_R1_fastqc.zip
│       ├── KPGP-00001_L3_R2_fastqc.html
│       ├── KPGP-00001_L3_R2_fastqc.zip
│       ├── KPGP-00001_L4_R1_fastqc.html
│       ├── KPGP-00001_L4_R1_fastqc.zip
│       ├── KPGP-00001_L4_R2_fastqc.html
│       ├── KPGP-00001_L4_R2_fastqc.zip
│       ├── KPGP-00001_L5_R1_fastqc.html
│       ├── KPGP-00001_L5_R1_fastqc.zip
│       ├── KPGP-00001_L5_R2_fastqc.html
│       ├── KPGP-00001_L5_R2_fastqc.zip
│       ├── KPGP-00001_L6_R1_fastqc.html
│       ├── KPGP-00001_L6_R1_fastqc.zip
│       ├── KPGP-00001_L6_R2_fastqc.html
│       ├── KPGP-00001_L6_R2_fastqc.zip
│       ├── multiqc_data
│       │   ├── multiqc_data.json
│       │   ├── multiqc_fastqc.txt
│       │   ├── multiqc_general_stats.txt
│       │   ├── multiqc.log
│       │   └── multiqc_sources.txt
│       └── multiqc_report.html
└── script
    ├── bwa_index.sh
    ├── fastqc1.log
    ├── fastqc2.log
    ├── fastqc3.log
    ├── fastqc4.log
    ├── fastqc5.log
    ├── fastqc6.log
    ├── fastqc.sh
    └── nohup.out

step2

cd /home/ubuntu/WGS_new/output
mkdir /home/ubuntu/WGS_new/output/bwa_mapping
cd /home/ubuntu/WGS_new/script
#比对的脚本如下
#!/bin/bash     
bwa mem -t 4 -R '@RG\tID:KPGP-00001_L1\tPL:illumina\tSM:KPGP-00001'  /home/ubuntu/WGS_new/input/genome/hg38 /home/ubuntu/WGS_new/input/KPGP-00001_L1_R1.fq.gz /home/ubuntu/WGS_new/input/KPGP-00001_L1_R2.fq.gz >/home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L1.sam && echo "KPGP-00001_L1 mapping is done" 
bwa mem -t 4 -R '@RG\tID:KPGP-00001_L2\tPL:illumina\tSM:KPGP-00001'  /home/ubuntu/WGS_new/input/genome/hg38 /home/ubuntu/WGS_new/input/KPGP-00001_L2_R1.fq.gz /home/ubuntu/WGS_new/input/KPGP-00001_L2_R2.fq.gz >/home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L2.sam && echo "KPGP-00001_L2 mapping is done"
bwa mem -t 4 -R '@RG\tID:KPGP-00001_L3\tPL:illumina\tSM:KPGP-00001'  /home/ubuntu/WGS_new/input/genome/hg38 /home/ubuntu/WGS_new/input/KPGP-00001_L3_R1.fq.gz /home/ubuntu/WGS_new/input/KPGP-00001_L3_R2.fq.gz >/home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L3.sam && echo "KPGP-00001_L3 mapping is done"
bwa mem -t 4 -R '@RG\tID:KPGP-00001_L4\tPL:illumina\tSM:KPGP-00001'  /home/ubuntu/WGS_new/input/genome/hg38 /home/ubuntu/WGS_new/input/KPGP-00001_L4_R1.fq.gz /home/ubuntu/WGS_new/input/KPGP-00001_L4_R2.fq.gz >/home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L4.sam && echo "KPGP-00001_L4 mapping is done"
bwa mem -t 4 -R '@RG\tID:KPGP-00001_L5\tPL:illumina\tSM:KPGP-00001'  /home/ubuntu/WGS_new/input/genome/hg38 /home/ubuntu/WGS_new/input/KPGP-00001_L5_R1.fq.gz /home/ubuntu/WGS_new/input/KPGP-00001_L5_R2.fq.gz >/home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L5.sam && echo "KPGP-00001_L5 mapping is done"
bwa mem -t 4 -R '@RG\tID:KPGP-00001_L6\tPL:illumina\tSM:KPGP-00001'  /home/ubuntu/WGS_new/input/genome/hg38 /home/ubuntu/WGS_new/input/KPGP-00001_L6_R1.fq.gz /home/ubuntu/WGS_new/input/KPGP-00001_L6_R2.fq.gz >/home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L6.sam && echo "KPGP-00001_L6 mapping is done"

#运行脚本
nohup bash bwa_mapping.sh &

比对后生成sam文件,将sam文件转换成二进制格式的bam文件

#转换的脚本如下
#!/bin/bash
for i in $(seq 1 6)
do
samtools view -Sb /home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L${i}.sam >/home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L${i}.bam && echo "KPGP-00001_L${i} samt2bam is done"
done

#运行脚本
nohup bash sam2bam.sh &

#运行结束后,再把sam格式文件删除,其实可以不删除,但是太占储存空间了
cd /home/ubuntu/WGS_new/output/bwa_mapping
rm *.sam

结果如下:

├── input
│   ├── genome
│   │   ├── hg38.amb
│   │   ├── hg38.ann
│   │   ├── hg38.bwt
│   │   ├── hg38.fa
│   │   ├── hg38.pac
│   │   ├── hg38.sa
│   │   └── nohup.out
│   ├── KPGP-00001_L1_R1.fq.gz
│   ├── KPGP-00001_L1_R2.fq.gz
│   ├── KPGP-00001_L2_R1.fq.gz
│   ├── KPGP-00001_L2_R2.fq.gz
│   ├── KPGP-00001_L3_R1.fq.gz
│   ├── KPGP-00001_L3_R2.fq.gz
│   ├── KPGP-00001_L4_R1.fq.gz
│   ├── KPGP-00001_L4_R2.fq.gz
│   ├── KPGP-00001_L5_R1.fq.gz
│   ├── KPGP-00001_L5_R2.fq.gz
│   ├── KPGP-00001_L6_R1.fq.gz
│   ├── KPGP-00001_L6_R2.fq.gz
│   └── nohup.out
├── output
│   ├── bwa_mapping
│   │   ├── KPGP-00001_L1.bam
│   │   ├── KPGP-00001_L2.bam
│   │   ├── KPGP-00001_L3.bam
│   │   ├── KPGP-00001_L4.bam
│   │   ├── KPGP-00001_L5.bam
│   │   └── KPGP-00001_L6.bam
│   └── fastqc_result
│       ├── KPGP-00001_L1_R1_fastqc.html
│       ├── KPGP-00001_L1_R1_fastqc.zip
│       ├── KPGP-00001_L2_R1_fastqc.html
│       ├── KPGP-00001_L2_R1_fastqc.zip
│       ├── KPGP-00001_L2_R2_fastqc.html
│       ├── KPGP-00001_L2_R2_fastqc.zip
│       ├── KPGP-00001_L3_R1_fastqc.html
│       ├── KPGP-00001_L3_R1_fastqc.zip
│       ├── KPGP-00001_L3_R2_fastqc.html
│       ├── KPGP-00001_L3_R2_fastqc.zip
│       ├── KPGP-00001_L4_R1_fastqc.html
│       ├── KPGP-00001_L4_R1_fastqc.zip
│       ├── KPGP-00001_L4_R2_fastqc.html
│       ├── KPGP-00001_L4_R2_fastqc.zip
│       ├── KPGP-00001_L5_R1_fastqc.html
│       ├── KPGP-00001_L5_R1_fastqc.zip
│       ├── KPGP-00001_L5_R2_fastqc.html
│       ├── KPGP-00001_L5_R2_fastqc.zip
│       ├── KPGP-00001_L6_R1_fastqc.html
│       ├── KPGP-00001_L6_R1_fastqc.zip
│       ├── KPGP-00001_L6_R2_fastqc.html
│       ├── KPGP-00001_L6_R2_fastqc.zip
│       ├── multiqc_data
│       │   ├── multiqc_data.json
│       │   ├── multiqc_fastqc.txt
│       │   ├── multiqc_general_stats.txt
│       │   ├── multiqc.log
│       │   └── multiqc_sources.txt
│       └── multiqc_report.html
└── script
    ├── bwa_index.sh
    ├── bwa_mapping.sh
    ├── fastqc1.log
    ├── fastqc2.log
    ├── fastqc3.log
    ├── fastqc4.log
    ├── fastqc5.log
    ├── fastqc6.log
    ├── fastqc.sh
    ├── nohup.out
    └── sam2bam.sh

step3
对生成的bam文件按position排序

#脚本如下

#!/bin/bash
for i in $(seq 1 6)
do
samtools sort -@ 4 -m 4G -O bam -o /home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L${i}.sorted.bam /home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L${i}.bam && echo "/KPGP-00001_L${i}.sorted.bam is done"
done

此时所有结果如下

├── input
│     ├── genome
│   │   ├── hg38.amb
│?? │?? ├── hg38.ann
│?? │?? ├── hg38.bwt
│?? │?? ├── hg38.fa
│?? │?? ├── hg38.pac
│?? │?? ├── hg38.sa
│?? │?? └── nohup.out
│?? ├── KPGP-00001_L1_R1.fq.gz
│?? ├── KPGP-00001_L1_R2.fq.gz
│?? ├── KPGP-00001_L2_R1.fq.gz
│?? ├── KPGP-00001_L2_R2.fq.gz
│?? ├── KPGP-00001_L3_R1.fq.gz
│?? ├── KPGP-00001_L3_R2.fq.gz
│?? ├── KPGP-00001_L4_R1.fq.gz
│?? ├── KPGP-00001_L4_R2.fq.gz
│?? ├── KPGP-00001_L5_R1.fq.gz
│?? ├── KPGP-00001_L5_R2.fq.gz
│?? ├── KPGP-00001_L6_R1.fq.gz
│?? ├── KPGP-00001_L6_R2.fq.gz
│?? └── nohup.out
├── output
│?? ├── bwa_mapping
│?? │?? ├── index
│?? │?? ├── KPGP-00001_L1.bam
│?? │?? ├── KPGP-00001_L1.sorted.bam
│?? │?? ├── KPGP-00001_L2.bam
│?? │?? ├── KPGP-00001_L2.sorted.bam
│?? │?? ├── KPGP-00001_L3.bam
│?? │?? ├── KPGP-00001_L3.sorted.bam
│?? │?? ├── KPGP-00001_L4.bam
│?? │?? ├── KPGP-00001_L4.sorted.bam
│?? │?? ├── KPGP-00001_L5.bam
│?? │?? ├── KPGP-00001_L5.sorted.bam
│?? │?? ├── KPGP-00001_L6.bam
│?? │?? └── KPGP-00001_L6.sorted.bam
│?? └── fastqc_result
│??     ├── KPGP-00001_L1_R1_fastqc.html
│??     ├── KPGP-00001_L1_R1_fastqc.zip
│??     ├── KPGP-00001_L2_R1_fastqc.html
│??     ├── KPGP-00001_L2_R1_fastqc.zip
│??     ├── KPGP-00001_L2_R2_fastqc.html
│??     ├── KPGP-00001_L2_R2_fastqc.zip
│??     ├── KPGP-00001_L3_R1_fastqc.html
│??     ├── KPGP-00001_L3_R1_fastqc.zip
│??     ├── KPGP-00001_L3_R2_fastqc.html
│??     ├── KPGP-00001_L3_R2_fastqc.zip
│??     ├── KPGP-00001_L4_R1_fastqc.html
│??     ├── KPGP-00001_L4_R1_fastqc.zip
│??     ├── KPGP-00001_L4_R2_fastqc.html
│??     ├── KPGP-00001_L4_R2_fastqc.zip
│??     ├── KPGP-00001_L5_R1_fastqc.html
│??     ├── KPGP-00001_L5_R1_fastqc.zip
│??     ├── KPGP-00001_L5_R2_fastqc.html
│??     ├── KPGP-00001_L5_R2_fastqc.zip
│??     ├── KPGP-00001_L6_R1_fastqc.html
│??     ├── KPGP-00001_L6_R1_fastqc.zip
│??     ├── KPGP-00001_L6_R2_fastqc.html
│??     ├── KPGP-00001_L6_R2_fastqc.zip
│??     ├── multiqc_data
│??     │?? ├── multiqc_data.json
│??     │?? ├── multiqc_fastqc.txt
│??     │?? ├── multiqc_general_stats.txt
│??     │?? ├── multiqc.log
│??     │?? └── multiqc_sources.txt
│??     └── multiqc_report.html
└── script
    ├── bam_index.sh
    ├── bwa_index.sh
    ├── bwa_mapping.sh
    ├── fastqc1.log
    ├── fastqc2.log
    ├── fastqc3.log
    ├── fastqc4.log
    ├── fastqc5.log
    ├── fastqc6.log
    ├── fastqc.sh
    ├── nohup.out
    └── sam2bam.sh

以上的步骤就完成了比对的过程
在此基础上,做一些以下的横向探索:

1.分别利用 samtools和 bedtools 对测序深度和覆盖度进行统计,并可视化

2.把bam文件按染色体分成小文件,并用IGV查看

3.bam格式转化为bw格式看测序深度分布

4.测序深度和GC含量的关系

1.分别利用 samtools和 bedtools 对测序深度和覆盖度进行统计,并可视化

用samtools 对测序深度进行统计

#!/bin/bash
for i in $(seq 1 6)
do
samtools depth /home/ubuntu/WGS_new/output/bwa_mapping/KPGP-00001_L${i}.sorted.bam 1>/home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L${i}.sorted.bam.depth 2>&1 && echo "KPGP-00001_L${i}.sorted.bam depth count is done"
done

这个软件得到的文件格式如下

chr1    9999    4
chr1    10000   5
chr1    10001   51
chr1    10002   161
chr1    10003   250
chr1    10004   278
chr1    10005   365
chr1    10006   390
chr1    10007   391
chr1    10008   397
chr1    10009   406
chr1    10010   407
chr1    10011   414
chr1    10012   415
chr1    10013   417
chr1    10014   420
chr1    10015   420
chr1    10016   419
chr1    10017   421
chr1    10018   422
chr1    10019   425
chr1    10020   427
chr1    10021   430
chr1    10022   432
chr1    10023   435
chr1    10024   435
chr1    10025   437
chr1    10026   439
chr1    10027   439
chr1    10028   440
chr1    10029   440
chr1    10030   442
...
...

第一列是染色体号,第二列是对应的单个碱基位置,第三列是单个碱基的深度

需要进一步统计到每个染色体对应的测序深度

这一步的python脚本如下

import sys
args=sys.argv
filename=args[1]
SumDict={}
for line in open(filename):
  lineL=line.strip().split("\t")
  ID=lineL[0]
  depth=int(lineL[2])
  if ID not in SumDict:
     SumDict[ID]=depth
  else:
     SumDict[ID]+=depth
for k,v in SumDict.items():
   print(k,v,sep="\t")

-----------------------------
nohup time python3 sumDepth.py /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L1.sorted.bam.depth > /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L1.SumOfDepth.txt &

nohup time python3 sumDepth.py /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L2.sorted.bam.depth > /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L2.SumOfDepth.txt &

nohup time python3 sumDepth.py /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L3.sorted.bam.depth > /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L3.SumOfDepth.txt &

nohup time python3 sumDepth.py /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L4.sorted.bam.depth > /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L4.SumOfDepth.txt &

nohup time python3 sumDepth.py /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L5.sorted.bam.depth > /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L5.SumOfDepth.txt &

nohup time python3 sumDepth.py /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L6.sorted.bam.depth > /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L6.SumOfDepth.txt &

得到的统计结果还需要把带“_”部分除掉

#!/bin/bash
for i in $(seq 1 6)
do
grep -v "_" /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L${i}.SumOfDepth.txt >/home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L${i}.SumOfDepth.final.txt
done

然后将所有的生成文件排序后合并,脚本如下

cd /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth

#脚本
--------
#!/bin/bash
for i in $(seq 1 6)
do
sed -i "s/chr//" KPGP-00001_L${i}.SumOfDepth.final.txt #首次去掉chr,方便排序
sort -k1,1n KPGP-00001_L${i}.SumOfDepth.final.txt > KPGP-00001_L${i}.SumOfDepth.sort.final.txt  #对第一列按数值排序
sed -i 's/^/chr/' KPGP-00001_L${i}.SumOfDepth.sort.final.txt  #再将chr添加回来

done


paste KPGP-00001_L*.SumOfDepth.sort.final.txt >KPGP-00001_all.SumOfDepth.sort.final.txt

awk '{sum=$2+$$4+$6+$8+$10+$12;print $1,sum;}' KPGP-00001_all.SumOfDepth.sort.final.txt >KPGP-00001.SumOfDepth.final_count.txt
---------
#运行脚本
nohup bash paste_sort.sh &

-----------
sed -i '1 i Chrom\tsum_of_depth' KPGP-00001.SumOfDepth.final_count.txt
cat KPGP-00001.SumOfDepth.final_count.txt
-----------
Chrom   sum_of_depth
chrM 34591025
chrX 4093132439
chrY 125469175
chr1 6482954037
chr2 6376037101
chr3 5286606057
chr4 5330867456
chr5 4949134249
chr6 4420827669
chr7 4173524521
chr8 3842370943
chr9 3228529809
chr10 3626998764
chr11 3548159595
chr12 3490214776
chr13 2618593673
chr14 2359781279
chr15 2098133774
chr16 2341297030
chr17 1911455487
chr18 2082861061
chr19 1341657686
chr20 1741460772
chr21 1203547746
chr22 988334122

sed -i 's/ /\t/' KPGP-00001.SumOfDepth.final_count.txt


以上就将所有的染色体的覆盖位点的测序深度总和统计出来了

接下来计算覆盖度

因为samtools depth计算的是所有覆盖的每个碱基的深度,所以将对应染色体的统计信息提取,并计算有多少个碱基,得到的碱基数就是对应的覆盖长度。
所以有如下脚本统计

#!/bin/bash
for i in $(seq 1 22) 
do
grep "chr${i}   " /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L1.sorted.bam.depth |wc -l >/home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chr${i}_cov.txt
sed -i "1 i chr${i}" /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chr${i}_cov.txt
done

grep "chrX  " /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L1.sorted.bam.depth |wc -l >/home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chrX_cov.txt #x染色体
sed -i "1 i chrX" /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chrX_cov.txt

grep "chrY  " /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L1.sorted.bam.depth |wc -l >/home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chrY_cov.txt #y染色体
sed -i "1 i chrY" /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chrY_cov.txt

grep "chrM  " /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L1.sorted.bam.depth |wc -l >/home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chrM_cov.txt #线粒体
sed -i "1 i chrM" /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chrM_cov.txt

这里计算的是一个lane的coverage,应该要计算所有6个lane的coverage,再求mean值,或者提前将6个lane的bam文件merge后再处理。此处由于系统存储空间问题,只对一个lane作简单统计。

sort -m chr*_cov.txt|sed -n 1~2p> chr_cov1.txt
sort -m chr*_cov.txt|sed -n 2~2p> chr_cov2.txt
paste chr_cov*.txt>chr_cov_all.txt
sed 's/chr//' chr_cov_all.txt|sort -k1,1n|sed 's/^/chr/'|sed '1 i Chrom\tcoverage' >chr_cov.txt
cat chr_cov.txt


Chrom   coverage
chrM    16569
chrX    151545600
chrY    4004642
chr1    224300366
chr2    235466712
chr3    194391189
chr4    185704231
chr5    176555626
chr6    164731880
chr7    155128428
chr8    141501464
chr9    118343356
chr10   129732215
chr11   131193733
chr12   130177621
chr13   95749291
chr14   87847379
chr15   81867181
chr16   78578328
chr17   78271424
chr18   77398752
chr19   54075815
chr20   62148856
chr21   38164294
chr22   36926516


计算参考序列染色体的长度
这里首先需要将hg38中的重复的N序列去除
首先想到的是

grep -v "N" hg38.fa >hg38.cut.fa

这里有一个小问题,就是如果N藏在正常ATGC序列之中的话,就很容易去除掉正常的碱基
所以改成sed命令

sed 's/N//g' hg38.fa >hg38.sed.fa #把所有的N替换成空
sed '/^$/d' hg38.sed.fa >hg38.final.fa  #去除空行

sed是将N替换成空,并不是将含N的行除去
虽然两个命令得到结果一样,但还是选择后者是正确的。

写了2个python脚本分别统计1.hg38原始文件对应各条染色体的长度
2.hg38去除N之后的各条染色体的长度
3.hg38原始文件的各条染色体的N含量
脚本如下

import sys
args=sys.argv
filename=args[1]
seq_id={}

for line in open(filename):
  line=line.strip()
  if line.startswith(">"):
      seq_name = line
      if seq_name not in seq_id:
          seq_id[seq_name]=''
  else:
      seq_id[seq_name]+=line.strip()
for k,v in seq_id.items():
   seq_length=len(v)
   name=k[1:]
   print(name,seq_length,sep="\t")
---------------------------------------------------
#运行脚本
--------------------
nohup python3 count_length.py hg38.fa > hg38.chr_length.txt &
nohup python3 count_length.py hg38.final.fa > hg38.cutN.chr_length.txt &
-----------------------------------
import sys
args=sys.argv
filename=args[1]
seq_id={}

for line in open(filename):
  line=line.strip()
  if line.startswith(">"):
      seq_name = line
      if seq_name not in seq_id:
          seq_id[seq_name]=''
  else:
      seq_id[seq_name]+=line
for k,v in seq_id.items():
   N_count=v.count("N")
   name=k[1:]
   print(k,N_count,sep="\t")
--------------------------
#运行脚本
nohup python3 count_N.py hg38.fa >hg38.chr.countN.txt &

这两个脚本本身没有问题,而且对于fasta格式读取,把ID 和序列先构建字典的方式也是之前总结出来的
但是!!!!
对于大型的文件,先构建字典,在读取字典的过程会花费太多的时间,所以这两个脚本运行了如下的时间,程序还没有跑完

image.png

所以,需要修改代码,不要用这种构建字典的方式。
修改后的脚本如下:

#统计长度的脚本

import sys
args=sys.argv
filename=args[1]
seq_length=0
for line in open(filename):
  line=line.strip()
  if line.startswith(">"):
     if seq_length:
        print(seq_length) 
     seq_length=0
     print(line)
  else:
     seq_length+=len(line)
print(seq_length)
--------------------------------------
#统计N数量的脚本
import sys
args=sys.argv
filename=args[1]
num_N=0
for line in open(filename):
  line=line.strip()
  if line.startswith(">"):
     if num_N :
       print (num_N)  
     num_N=0
     print (line)

  else:
      num_N+=line.count("N")

print(num_N)
-----------

优化后的代码只花了2到3分钟就完成任务,可见代码优化的重要性。

因为得到结果不仅仅有chr1~22+x+y+M的信息,还有其他信息,所以需要提取
提取脚本如下

#!/bin/bash
for i in $(seq 1 22)
do
grep -A 1 ">chr${i}$" hg38.cutN.chr_length.txt > hg38.cutN.chr_length.final${i}.txt
grep -A 1 ">chr${i}$" count_N_new.txt > count_N_new.final${i}.txt
done
#!/bin/bash
for i in $(seq 1 22)
do
grep -A 1 ">chr${i}$" hg38.chr_length.txt >hg38.chr_length.final${i}.txt        #提取>chr${i}$以及其下面一行,-A是after的意思,之所以是chr${i}+一个$是因为chr${i}后面加空行
才是想要的结果,如果不清楚可以cat -A 一下,再判断
grep -A 1 ">chr${i}$" hg38.cutN.chr_length.txt > hg38.cutN.chr_length.final${i}.txt
grep -A 1 ">chr${i}$" count_N_new.txt > count_N_new.final${i}.txt
done

grep -A 1 ">chrX$" hg38.chr_length.txt >hg38.chr_length.finalX.txt
grep -A 1 ">chrX$" hg38.cutN.chr_length.txt > hg38.cutN.chr_length.finalX.txt
grep -A 1 ">chrX$" count_N_new.txt > count_N_new.finalX.txt

grep -A 1 ">chrY$" hg38.chr_length.txt >hg38.chr_length.finalY.txt
grep -A 1 ">chrY$" hg38.cutN.chr_length.txt > hg38.cutN.chr_length.finalY.txt
grep -A 1 ">chrY$" count_N_new.txt > count_N_new.finalY.txt

grep -A 1 ">chrM$" hg38.chr_length.txt >hg38.chr_length.finalM.txt
grep -A 1 ">chrM$" hg38.cutN.chr_length.txt > hg38.cutN.chr_length.finalM.txt
grep -A 1 ">chrM$" count_N_new.txt > count_N_new.finalM.txt

rm hg38.chr_length.txt
rm hg38.cutN.chr_length.txt
rm count_N_new.txt

sort -m  hg38.chr_length.final*.txt >hg38.chr_length.final_all.txt   #将所有hg38.chr_length.final*.txt 文件合并,区别于paste,这个合并成列
sort -m  hg38.cutN.chr_length.final*.txt >hg38.cutN.chr_length.final_all.txt
sort -m  count_N_new.final*.txt >count_N_new.final_all.txt

sed -n 1~2p hg38.chr_length.final_all.txt >hg38.chr_length.final_all_1.txt    #提取奇数行,1~2p中1是第一行,2p是从第一行开始,每2行输出,也就是输出奇数行
sed -n 2~2p hg38.chr_length.final_all.txt >hg38.chr_length.final_all_2.txt    #提取偶数行,2~2p中1是第一行,2p是从第一行开始,每2行输出,也就是输出偶数行
paste hg38.chr_length.final_all_1.txt hg38.chr_length.final_all_2.txt > hg38.chr_length.final_all_3.txt #hg38每条染色体的长度,包括N

这里包括3个知识点:

  1. grep -A 1 string file 提取file中匹配到string的行和下面一行,1可以改成其他数字,表示多行
    grep -B 1 string file 上面
    grep -C 1 string file 上面和下面

2.cat -A 之后再找匹配的字符串比较准确

  1. sort -m 将文件合并成列,区别与paste
  2. sed -n 1~2p 提取奇数行
    sed -n 2~2p 提取偶数行
    当然awk也很容易实现

上面提取之后的文件排序,加列标题,然后合并
脚本如下:

 sed 's/>chr//' count_N_new.final_all_3.txt |sort -k1,1n |sed 's/^/chr/'|sed '1 i Chrom\tN_Number' >N_number.txt   #排序,然后添加列标题

sed 's/>chr//' hg38.cutN.chr_length.final_all_3.txt |sort -k1,1n |sed 's/^/chr/'|sed '1 i Chrom\tCut_N_length' >hg38.cutN.len.txt

sed 's/>chr//' hg38.chr_length.final_all_3.txt |sort -k1,1n |sed 's/^/chr/'|sed '1 i Chrom\tlength' >hg38.len.txt
paste hg38.len.txt hg38.cutN.len.txt N_number.txt |cut -f 1,2,4,6 >hg38.count_all_final.txt

less -S hg38.count_all_final.txt
-------------------------------------------------
Chrom   length  Cut_N_length    N_Number
chrM    16569   16568   1
chrX    156040895       154893130       1147765
chrY    57227415        26415183        30812232
chr1    248956422       230481193       18475229
chr2    242193529       240548238       1645291
chr3    198295559       198100139       195420
chr4    190214555       189752667       461888
chr5    181538259       181265378       272881
chr6    170805979       170078724       727255
chr7    159345973       158970132       375841
chr8    145138636       144768136       370500
chr9    138394717       121790590       16604127
chr10   133797422       133263135       534287
chr11   135086622       134533742       552880
chr12   133275309       133138039       137270
chr13   114364328       97983128        16381200
chr14   107043718       90568149        16475569
chr15   101991189       84641348        17349841
chr16   90338345        81805944        8532401
chr17   83257441        82921074        336367
chr18   80373285        80089658        283627
chr19   58617616        58440758        176858
chr20   64444167        63944581        499586
chr21   46709983        40088683        6621300
chr22   50818468        39159777        11658691

--------------
结果一目了然

-------------------------------------------------------------------------------

最后再把测序深度、覆盖度、参考序列长度合并

cd /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/new
ls -lh
------
total 12K
-rw-rw-r-- 1 ubuntu ubuntu 387 Aug  7 22:11 chr_cov.txt
-rw-rw-r-- 1 ubuntu ubuntu 834 Aug  7 21:51 hg38.count_all_final.txt
-rw-rw-r-- 1 ubuntu ubuntu 429 Aug  7 22:18 KPGP-00001.SumOfDepth.final_count.txt
-------
paste * |cut -f 1,2,4,5,6,8 >count_all.txt
cat count_all.txt

Chrom   coverage    length  Cut_N_length    N_Number    sum_of_depth
chrM    16569   16569   16568   1   34591025
chrX    151545600   156040895   154893130   1147765 4093132439
chrY    4004642 57227415    26415183    30812232    125469175
chr1    224300366   248956422   230481193   18475229    6482954037
chr2    235466712   242193529   240548238   1645291 6376037101
chr3    194391189   198295559   198100139   195420  5286606057
chr4    185704231   190214555   189752667   461888  5330867456
chr5    176555626   181538259   181265378   272881  4949134249
chr6    164731880   170805979   170078724   727255  4420827669
chr7    155128428   159345973   158970132   375841  4173524521
chr8    141501464   145138636   144768136   370500  3842370943
chr9    118343356   138394717   121790590   16604127    3228529809
chr10   129732215   133797422   133263135   534287  3626998764
chr11   131193733   135086622   134533742   552880  3548159595
chr12   130177621   133275309   133138039   137270  3490214776
chr13   95749291    114364328   97983128    16381200    2618593673
chr14   87847379    107043718   90568149    16475569    2359781279
chr15   81867181    101991189   84641348    17349841    2098133774
chr16   78578328    90338345    81805944    8532401 2341297030
chr17   78271424    83257441    82921074    336367  1911455487
chr18   77398752    80373285    80089658    283627  2082861061
chr19   54075815    58617616    58440758    176858  1341657686
chr20   62148856    64444167    63944581    499586  1741460772
chr21   38164294    46709983    40088683    6621300 1203547746
chr22   36926516    50818468    39159777    11658691    988334122


awk 'BEGIN{OFS=FS="\t";}{if (NR>1){cov=$2/$4;print cov}}' count_all.txt >cov_percent.txt #计算覆盖率
awk 'BEGIN{OFS=FS="\t";}{if (NR>1){cov=$6/$2;print cov}}' count_all.txt >mean_depth.txt
sed -i '1 i cov_percent' cov_percent.txt
paste count_all.txt mean_depth.txt cov_percent.txt >count_all_done.txt
cat count_all_done.txt

Chrom   coverage    length  Cut_N_length    N_Number    sum_of_depth    mean_depth  cov_percent
chrM    16569   16569   16568   1   34591025    2087.7  1.00006
chrX    151545600   156040895   154893130   1147765 4093132439  27.0092 0.978388
chrY    4004642 57227415    26415183    30812232    125469175   31.3309 0.151604
chr1    224300366   248956422   230481193   18475229    6482954037  28.903  0.973183
chr2    235466712   242193529   240548238   1645291 6376037101  27.0783 0.978875
chr3    194391189   198295559   198100139   195420  5286606057  27.1957 0.981277
chr4    185704231   190214555   189752667   461888  5330867456  28.7062 0.978665
chr5    176555626   181538259   181265378   272881  4949134249  28.0316 0.974017
chr6    164731880   170805979   170078724   727255  4420827669  26.8365 0.968563
chr7    155128428   159345973   158970132   375841  4173524521  26.9037 0.975834
chr8    141501464   145138636   144768136   370500  3842370943  27.1543 0.977435
chr9    118343356   138394717   121790590   16604127    3228529809  27.281  0.971695
chr10   129732215   133797422   133263135   534287  3626998764  27.9576 0.973504
chr11   131193733   135086622   134533742   552880  3548159595  27.0452 0.975173
chr12   130177621   133275309   133138039   137270  3490214776  26.8112 0.977764
chr13   95749291    114364328   97983128    16381200    2618593673  27.3484 0.977202
chr14   87847379    107043718   90568149    16475569    2359781279  26.8623 0.969959
chr15   81867181    101991189   84641348    17349841    2098133774  25.6285 0.967224
chr16   78578328    90338345    81805944    8532401 2341297030  29.7957 0.960545
chr17   78271424    83257441    82921074    336367  1911455487  24.4209 0.943927
chr18   77398752    80373285    80089658    283627  2082861061  26.9108 0.966401
chr19   54075815    58617616    58440758    176858  1341657686  24.8107 0.92531
chr20   62148856    64444167    63944581    499586  1741460772  28.0208 0.971917
chr21   38164294    46709983    40088683    6621300 1203547746  31.536  0.951997
chr22   36926516    50818468    39159777    11658691    988334122   26.7649 0.942971


知识补充:
1depth 测序深度
测序深度是指测序得到的总碱基数与待测基因组大小的比值,可以理解为基因组中每个碱基被测序到的平均次数。测序深度 = reads长度 × 比对的reads数目 / 参考序列长度。假设一个基因大小为2M,测序深度为10X,那么获得的总数据量为20M。
之所以测序深度=reads长度×比对的reads数目 / 参考序列长度,可以这么去理解,因为深度指的是每个碱基被测序到的平均次数。所以假设reads长度特别长,长到等于参考序列长度(当然这不可能)。那么,这时候reads数目就直接等于测序深度,但是reads长度远远没有参考序列长,所以才有了相当于reads长度/参考序列长度,这样的一个可以理解为矫正系数。

如果我们的研究目的仅仅是进行群体遗传分析等类型的分析。由于分析是通过计算基因组不同区域的多样性变化来推断进化选择压力,或构建进化树推断遗传分化关系,SNP检出率达到70~90%足以达到此类目的。所以,此类研究常见的测序深度选择在10X左右。

如果想检测个体的全基因组突变,来寻找某个特定功能突变,则我们推荐大于30X的测序深度,以保证接近于“毫无疏漏”。

如果测序样本是混样,例如,癌组织样本(癌细胞的细胞异质性很大),BSA分析中的群体混合池样本。那么在保证30X的测序深度的基础上,如果经费许可50X的测序深度更佳,以保证对混合池中低频变异的检测成功率(例如,新出现或即将消亡的癌细胞突变)。

2.coverage 覆盖度:
覆盖度是指测序获得的序列占整个基因组的比例。指的是基因组上至少被检测到1次的区域,占整个基因组的比例。当然,有些文章中也会将测序深度称为Coverage,容易给我们带来混淆。因此,我们还是需要根据语境来推断Coverage的意思。
我们假设基因组大小为G, 假定每次测序可从基因组任何位置上随机检测一个碱基。那么对于基因组上某一个固定碱基位置,在一次测序中,该位置被命中的概率为P (P=1/G)。我们将试验重复n次,相当于产生了n个碱基(n=c*G, c为测序深度)。 碱基的深度分布,相当于求该位置被测到0次,1次,…,n次的概率各是多少? 位点被检测到的n次的概率符合泊松分布。当然,由于概率极低,检测次数很大,所以这样的泊松分布接近于正态分布。

由于基因组中的高GC、重复序列等复杂结构的存在,测序最终拼接组装获得的序列往往无法覆盖有所的区域,这部分没有获得的区域就称为Gap。例如一个细菌基因组测序,覆盖度是98%,那么还有2%的序列区域是没有通过测序获得的。

上面统计所有染色体测序深度用的是python的脚本,这里也提供一个shell脚本,但是代码会相对长一点。

#!/bin/bash
for i in $(seq 1 22) #22对染色体
do
grep "chr${i}   " /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L1.sorted.bam.depth |cut -f 3 |awk '{sum += $1;}END{print sum;}' >/home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chr${i}.txt #注意END 的使用 |注意\t键的使用,脚本中可以直接键入tab,命令行下先Ctrl+V,再按tab键。这里之所以要加tab键,是因为,比如,如果>不加tab键,grep "chr1" 得到包括chr1,chr11,chr1_...>等。

sed -i "1 i chr${i}" /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chr${i}.txt # 1表示第一行,i表示插入,即在第一行前面插入新行,名称为chr${i}
done

grep "chrX      " /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L1.sorted.bam.depth |cut -f 3 |awk '{sum += $1;}END{print sum;}' > /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chrx.txt #x染色体
grep "chrY      " /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/KPGP-00001_L1.sorted.bam.depth |cut -f 3 |awk '{sum += $1;}END{print sum;}' > /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chry.txt #y染色体
sed -i "1 i chrx" /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chrx.txt #添加列标题 chrx
sed -i "1 i chry" /home/ubuntu/WGS_new/output/bwa_mapping/samtools_depth/chry.txt

注意:awk命令要注意尽量冒号小写

awk '{sum += $1} END{print sum}' chr2.tmp
结果
3399
而
awk "{sum += $1} END{print sum}" chr2.tmp
报错
awk: cmd. line:1: {sum += } END{print sum}
awk: cmd. line:1:         ^ syntax error

小总结

cut -f 可以提取特定列
cut -f 2 提取第2列
sed -n 2p 提取2行
sed -n 2,4p 提取2至3行

对于上诉得到的汇总结果存到count.txt中,并进行可视化,脚本如下


pdf()
library(ggplot2)
data <- read.table("count.txt",header = T)
#因为上一个命令,header=T已经将首行作为列标题,所以$1没法识别,用$加列名
data <-data[-1,] #将线粒体那行删除
data$Chrom <-factor(data$Chrom,levels = c(1:22,"X","Y")) #这一步很重要,这样横坐标就按顺序排列了
Chr <- data$Chrom
M <- data$mean_depth
C <- data$cov_percent
dt1 <- data.frame(Chr,M)


dt2 <- data.frame(Chr,C)

p1 <- ggplot(dt1,aes(x=Chr,y=M))+xlab("chrom ID")+ylab("mean_depth")+labs(title="KPGP-00001")+ylim(0,100)+geom_bar(aes(fill=Chr),stat = "identity")+theme_bw()+theme(plot.title = element_text(hjust = 0.5),panel.grid.major =element_blank(),panel.grid.minor = element_blank())

# 1    ggplot(dt1,aes(x=Chr,y=M,group=Chr))是构建一个画板
# 2    +xlab("chrom ID")+ylab("mean_depth") 是更改横纵坐标标签
# 3    +labs(title="KPGP-00001") 是增加主标题
# 4    ylim(0,100) 设置y轴刻度为1~100
# 5    +geom_bar(aes(fill=Chr),stat = "identity")是画出柱状图
# 6    theme_bw()为传统的白色背景和深灰色的网格线
# 7    theme是参数的设置  plot.title = element_text(hjust = 0.5) 是将title移到中间
                        # panel.grid.major =element_blank(),panel.grid.minor = element_blank()
                        #去除网格线

p2 <- ggplot(dt2,aes(x=Chr,y=C,group=1))+xlab("chrom ID")+ylab("coverage_percent")+labs(title="KPGP-00001")+ylim(0,1.5)+geom_line(aes(color=Chr))+geom_point(aes(color=Chr))+theme_bw()+theme(plot.title = element_text(hjust = 0.5),panel.grid.major =element_blank(),panel.grid.minor = element_blank())

p1
p2
dev.off()

最终结果如下


image.png
image.png

Y染色体的覆盖度特别低,不知道什么原因。

2.把bam文件按染色体分成小文件,并用IGV查看

bam文件太大了,有时候把bam文件拆分成小的文件是有必要的

这里用到一个工具bamtools,它的功能很多,这里选用split的功能

usage: bamtools [--help] COMMAND [ARGS]

Available bamtools commands:
    convert         Converts between BAM and a number of other formats
    count           Prints number of alignments in BAM file(s)
    coverage        Prints coverage statistics from the input BAM file
    filter          Filters BAM file(s) by user-specified criteria
    header          Prints BAM header information
    index           Generates index for BAM file
    merge           Merge multiple BAM files into single file
    random          Select random alignments from existing BAM file(s), intended more as a testing tool.
    resolve         Resolves paired-end reads (marking the IsProperPair flag as needed)
    revert          Removes duplicate marks and restores original base qualities
    sort            Sorts the BAM file according to some criteria
    split           Splits a BAM file on user-specified property, creating a new BAM output file for each value found
    stats           Prints some basic statistics from input BAM file(s)

See 'bamtools help COMMAND' for more information on a specific command.


这里只用lane1的bam文件做一个测试

nohup bamtools split -in KPGP-00001_L1.sorted.bam  -reference &
#-reference指的是按reference拆分

拆分后,选取文件大小较小的chr19的bam文件,和chrY的文件(正好看看上一部布统计的覆盖度很低是不是统计错误)

#排序
samtools sort KPGP-00001_L1.sorted.REF_chrY.bam >chr_Y.sort.bam
samtools sort KPGP-00001_L1.sorted.REF_chr19.bam >chr_19.sort.bam


#建索引
samtools index chr_Y.sort.bam
samtools index chr_19.sort.bam

然后把文件导入IGV
先看一下chrY


image.png

可见覆盖度确实很低,并不是之前统计的问题

再看看chr19

image.png

chr19的覆盖程度明显大很多

3.bam格式转化为bw格式看测序深度分布

bam文件很大,很多时候才看很不方便。有些时候,我们只需要我们的测序数据在全基因组的测序深度这一个值,并不需要具体某条reads的碱基序列,碱基质量值。这样只需要把bam文件压缩为bw格式。

同样是只用lane1做测试
这里用到的一个软件deeptools
用到它其中的一个工具bamCoverage

#首先还是要先建立索引
nohup samtools index KPGP-00001_L1.sorted.bam &

再就是转换格式

nohup bamCoverage -b KPGP-00001_L1.sorted.bam -o KPGP-00001_L1.sorted.bw &

bw格式的大小才200M,可以轻松的导入IGV,可以从整体看出测序的深度和覆盖度情况。
比如


image.png

很显然,y染色体覆盖度很小

4.测序深度和GC含量的关系

首先,把全基因组的bam文件用 mpileup模式输出,根据 1000bp 的窗口滑动来统计每个窗口的测到的碱基数,GC碱基数,测序总深度。因为涉及到测序深度,所以先把各个lane的bam文件merge,再拿merge后的bam文件得到结果的前面一百万行的数据做测试。

nohup samtools merge KPGP-00001.sorted.merge.bam KPGP-00001_L*.sorted.bam &
samtools mpileup -f /home/ubuntu/WGS_new/input/genome/new/hg38.fa KPGP-00001.sorted.merge.bam KPGP-00001_L*.sorted.bam |head -n 1000000 >1M_mpileup.txt

先看一下输出文件的大概格式(这个文件是之前用lane2的bam做的测试结果)


image.png

包括6列:
分别是:
染色体号、碱基位置、参考序列对应的碱基、比对上的reads数目(也就是depth)、比对的情况、比对的质量

命令中之所以加一个-f 参数就是为了提供参考序列fasta,使最终得到的结果文件的第3列是对应的碱基,如果不加,则变成了N,如下

image.png

既然加了参考序列,就序列提前对参考序列构建索引,软件要求的是faidx index。

回到正题
现在统计测序深度和GC含量的关系,理论上测序得到的reads 拼接的结果应该是和参考序列一致的,因此统计参考序列的GC含量实际上就是统计对应的测序本身的insert 片段的GC含量。然后与此同时统计测序的对应区间的测序深度的值,观察两者的关系。

python脚本如下

import sys
args=sys.argv
filename=args[1]
count_depth={}
count_base={}
count_number={}
count_all={}
with open (filename) as fh:
   for line in fh:
     lineL=line.strip().split("\t")
     chr_ID=lineL[0]
     base_position = int(lineL[1])
     window_position = int(base_position/1000)
     base=lineL[2]
     base.upper() #大写
     depth=int(lineL[3])
     chr_win=chr_ID+"   "+str(window_position)
     if chr_win not in count_base :
          count_base[chr_win]=0
    # if chr_win not in count_depth:      因为两个字典是按同一个key,所以这条可以省略                                                
          count_depth[chr_win]=0
          count_number[chr_win]=0
     if base=="G" or base=="C":
               count_base[chr_win]+=1

     count_depth[chr_win]+=depth
     count_number[chr_win]+=1
     count_all[chr_win]=str(count_base[chr_win])+'      '+str(count_depth[chr_win])+'   '+str(count_number[chr_win]) #把3个字典的value合并成一个字符串作为一个新的字典的value
for k,v in count_all.items():
   print(k,v,sep="\t")

这个脚本写的很长,我相信肯定改进的地方很大,但是这是我自己写的脚本,所以凑活用吧。

#总结一下:python字典计数的方式可大致分为两种写法
   # 1. if key not in dict:
   #          dict[key]=1 或者其他初始值
   #    else:
   #         dict[key]+=1


   # 2. if key not in dict:
   #          dict[key]='' 或者 0
   #    dict[key]+=1

   #两种用法虽然没什么大的差别,但是有的情况下,2能用的起来,而1不行或更麻烦,比如此脚本情况
   # 其实区别在于1中的if else,执行了if就不会执行else。而2中执行了if会继续执行下面的语句

python3 count.py 1M_mpileup.txt |sort -k2,2n >count_all.txt

head count_all.txt
---------------
chr1    9   0   3   1
chr1    10  0   425756  529
chr1    11  133 35354   952
chr1    12  600 46231   1000
chr1    13  575 41108   1000
chr1    14  582 51064   1000
chr1    15  537 30959   1000
chr1    16  541 28821   1000
chr1    17  621 51877   1000
chr1    18  537 34340   1000

-------------------------------------

第一列是染色体号,
第二列是对应的窗口第几个窗口(从10开始)
第三列是对应GC碱基数
第四列是总测序深度
第五列是每个窗口统计到的碱基总数

再分别计算一下GC%和mean depth就可以可视化了

在这之前还是先看看刚统计的结果,可以发现,以1000bp的窗口滑动,统计到的碱基数目并不为1000,有的甚至很低,其实这很容易理解。我的理解是,对于参考基因组,仍然是存在一些含N的重复序列,而这列序列在比对的过程中是不计算的,samtools mpileup 生成的文本中这部分就已经去除了,所以碱基的位置信息不是连续的。而脚本中1000bp是按碱基的位置信息除以1000取int来做的,所以统计到的碱基数目不一致是正常的

接下来给出可视化的R脚本:

library(ggplot2)
dt <- read.table("count.txt") #读入数据
#head(dt)
dt$GC <- dt$V3/dt$V5 #得到GC含量
dt$depth <-dt$V4/dt$V5 #得到平均的depth
dt <- dt[dt$GC>0,] #把GC等于0的部分去除
dt <- dt[dt$depth<100,] #把depth大于100的去除

lm_eqn <- function(x,y){
  
  m <- lm(y ~ x);
  
  eq <- substitute(italic(y) == a + b %.% italic(x)*","~~italic(r)^2~"="~r2,
                   
                   list(a = format(coef(m)[1], digits = 2),
                        
                        b = format(coef(m)[2], digits = 2),
                        
                        r2 = format(summary(m)$r.squared, digits = 3)))
  
  as.character(as.expression(eq));
  
}    #添加线性回归方程



p <- ggplot(dt, aes(x = GC, y = depth)) +xlim(c(0,0.8))+ylim(c(0,100))+
  geom_smooth(method = "lm", se=FALSE, color="black", formula = y ~ x)+
  geom_point()+geom_text(x=0.6,y=80,label = lm_eqn(dt$GC , dt$depth), parse = TRUE)+theme_bw()+theme(panel.grid = element_blank())

#作图

结果图如下


image.png

从这个结果看似乎是负相关,所以再取其他百万行的结果重复一遍,看看是否得到同样的结果

这是第2000000至3000000之间的图

image.png

负相关,不知道什么原因,先不去管它

Part4 去重复(或标记重复序列)

以上对比对的横向探索结束
接下来继续纵向走,下一步是
去重复(或标记重复序列)
这里用两种软件:samtools和picard分别处理
1.samtools
这里本来应该是用samtools的markdup来标记或去除PCR重复,本来脚本已经写好开始运行了,但是报错了
脚本如下

#!/bin/bash
dir1=~/WGS_new/output/bwa_mapping
dir2=~/WGS_new/output/bwa_mapping/Dup
for i in $(seq 1 6)
do
samtools markdup -r $dir1/KPGP-00001_L${i}.sorted.bam $dir2/KPGP-00001_L${i}.sorted.rm.bam && echo "rm KPGP-00001_L${i} done"
samtools markdup -S $dir1/KPGP-00001_L${i}.sorted.bam $dir2/KPGP-00001_L${i}.sorted.mk.bam && echo "mk KPGP-00001_L${i} done"
done

报错信息如下

[markdup] error: no ms score tag.
[markdup] error: no ms score tag.
[markdup] error: no ms score tag.
[markdup] error: no ms score tag.
[markdup] error: no ms score tag.
[markdup] error: no ms score tag.
[markdup] error: no ms score tag.

仔细看了一下说明书

Usage:  samtools markdup <input.bam> <output.bam>

Option: 
  -r           Remove duplicate reads
  -l INT       Max read length (default 300 bases)
  -S           Mark supplemenary alignments of duplicates as duplicates (slower).
  -s           Report stats.
  -T PREFIX    Write temporary files to PREFIX.samtools.nnnn.nnnn.tmp.
  -t           Mark primary duplicates with the name of the original in a 'do' tag. Mainly for information and debugging.
      --input-fmt-option OPT[=VAL]
               Specify a single input file format option in the form
               of OPTION or OPTION=VALUE
  -O, --output-fmt FORMAT[,OPT[=VAL]]...
               Specify output format (SAM, BAM, CRAM)
      --output-fmt-option OPT[=VAL]
               Specify a single output file format option in the form
               of OPTION or OPTION=VALUE
      --reference FILE
               Reference sequence FASTA FILE [null]
  -@, --threads INT
               Number of additional threads to use [0]

The input file must be coordinate sorted and must have gone through fixmates with the mate scoring option on.

最后一行说到,必须gone through fixmates with the mate scoring option on
所以需要先fixmate

samtools fixmate KPGP-00001_L1.sorted.bam KPGP-00001_L1.sorted.fix.bam

然而又报错了

[bam_mating_core] ERROR: Coordinate sorted, require grouped/sorted by queryname

bam文件需要按quername排序,而samtools默认是按position排序的,而原始的bam文件为了减少储存,已经被我删除了。。。。
所以这一步没办法做了,因而samtools markdup去重就不做了,直接用picard的吧

2.picard
这里用GATK4的中的picard

#!/bin/bash
dir1=~/WGS_new/output/bwa_mapping
dir2=~/WGS_new/output/bwa_mapping/GATK/Dup
for i in $(seq 1 6)
do
#将重复序列删除,注意--REMOVE_DUPLICATES=true
gatk MarkDuplicates  --REMOVE_DUPLICATES=true  -I $dir1/KPGP-00001_L${i}.sorted.bam  -M $dir2/KPGP-00001_L${i}.rm_metrics.txt -O $dir2/KPGP-00001_L${i}.rm.bam && echo "rm KPGP-00001_L${i} done"

#只是将重复标记,可以让后续软件识别,但是并没有删除
gatk MarkDuplicates -I $dir1/KPGP-00001_L${i}.sorted.bam  -M $dir2/KPGP-00001_L${i}.mk_metrics.txt -O $dir2/KPGP-00001_L${i}.mk.bam && echo "mk KPGP-00001_L${i} done"
done


这里先解释为什么要去除重复,这部分节选自解螺旋的矿工公众号

首先,我们需要先理解什么是重复序列,它是如何产生的,以及为什么需要去除掉?要回答这几个问题,我们需要再次理解在建库和测序时到底发生了什么。

我们已经知道,在NGS测序之前都需要先构建测序文库:通过物理(超声)打断或者化学试剂(酶切)切断原始的DNA序列,然后选择特定长度范围的序列去进行PCR扩增并上机测序。

因此,这里重复序列的来源实际上就是由PCR过程中所引入的。因为所谓的PCR扩增就是把原来的一段DNA序列复制多次。可是为什么需要PCR扩增呢?如果没有扩增不就可以省略这一步了吗?

情况确实如此,但是很多时候我们构建测序文库时能用的细胞量并不会非常充足,而且在打断的步骤中也会引起部分DNA的降解,这两点会使整体或者局部的DNA浓度过低,这时如果直接从这个溶液中取样去测序就很可能漏掉原本基因组上的一些DNA片段,导致测序不全。而PCR扩增的作用就是为了把这些微弱的DNA多复制几倍乃至几十倍,以便增大它们在溶液中分布的密度,使得能够在取样时被获取到。所以这里大家需要记住一个重点,PCR扩增原本的目的是为了增大微弱DNA序列片段的密度,但由于整个反应都在一个试管中进行,因此其他一些密度并不低的DNA片段也会被同步放大,那么这时在取样去上机测序的时候,这些DNA片段就很可能会被重复取到相同的几条去进行测序。看到这里,你或许会觉得,那没必要去除不也应该可以吗?因为即便扩增了多几次,不也同样还是原来的那一段DNA吗?直接用来分析对结果也不会有影响啊!难道不是吗?
会有影响,而且有时影响会很大!最直接的后果就是同时增大了变异检测结果的假阴和假阳率。主要有几个原因:
DNA在打断的那一步会发生一些损失,主要表现是会引发一些碱基发生颠换变换(嘌呤-变嘧啶或者嘧啶变嘌呤),带来假的变异。PCR过程会扩大这个信号,导致最后的检测结果中混入了假的结果;
PCR反应过程中也会带来新的碱基错误。发生在前几轮的PCR扩增发生的错误会在后续的PCR过程中扩大,同样带来假的变异;
对于真实的变异,PCR反应可能会对包含某一个碱基的DNA模版扩增更加剧烈(这个现象称为PCR Bias)。因此,如果反应体系是对含有reference allele的模板扩增偏向强烈,那么变异碱基的信息会变小,从而会导致假阴。
PCR对真实的变异检测和个体的基因型判断都有不好的影响。GATK、Samtools、Platpus等这种利用贝叶斯原理的变异检测算法都是认为所用的序列数据都不是重复序列(即将它们和其他序列一视同仁地进行变异的判断,所以带来误导),因此必须要进行标记(去除)或者使用PCR-Free的测序方案(这种方案目前正变得越来越流行,特别是对于RNA-Seq来说尤为重要,现在著名的基因组学研究所——Broad Institute,基本都是使用PCR-Free的测序方案)。


跑完上面的流程的结果如下:

image.png

可以看出只是标记重复的(mk)文件是要比去除重复(rm)文件要大的。

再看一下之前的bam 文件

image.png

很显然这两个处理后的文件都是要比原始文件要大的。

分别看看mk和rm生成的文件有什么不同

samtools view KPGP-00001_L1.mk.bam |head

结果如下


image.png
samtools view KPGP-00001_L1.rm.bam |head
image.png
samtools view KPGP-00001_L1.sorted.bam |head
image.png

很明显,相比原始bam文件,rm多了一些markduplicate的字符,所以文件变大了
而,相比rm文件,mk,在flag值一列变大了,所以mk比rm文件大,这些通过文件内容很容易看出来

从下一步开始就直接用mk文件

因为如果 MarkDuplicates 这步把重复去掉,则会对 mate 信息产生影响,可以考虑在这步之后加上 FixMateInformation。
但是如果只是 MarkDuplicates而没有去除重复,则不会对mate信息产生影响,理论上不需要 FixMateInformation这一步

这个可以在哪得到论证呢

我们可以看看上面对3个bam文件查看的内容,对比flag值
(荧光标出来的部分)

mk.bam rm.bam sort.bam
1187 99 163
99 163 99
1123 163 99
163 99 163
1123 99 99

image.png

image.png

image.png

结果显而易见

Part5 碱基质量重校正

先下载一些必备数据库

#!/bin/bash
wget ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz
wget ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/1000G_phase1.snps.high_confidence.hg38.vcf.gz.tbi
wget ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz
wget ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.tbi
wget ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/hapmap_3.3.hg38.vcf.gz
wget ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/hapmap_3.3.hg38.vcf.gz.tbi
wget ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/dbsnp_146.hg38.vcf.gz
wget ftp://gsapubftp-anonymous@ftp.broadinstitute.org/bundle/hg38/dbsnp_146.hg38.vcf.gz.tbi

结果如下

total 5.1G
-rw-rw-r-- 1 ubuntu ubuntu 1.8G Aug 11 00:52 1000G_phase1.snps.high_confidence.hg38.vcf.gz
-rw-rw-r-- 1 ubuntu ubuntu 2.1M Aug 11 01:07 1000G_phase1.snps.high_confidence.hg38.vcf.gz.tbi
-rw-rw-r-- 1 ubuntu ubuntu 3.2G Aug 11 03:04 dbsnp_146.hg38.vcf.gz
-rw-rw-r-- 1 ubuntu ubuntu 2.4M Aug 11 03:20 dbsnp_146.hg38.vcf.gz.tbi
-rw-rw-r-- 1 ubuntu ubuntu  837 Aug 10 23:17 download.sh
-rw-rw-r-- 1 ubuntu ubuntu  60M Aug 11 01:08 hapmap_3.3.hg38.vcf.gz
-rw-rw-r-- 1 ubuntu ubuntu 1.5M Aug 11 01:08 hapmap_3.3.hg38.vcf.gz.tbi
-rw-rw-r-- 1 ubuntu ubuntu  20M Aug 11 01:07 Mills_and_1000G_gold_standard.indels.hg38.vcf.gz
-rw-rw-r-- 1 ubuntu ubuntu 1.5M Aug 11 01:07 Mills_and_1000G_gold_standard.indels.hg38.vcf.gz.tbi

在此之前先把之前下载的hg38.fa构建dict,注意dict和之前的bwa构建的index不一样

cd /home/ubuntu/WGS_new/input/genome/new
nohup gatk CreateSequenceDictionary -R hg38.fa -O hg38.dict &

创建了字典之后就可以继续了

#!/bin/bash
snp=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource/dbsnp_146.hg38.vcf.gz
indel=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz
#dir1=~/WGS_new/output/bwa_mapping
dir2=~/WGS_new/output/bwa_mapping/GATK/Dup
#dir3=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/index
dir4=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource
dir5=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/recal

ref=~/WGS_new/input/genome/new/hg38.fa
for i in $(seq 1 6)
do
gatk BaseRecalibrator -R $ref -I $dir2/KPGP-00001_L${i}.mk.bam --known-sites $snp --known-sites $indel -O $dir5/KPGP-00001_L${i}.mk_recal.table
done

得到的table文件只是一个中间文件,还需要一步才能得到BQSR后的bam文件。

#!/bin/bash
snp=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource/dbsnp_146.hg38.vcf.gz
indel=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz
#dir1=~/WGS_new/output/bwa_mapping
dir2=~/WGS_new/output/bwa_mapping/GATK/Dup
#dir3=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/index
dir4=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource
dir5=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/recal

ref=~/WGS_new/input/genome/new/hg38.fa
#for i in $(seq 1 6)
#do
#gatk BaseRecalibrator -R $ref -I $dir2/KPGP-00001_L${i}.mk.bam --known-sites $snp --known-sites $indel -O $dir5/KPGP-00001_L${i}.mk_recal.table
#done



for i in $(seq 1 6)
do
gatk  ApplyBQSR -R $ref -I $dir2/KPGP-00001_L${i}.mk.bam -bqsr $dir5/KPGP-00001_L${i}.mk_recal.table -O $dir5/KPGP-00001_L${i}.mk_bqsr.bam
done

好了,到了这一步,利用生成的高质量的bam,接下来就是用4种工具来找变异,分别是GATK、bcftools、freebayes、varscan
再这之前先将各个lane生成的bam文件合并

nohup samtools merge KPGP-00001_bqsr.merge.bam *.bam 

Part6 找变异

1.GATK
先对上一步生成的merge的bam文件建立索引

 nohup samtools index KPGP-00001_bqsr.merge.bam &

然后是使用GATK的HaplotypeCaller

#!/bin/bash
snp=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource/dbsnp_146.hg38.vcf.gz
indel=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz
#dir1=~/WGS_new/output/bwa_mapping
dir2=~/WGS_new/output/bwa_mapping/GATK/Dup
#dir3=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/index
dir4=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource
dir5=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/recal
dir6=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/vcf

ref=~/WGS_new/input/genome/new/hg38.fa

gatk HaplotypeCaller -R $ref -I $dir5/KPGP-00001_bqsr.merge.bam --dbsnp $snp -O $dir6/KPGP-00001_bqsr.merge.vcf


2.bcftools

#!/bin/bash
snp=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource/dbsnp_146.hg38.vcf.gz
indel=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource/Mills_and_1000G_gold_standard.indels.hg38.vcf.gz
#dir1=~/WGS_new/output/bwa_mapping
dir2=~/WGS_new/output/bwa_mapping/GATK/Dup
#dir3=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/index
dir4=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource
dir5=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/recal
dir6=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/vcf

ref=~/WGS_new/input/genome/new/hg38.fa

samtools mpileup -ugf $ref $dir5/KPGP-00001_bqsr.merge.bam | bcftools call --thread 6 -v -m -O z  -o $dir6/KPGP-00001_bqsr.vcf.gz

最终用两个软件得到的vcf大小如下:


image.png

用GATK Ht得到的vcf大小为988M
用bcftools得到的大小为663M

Part7 简单的可视化比对文件和变异的结果

因为比对的bam文件太大了,导入IGV并不可取
所以可以简化一个就只看某个基因的变异情况
比如BRCA1

1.首先从gtf文件中得到BRCA1基因的坐标

从genecode下载的基因组的注释文件gtf

#注意gz文件不能直接grep
zcat gencode.v28.annotation.gtf.gz |grep "BRCA1"|grep -v "transcript_id"

#结果如下
chr17   HAVANA  gene    43044295    43170245    .   -   .   gene_id "ENSG00000012048.21"; gene_type "protein_coding"; gene_name "BRCA1"; level 2; tag "overlapping_locus"; havana_gene "OTTHUMG00000157426.14";

所以得到BRCA1的基因坐标为
chr17:43044295-43170245

2.从总的bam文件中提取BRCA1的bam文件
用samtools view来提取BRCA1的bam文件

samtools view -h KPGP-00001_bqsr.merge.bam chr17:43044295-43170245 |samtools sort -o BRCA1.bam -

#提取,再排序

再对生成的bam文件建立索引(IGV必须的步骤)

samtools index BRCA1.bam

3.提取BRCA1区间的vcf文件

grep "chr17        " KPGP-00001_bqsr.vcf |awk '{if ($2>43044295&&$2<43170245) {print $0;} }' >BRCA1_bcftools.vcf

grep "chr17        " KPGP-00001_bqsr.merge.vcf |awk '{if ($2>43044295&&$2<43170245) {print $0;} }' >BRCA1_gatk.vcf

可以先了解一下这2个vcf有什么不同

wc -l BRCA1_gatk.vcf
#282 BRCA1_gatk.vcf

wc -l BRCA1_bcftools.vcf
#271 BRCA1_bcftools.vcf

似乎是gatk比bcftools找的变异有一些不同

先找到不同变异的位置
python脚本如下

import sys
args=sys.argv
filename1=args[1]  #基准
filename2=args[2]  


Alist=[]
Blist=[]
for line in open (filename1):
   lineL=line.strip().split("\t")
   Alist.append(lineL[1])              #把bcftools中的position存到Alist中,注意不能用“+”这种添加方式

for line in open (filename2):
    lineL=line.strip().split("\t")
    pos=lineL[1]
    if pos not in Alist:
       Blist.append(pos)
for i in Blist:
   print(i)

找出gatk找到的,而bcf中没有的

python3 dis.py BRCA1_bcftools.vcf BRCA1_gatk.vcf


43045922
43046757
43050618
43054744
43067255
43077746
43079788
43098030
43098525
43102948
43106118
43111100
43112722
43112723
43112726
43112732
43112733
43112734
43112736
43112738
43114390
43118761
43123323
43128817
43133637
43142964
43149269
43155699
43166140


python3 dis.py BRCA1_bcftools.vcf BRCA1_gatk.vcf |wc -l
29

找出bcftools找到的,而GATK中没有的

python3 dis.py BRCA1_gatk.vcf BRCA1_bcftools.vcf


43050613
43050615
43052817
43067836
43077762
43086105
43089550
43089552
43090048
43100595
43100596
43102357
43104058
43104083
43123322
43142960
43142966
43166150


python3 dis.py BRCA1_gatk.vcf BRCA1_bcftools.vcf |wc -l
18

可见GATK和bcftools分别除了这29个和18个,剩下的253个变异的位点找到的是一致的
这些不同并不是最重要的,因为我们还没有对变异质控过滤

看几个共同的
bcftools的vcf


image.png

GATK的vcf


image.png

4.将BRCA1区间的bam文件导入IGV

43044391


image.png

43048520


image.png

43052360

image.png

以上就是对比对结果和变异结果的简单可视化

Part8 比对以及变异结果的质控

1.raw和clean的fastq文件都需要使用fastqc质控。
这个做过了
2.比对的各个阶段的bam文件都可以质控。
比对各个的阶段的bam文件都是可以质控的
这里因为我只还有bqsr后的merge的bam文件,所以就拿这个来做个测试
使用的工具是samtools的flagstat
nohup samtools flagstat KPGP-00001_bqsr.merge.bam >KPGP-00001_bqsr.merge.stat &

结果如下:
       1077675587 + 0 in total (QC-passed reads + QC-failed reads)
0 + 0 secondary
1460481 + 0 supplementary
88369576 + 0 duplicates
1073568441 + 0 mapped (99.62% : N/A)
1076215106 + 0 paired in sequencing
538107553 + 0 read1
538107553 + 0 read2
1047425796 + 0 properly paired (97.32% : N/A)
1068909862 + 0 with itself and mate mapped
3198098 + 0 singletons (0.30% : N/A)
12264590 + 0 with mate mapped to a different chr
6236962 + 0 with mate mapped to a different chr (mapQ>=5)

简单解读一下:
1077675587 是总的reads数
1460481 是supplementary(但这里指的是总的reads中不是pair-end的那部分reads数目)
88369576 是重复(虽然这个bam是做过去重步骤的,但是重复序列只是标记,没有remove,所以这里有是正常的)

1073568441 是指map上的总reads数,可见匹配率99.62%
1076215106 是指pair-end的reads数,基本上都是,总reads数减掉这个就是supplementary

538107553 + 0 read1
538107553 + 0 read2 双端测序两端的reads数目

1047425796指的是完美匹配的reads数目,完美匹配率也还是有97.32%

1068909862 指的是两端都匹配上的reads数目

3198098 指只有一端匹配上的reads数目

12264590 两端都匹配到不同的区域的reads

6236962 同上一个,只是其中比对质量>=5的reads的数量

3.使用qualimap对wes的比对bam文件总结测序深度及覆盖度。
关于对bam文件总结测序深度及覆盖度,前面已经自己专门写了脚本做了这件事

但是是有软件可以做这件事的,比如qualimap,这里就不重复了

4.变异结果的质控
质控的目的是指通过一定的标准,最大可能性的剔除假阳性的结果,并尽可能的保留最多的数据

对变异结果质控一般可以分为两种
第一种:软过滤
也就是使用GATK的VQSR,它使用机器学习的方法,利用多个不同数据的特征训练一个模型(高斯混合模型)对变异的结果进行质控
但是软过滤是有一定的条件的:
(1)需要一个精心准备的已知变异集合,作为训练质控模型的真集,比如:Hapmap,OMINI,1000G,dbsnp等这些国际性项目的数据
(2)要求新检测的结果中有足够多的变异,不然VQSR在进行模型训练时,会因为可用的变异位点数目不足而无法进行。
很多非人的物种在完成变异检测后,没法使用VQSR进行质控。同样的,一些小panel、外显子测序,由于最后的变异位点数目不够而无法进行VQSR。
全基因组分析或者多个样本的全外显子组分析可以使用此法。

第二种:硬过滤
简单的说就是对一些过滤指标一定的阈值,然后一刀切
主要涉及一下的一些过滤指标:
QualByDepth(QD):QD是变异质量值除以覆盖深度得到的比值
FisherStrand(FS):FS是一种通过Fisher检验得到的pValue转换而来的值,它描述的是在测序或者比对的时候,对只含有变异的read以及只含有参考序列碱基的read是否有明显的链特异性(strand bias)
StrandOddRatio (SOR):是对连特异性的一种描述
RMSMappingQuality(MQ):MQ这个值是所有比对到该位点上的read的比对质量值的均方根
MappingQualityRankSumTest(MQRankSum)
ReadPosRankSumTest (ReadPosRankSum)

                其实这六个指标也就是VQSR进行质控模型训练的指标,它可以在一定的程度上描述每个变异的质量,因此,使用这些指标来进行硬过滤在一定程度上是合理的。
                 现在的问题是:什么样的指标是合理的。
                 常用的指标是:
                   snp:
                    QD<2 || MQ<40 || FS>60 || SOR >3.0 ||MQRankSum <-12.5|| ReadPosRankSum<-8.0
                    Indel:
                      QD<2 || FS>200.0 || SOR >10.0 ||MQRankSum <-12.5|| ReadPosRankSum<-8.0
                     
                     至于为什么选择这个参数,**碱基矿工**在《GATK4.0和全基因组数据分析实践(下)》(https://mp.weixin.qq.com/s?__biz=MzAxOTUxOTM0Nw==&mid=2649798455&idx=1&sn=67a7407980a57ce138948eb46992b603&scene=21#wechat_redirect)已经说的很清楚了
                      其实简单的说就是用一些国际大项目的样本,查看样本VQSR前后的这些指标的分布,来确定阈值

这里给出我用GATK VQSR的脚本,我使用的是GATK4.0的版本

#!/bin/bash
#dir1=~/WGS_new/output/bwa_mapping
dir2=~/WGS_new/output/bwa_mapping/GATK/Dup
#dir3=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/index
dir4=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/resource
dir5=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/recal
dir6=/home/ubuntu/WGS_new/output/bwa_mapping/GATK/vcf
GATK_bundle=~/WGS_new/output/bwa_mapping/GATK/resource
ref=~/WGS_new/input/genome/new/hg38.fa

gatk VariantRecalibrator -R $ref -V $dir6/KPGP-00001_bqsr.merge.vcf\
                         -resource hapmap,known=false,training=true,truth=true,prior=15.0:$GATK_bundle/hapmap_3.3.hg38.vcf.gz\
                         -resource 1000G,known=false,training=true,truth=false,prior=10.0:$GATK_bundle/1000G_phase1.snps.high_confidence.hg38.vcf.gz\
                         -resource dbsnp,known=true,traning=false,truth=false,prior=6.0:$GATK_bundle/dbsnp_146.hg38.vcf.gz\
                         -an DP -an QD -an FS -an SOR -an ReadPosRankSum -an MQRankSum\
                         -mode SNP\
                         -tranches-file $dir6/KPGP-00001.GATK.snps.trache\
                         -tranche 100.0 -tranche 99.9 -tranche 99.0 -tranche 95.0 -tranche 90.0\
                         -rscript-file $dir6/KPGP-00001.GATK.snps.plots.R\
                         -O $dir6/KPGP-00001.GATK.snps.recal

gatk ApplyVQSR  \
     -R $ref \
     -V $dir6/KPGP-00001_bqsr.merge.vcf \
     -ts-filter-level 99.0 \
     -tranches-file $dir6/KPGP-00001.GATK.snps.trache\
     -recal-file $dir6/KPGP-00001.GATK.snps.recal\
     -mode SNP \
     -O $dir6/KPGP-00001.GATK.VQSR.snps.vcf.gz

因为INDEL mode没有跑成功,并不清楚原因,先不管他,后面就用SNP注释

关于硬过滤,这里给出用法

#SNP mode
#选出SNP
GATK SelectVariants -select-type SNP -v *.raw.vcf  -O *.snp.vcf
#对SNP 过滤
GATK VariantFiltration -V *.snp.vcf --filter-expression "QD<2 || MQ<40 || FS>60 || SOR >3.0 ||MQRankSum <-12.5|| ReadPosRankSum<-8.0" --filter-name "PASS"  -O *.snp.filter.vcf


#INDEL mode
#选出INDEL
GATK SelectVariants -select-type INDEL -v *.raw.vcf  -O *.indel.vcf
#对INDEL过滤
GATK VariantFiltration -V *.indel.vcf --filter-expression "QD<2 || FS>200.0 || SOR >10.0 ||MQRankSum <-12.5|| ReadPosRankSum<-8.0" --filter-name "PASS"  -O *.indel.filter.vcf

再看看VQSR的结果

grep -v "#"  KPGP-00001.GATK.VQSR.snps.vcf|wc -l

4565613

---------------------

grep "PASS"  KPGP-00001.GATK.VQSR.snps.vcf > KPGP-00001.GATK.VQSR.pass.snps.vcf

wc -l  KPGP-00001.GATK.VQSR.pass.snps.vcf

3252051 KPGP-00001.GATK.VQSR.pass.snps.vcf

可见,过滤了大约100多万的变异

Part9 变异的结果的注释
常用的注释软件有VEP、snpEFF、annovar

annovar注释
annovar是个perl编写的命令行工具,需要edu邮箱才能注册
annovar下载的时候会自带一些数据库存放在humandb文件夹中,但主要是hg19版本的,所以一般需要自己更新下载一些数据库

  1. 3种变异的注释方式
    (1)Gene-based Annotation(基于基因的注释):基于基因的注释解释了变异与已知基因的直接关系,以及对其产生的功能性的影响
    (2)Region-based Annotation(基于区域的注释):基于区域的注释看起来更像是一个区域的查询(这个区域可以是一个单一的位点),在一个数据库中,它不在乎位置的精确匹配,不在乎核苷酸的识别。基于区域的注释,揭示变异与不同基因组特定段的关系。例如:它是否落在已知的保守基因组区域。
    (3)Filter-based Annotation(基于过滤的注释):则给出这个变异的一系列信息,如: population frequency in different populations 和various types of variant-deleteriousness prediction scores,这些可被用来过滤掉一些公共的probably
    nondeleterious variants。filter-based和region-based的区别在于,filter-based针对mutation(核苷酸的变化),region-based针对染色体上的位置。如在全基因组数据中的变异频率,可以用1000g2015aug、kaviar_20150923等数据库;在全外显子组数据中的变异频率,可使用exac03、esp6500siv2_all等;在孤立或低代表人群中的变异频率可使用ajews等数据库。

2.对应注释方式的数据库下载
这3种注释方式即可以分别进行,也可以同时进行,无论哪种方式,对应方式的数据库都是需要下载的。
(1)gene-based annotation:
refGene

 annotate_variation.pl -downdb -buildver hg38 -webfrom annovar refGene humandb/

(2)region-based annotation:
保守基因组元件注释:
phastConsElements46way

 annotate_variation.pl -downdb -buildver hg38 -webfrom annovar  phastConsElements46way humandb/

转录因子结合位点注释:
tfbsConsSites

annotate_variation.pl -downdb -buildver hg38 -webfrom annovar  tfbsConsSites humandb/


细胞遗传学区段(cytogenetic band):
cytoBand

annotate_variation.pl -downdb -buildver hg38 -webfrom annovar cytoBand  humandb/

Identify variants disrupting microRNAs and snoRNAs:
wgRna

annotate_variation.pl -downdb -buildver hg38 -webfrom annovar wgRna  humandb/

.
.
.
.
.
等等,具体更多的可以查看Annovar documentation

(3)filter-based annotation:
由于这一类注释方式的数据库实在太多了,Annovar官方给了总结如下:

For frequency of variants in whole-genome data:

1000g2015aug: latest 1000 Genomes Project dataset with allele frequencies in six populations including ALL, AFR (African), AMR (Admixed American), EAS (East Asian), EUR (European), SAS (South Asian). These are whole-genome
variants.

kaviar_20150923: latest Kaviar database with 170 million variants from 13K genomes and 64K exomes.

hrcr1: latest Haplotype Reference Consortium database with 40 million variants from 32K samples in haplotype reference consortium

cg69: allele frequency in 69 human subjects sequenced by Complete Genomics. useful to exclude platform specific variants.

gnomad_genome: allele frequency in gnomAD database whole-genome sequence data on multiple populations.

For frequency of variants in whole-exome data:

exac03: latest Exome Aggregation Consortium dataste with allele frequencies in ALL, AFR (African), AMR (Admixed American), EAS (East Asian), FIN (Finnish), NFE (Non-finnish European), OTH (other), SAS (South Asian).

esp6500siv2: latest NHLBI-ESP project with 6500 exomes. Three separate key words are used for 3 population groupings: esp6500siv2_all, esp6500siv2_ea, esp6500siv2_aa.

gnomad_exome: allele frequency in gnomAD database whole-exome sequence data on multiple populations.

For frequency of variants in isolated or less represented populations:
ajews: common alleles in ashkenazi jews

TMC-SNPDB: common alleles in Indian populations

gme: GME (Greater Middle East Variome) allele frequency, including ALL, NWA (northwest Africa), NEA (northeast Africa), AP (Arabian peninsula), Israel, SD (Syrian desert), TP (Turkish peninsula) and CA (Central Asia).
???: I strongly encourage ANNOVAR users to donate your own allelel frequency database on isolated/special populations to be shared to worldwide users

For functional prediction of variants in whole-genome data:

gerp++: functional prediction scores for 9 billion mutations based on selective constraints across human genome. You can optionally use gerp++gt2 instead since it includes only RS score greater than 2, which provides high sensitivity while still strongly enriching for truly constrained sites

cadd: Combined Annotation Dependent Depletion score for 9 billion mutations. It is basically constructed by a support vector machine trained to differentiate 14.7 million high-frequency human-derived alleles from 14.7 million simulated variants, using ~70 different features. For known indels, use caddindel.

cadd13: CADD version 1.3.

dann: functional prediction score generated by deep learning, using the identical set of training data as cadd but with much improved performance than cadd.

fathmm: a hidden markov model to predict the functional importance of both coding and non-coding variants (that is, two separate scores are provided) on 9 billion mutations.

eigen: a spectral approach integrating functional genomic annotations for coding and noncoding variants on 9 billion mutations, without labelled training data (that is, unsupervised approach)

gwava: genome-wide annotation of variants that supports prioritization of noncoding variants by integrating various genomic and epigenomic annotations on 9 billion mutations.

For functional prediction of variants in whole-exome data:

dbnsfp30a: this dataset already includes SIFT, PolyPhen2 HDIV, PolyPhen2 HVAR, LRT, MutationTaster, MutationAssessor, FATHMM, MetaSVM, MetaLR, VEST, CADD, GERP++, DANN, fitCons, PhyloP and SiPhy scores, but ONLY on coding variants

For functional prediction of splice variants:

dbscsnv11: dbscSNV version 1.1 for splice site prediction by AdaBoost and Random Forest, which score how likely that the variant may affect splicing

spidex: deep learning based prediction of splice variants. Unlike dbscsnv11, these variants could be far away from canonical splice sites

For disease-specific variants:
clinvar_20160302: ClinVar database with separate columns (CLINSIG CLNDBN CLNACC CLNDSDB CLNDSDBID) for each variant (Please check the download page for the latest version, or read below for creating your own most updated version)

cosmic70: the latest COSMIC database with somatic mutations from cancer and the frequency of occurence in each subtype of cancer. For more updated cosmic, see instructions below on how to make them.

icgc21: International Cancer Genome Consortium version 21 mutations.

nci60: NCI-60 human tumor cell line panel exome sequencing allele frequency data

For variant identifiers:

snp142: dbSNP version 142

avsnp142: an abbreviated version of dbSNP 142 with left-normalization by

ANNOVAR developers. (Please check the download page for the latest version)

3.分别进行3种注释方式的代码和同时进行3种注释方式的代码

分别的:
以gene-based annotation为代表:

 convert2annovar.pl  -format vcf4old   ~/WGS_new/output/bwa_mapping/GATK/vcf/KPGP-00001.GATK.VQSR.pass.snps.vcf  >~/WGS_new/output/bwa_mapping/GATK/vcf/KPGP-00001.GATK.VQSR.pass.snps.annovar


annotate_variation.pl -buildver hg38  --outfile ~/WGS_new/output/bwa_mapping/GATK/vcf/KPGP-00001.GATK.VQSR.pass.snps.anno ~/WGS_new/output/bwa_mapping/GATK/vcf/KPGP-00001.GATK.VQSR.pass.snps.annovar humandb

其他的可以参考annovar的说明书:

#download annotation databases from ANNOVAR or UCSC and save to humandb/ directory
              annotate_variation.pl -downdb -webfrom annovar refGene humandb/
              annotate_variation.pl -buildver mm9 -downdb refGene mousedb/
              annotate_variation.pl -downdb -webfrom annovar esp6500siv2_all humandb/
        
              #gene-based annotation of variants in the varlist file (by default --geneanno is ON)
              annotate_variation.pl -buildver hg19 ex1.avinput humandb/
          
              #region-based annotate variants
              annotate_variation.pl -regionanno -buildver hg19 -dbtype cytoBand ex1.avinput humandb/
              annotate_variation.pl -regionanno -buildver hg19 -dbtype gff3 -gff3dbfile tfbs.gff3 ex1.avinput humandb/
          
              #filter rare or unreported variants (in 1000G/dbSNP) or predicted deleterious variants
              annotate_variation.pl -filter -dbtype 1000g2015aug_all -maf 0.01 ex1.avinput humandb/
              annotate_variation.pl -filter -buildver hg19 -dbtype snp138 ex1.avinput humandb/
              annotate_variation.pl -filter -dbtype dbnsfp30a -otherinfo ex1.avinput humandb/

得到的结果如下:


image.png

首先看一下全基因组范围的:


image.png

第一列包含的值有:


image.png

再重点看一下外显子区域的:


image.png

简单解释一下红色线画出的部分:
这是一个非同义突变(DNA 片 段中有时某个碱基对的突变改变所编码 氨基酸的改变)的SNV,发生在NOC2L这个基因上,gene ID 是NM_015658,这个变异发生在该基因的第9个exon上面,A变成G,蛋白方面是氨基酸I变成V,这是一个纯和的变异

同时进行的:

nohup table_annovar.pl ~/WGS_new/output/bwa_mapping/GATK/vcf/KPGP-00001.GATK.VQSR.pass.snps.annovar ~/soft/annovar/humandb/ -buildver hg38 -out anpanno -remove -protocol refGene,cytoBand,dbnsfp30a,EAS.sites.2015_08,avsnp142 -operation g,r,f,f,f -nastring . -csvout &

在这里,filter-based annotation选择了3个数据库,分别是
dbnsfp30a
1000g2015aug(EAS.sites.2015_08)
avsnp142

其中avsnp142是dbSNP数据库的简单版
1000g2015aug(EAS.sites.2015_08):千人基因组计划,这里使用的EAS,也就是东亚人群的数据库,因为我是在韩国个人基因组计划中下载的数据,所以使用的是东亚的数据库。
dbnsfp30a:这个数据库包括了IFT, PolyPhen2 HDIV, PolyPhen2 HVAR, LRT, MutationTaster, MutationAssessor, FATHMM, MetaSVM, MetaLR, VEST, CADD, GERP++, DANN, fitCons, PhyloP and SiPhy scores,通过评分,用于判断变异是不是有害的变异。这些分值只针对编码区的基因。

image.png

所以接下来要做的就是先过滤掉千人基因组计划和dbsnp中含有的变异(这并不合理,但是突变实在太多,只是作为观察的对象,或者说这部分是我感兴趣的)
然后用dbnsfp来判断变异是否有害

得到的结果中居然没有千人基因组计划数据库中变异,所以还是按dbsnp数据库进行过滤
由于全基因组的变异实在太多,这里就只把外显子区域的变异提取出来单独看,并且只保留非同义突变

grep '"exonic"' anpanno.hg38_multianno.csv |grep '"nonsynonymous SNV"' >anpanno.hg38_multianno.exon.nonsynonymous.csv

然后是过滤掉dbsnp中已经有的突变

import sys
args=sys.argv
filename=args[1]

with open (filename) as fh:
  for line in fh:
    if line.startswith("C"):
       print(line)
    lineL=line.strip().split(",")
    if lineL[-1]==".":
        print(line)

python3 ex.py anpanno.hg38_multianno.exon.nonsynonymous.new.csv >exon.nonsynonymous.filter.csv
wc -l exon.nonsynonymous.filter.csv
472 exon.nonsynonymous.filter.csv

这样最终得到472个变异

将文件导入R,并筛选

data <- read.csv("exon.nonsynonymous.filter.csv")
data <- data[data$SIFT_pred=="D",]
data <- data[data$Polyphen2_HDIV_pred=="D",]
data <- data[data$PROVEAN_pred=="D",]
data <- data[data$LRT_pred=="D",]
data <- data[data$fathmm.MKL_coding_pred=="D",]
data <- data[data$MetaLR_pred=="D",]
data <- data[data$MetaSVM_pred=="D",]
data <- data[data$FATHMM_pred=="D",]
data <- data[data$Polyphen2_HVAR_pred=="D",]
data <-data[,c("Chr","Start","End","Ref","Alt","Func.refGene","Gene.refGene","AAChange.refGene")]

最终得到这些指标一致认为有害的变异有5个


image.png

到此,整个WGS的流程的简单的学习算暂时结束,下游分析其实还有太多更复杂的地方,所以需要学习的地方还有很多很多
慢慢努力,一步一个脚印

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容