CNV 检测
临床遗传全外显子一般需要分析"外显子"和"大片段"两个水平。按照以往逻辑,会使用XHMM、ExomeDepth等工具,但我个人是All In CNVkit的。
基线准备
从既往经验来说,使用同批次产生的同性别数据作为基线样本,会有较好的表现(一般需要≥8个样本)。
但是显然,这对于样本量少的公司,无法实现。而且,这样做对于后台流程也会比较复杂。因此,我们还是采取固定基线的方法,采取若干的正常表型数据及格的样本进行CNV基线建立。建议男女性样本各20个。
当然,由于这次我们使用的是公共数据,因此只能虚空演示。
首先是窗口划分,与WGS、CNV-seq等划分固定大小的窗口(bins)的方式不同,WES建议以外显子进行窗口划分,即每个bins实际是不同大小的。这样做的好处是最终我们可以去评估单个外显子水平的CNV;后面也可以对窗口进行segment,从而获得大片段水平的CNV。
显然,我们需要先去获得一个外显子的bed。
外显子bed
这里基于Gencode来制作一个GRCh38的外显子bed。首先下载gff文件(GRCh37可以通过Gencode下载)
wget https://ftp.ncbi.nlm.nih.gov/refseq/MANE/MANE_human/release_1.3/MANE.GRCh38.v1.3.refseq_genomic.gff.gz
gunzip MANE.GRCh38.v1.3.refseq_genomic.gff.gz
然后处理为bed格式
output_bed = open("GRCh38.NCBI.ManeSelect.Exon.bed", "w", encoding="utf-8")
output_bed.write("#Chrom\tStart\tEnd\tRegion\tGene\tEnsembl\tRefseq\tStrand\n")
with open("MANE.GRCh38.v1.3.refseq_genomic.gff", "r") as f:
for line in f:
if line.startswith("#"):
continue
ensembl = refseq = "."
exon_id = "exon1"
gene = ""
lines = line.rstrip().split("\t")
if (lines[2] == "exon") and ("tag=MANE Select" in line):
info_fields = lines[8].split(";")
for i in info_fields:
if i.startswith("Dbxref"):
dbxrefs = i.lstrip("Dbxref=").split(",")
for d in dbxrefs:
if d.startswith("Ensembl:"):
ensembl = d.split("Ensembl:")[1]
elif i.startswith("transcript_id="):
refseq = i.split("transcript_id=")[1]
elif i.startswith("ID=exon-"):
exon_id = "exon" + i.split("-")[-1]
elif i.startswith("gene="):
gene = i.split("gene=")[1]
output_list = [lines[0], lines[3], lines[4], exon_id, gene, ensembl, refseq, lines[6]]
output_bed.write("\t".join(output_list) + "\n")
output_bed.close()
最后,建议使用bedtools进行一次merge,用以去掉一些同源重复区域。
bedtools merge -i GRCh38.NCBI.ManeSelect.Exon.bed > GRCh38.NCBI.ManeSelect.Exon.merge.bed
CNVKit分析流程
CNVKit的分析分为几个步骤:首先生成antitarget区域,然后分别计算target和antitarget的覆盖度,最后合并生成结果。
生成antitarget区域
antitarget是靶向区域之间的区域,用于估计背景噪声。需要排除不可映射区域:
# 获取可访问区域,排除不可映射区域
cnvkit.py access GRCh38.d1.vd1.fa -x hg38_excludeble.bed -o access.bed
# 生成antitarget区域
cnvkit.py antitarget target.bed -g access.bed -o SRR14724513.antitarget.bed
计算覆盖度
分别计算target和antitarget区域的覆盖度,使用 -p 参数指定并行线程数:
# target覆盖度
cnvkit.py coverage bam/SRR14724513.markdup.bam target.bed \
-o SRR14724513.targetcoverage.cnn -p 16
# antitarget覆盖度
cnvkit.py coverage bam/SRR14724513.markdup.bam SRR14724513.antitarget.bed \
-o SRR14724513.antitargetcoverage.cnn -p 16
合并结果
使用预先构建好的参考基线,将target和antitarget的覆盖度合并:
cnvkit.py fix \
SRR14724513.targetcoverage.cnn \
SRR14724513.antitargetcoverage.cnn \
cnvkit_reference.cnn \
-o SRR14724513.cnvkit.cnr
.cnr文件包含了每个bin的log2 ratio值,是后续CNV判断的基础。
外显子水平
CBS基因水平分割
在得到CNVKit的.cnr文件后,使用CBS(Circular Binary Segmentation)算法在基因水平上进行分割,评估每个基因的拷贝数状态:
python3 gene_level_segment.py \
-i SRR14724513.cnvkit.cnr \
-o SRR14724513.cnv.gene.txt \
--cn-del-threshold 1.5 \
--cn-dup-threshold 2.5
CBS算法会将连续的bins按照log2 ratio的显著变化点进行分段,然后对每段计算平均拷贝数。--cn-del-threshold和--cn-dup-threshold用于定义拷贝数变异的阈值:
- CN < 1.5:缺失(Deletion)
- CN > 2.5:重复(Duplication)
- 1.5 ≤ CN ≤ 2.5:正常
报告会包含每个基因的拷贝数估计、置信度评分、变异类型等信息。
大片段水平
窗口合并
为了获得大片段水平的CNV,需要将小的外显子bins合并为固定大小的窗口(如20kb),然后在窗口水平上进行评估:
python3 merge_bins_for_cnv.py \
-i SRR14724513.cnvkit.cnr \
-o SRR14724513.cnv.region.txt \
--del-threshold 1.5 \
--dup-threshold 2.5 \
--bin-size 20000 \
--keep-antitarget
--bin-size 20000指定合并后的窗口大小为20kb。--keep-antitarget保留antitarget区域的信息用于辅助判断。合并时使用加权平均,权重为每个bin的probe数量。
常见的窗口大小选择:
- 10kb:较细粒度,适合检测较小的CNV
- 20kb:平衡粒度,推荐默认值
- 50kb:较粗粒度,适合检测大片段CNV
CNV注释
使用CNVAnno对检出的CNV进行基因注释:
python3 cnvanno.py \
SRR14724513.cnv.gene.txt \
-d /app/CNVAnno/data \
-g GRCh38 \
-f tsv \
-o SRR14724513.cnvanno.txt
CNVAnno会将CNV区域与基因数据库进行比对,注释受影响的基因及其关联的疾病信息。也可以使用在线工具AutoCNV进行辅助分析。
实际上CNV的ClinGen规则判定受主观因素影响,建议有能力的可以自行根据ClinGen规则搭建适用于自己的注释流程。