Hemberg-lab单细胞转录组数据分析(一)
Hemberg-lab单细胞转录组数据分析(二)
收藏|北大生信平台"单细胞分析、染色质分析"视频和PPT分享
生信老司机以中心法则为主线讲解组学技术的应用和生信分析心得 - 限时免费
scRNA-seq原始数据加工
FastQC
得到单细胞RNA-seq测序数据后,首先检查测序reads的质量。为了完成这个任务,我们使用的工具是FastQC。FastQC是一款质控工具,能对bulk RNA-seq和单细胞RNA-seq的原始数据进行质量控制 (其他类型的高通量测序结果也适用)。FastQC以原始测序reads为输入(fastq格式),输出序列质量报告。复制粘贴下面的链接到你的浏览器进入FastQC官网:
https://www.bioinformatics.babraham.ac.uk/projects/fastqc/
这个网址包含下载和安装FastQC及示例报告文件的链接。向下滚动页面到Example Reports
并点击Good Illumina Data
,会看到高质量Illumina测序Reads的理想质控结果。如果使用Docker
镜像,则FastQC已经安装好。如果是自己的服务器,FastQC下载下来即可使用(依赖于Java
)。生信宝典的推文NGS基础 - FASTQ格式解释和质量评估对FASTQ原始数据和FastQC的使用和结果描述有比较详细的介绍,如果不熟悉,建议阅读。
现在让我们自己来做一个FastQC报告。
今天我们会用一个mESC数据集 [@kim_characterizing_2015] (原文档文献引用错误,有更新)的单细胞测序结果为例做后续分析。细胞使用SMART-seq2
方法构建测序文库并进行双端测序。这些文件在Share
文件夹下。
注意: 当前课程教案是写给线下参加我们课程的学员,程序和数据都已放置在特定位置。如果您只是跟着教程学习,需要自己配置服务器和原始数据文件,比如下载文件(ERR522959_1.fastq
和ERR522959_2.fastq
)并放置到Share
(注意大小写)目录。在EBI的ArrayExpress搜索E-MTAB-2600
获取数据下载链接:https://www.ebi.ac.uk/arrayexpress/experiments/E-MTAB-2600/。
NCBI SRA: NGS基础 - 测序原始数据下载查看如何从NCBI下载原始测序数据。
现在让我们来看看文件 (基本Linux命令见免费Linux系统和生信宝典原创学习教程):
# 很常用的查看文件的命令
# 按 q 退出,空格翻页
# 更多见上面的链接
less Share/ERR522959_1.fastq
less Share/ERR522959_2.fastq
任务1:尝试找到可以生成FastQC报告的命令。提示:尝试执行
# program -h 或 program --help是最常用的获取帮助信息的命令 (通常一个短线后面跟单个字母称为短参数,两个短线后面跟数个单词称为长参数)
# program -help 或 program 或program -?也是偶尔会用到的获取帮助信息的命令,不常用但有,比如blastn -help, samtools -?
fastqc -h
这个命令会告诉你FastQC有哪些选项可以设置。如果您看明白了输出,也就应该知道如何用FastQC进行质控了。运行成功后,正向和反向reads都会获得一个 .zip
和.html
。如果成功了,跳到下一部分吧。
解决方案和下载报告
如果还没成功,可以用下面的命令生成FastQC报告:
# 一般加-p,文件夹存在也不会报错
# man mkdir查看下-p是什么意思
mkdir -p fastqc_results
fastqc -o fastqc_results Share/ERR522959_1.fastq Share/ERR522959_2.fastq
命令执行完成后,可以得到四个文件—每端reads对应一个zip
文件和一个html
文件。报告在html文件里,我们可以用filezilla
或者scp
把它从服务器下载到你的电脑上来查看它。如果使用的是Rstudio,在右下角窗口直接打开查看即可。
大概浏览一下文件,记住要看双端reads
的报告!什么样的reads质量好呢?有什么我们需要在意的问题呢?我们该怎么解决这些问题?更多请阅读生信宝典的推文NGS基础 - FASTQ格式解释和质量评估一文。
如果文件很多,一个个看比较麻烦,可以试试整合QC质控结果的利器——MultiQC。
移除接头和低质量碱基
TrimGalore!
工具是对cutadapt
软件的封装,用于移除测序接头序列或测序序列末端低质量碱基。
鉴于上一步FastQC报告中有一些接头污染,因此需要去除接头部分。看下NGS基础 - 高通量测序原理,想想什么时候会有接头产生?
任务2:我们的测试数据中出现了哪种类型接头?提示:看一下FastQC报告中的Adapter Content
部分。
现在让我们尝试用Trim Galore!
去除那些麻烦的接头序列,去除接头后,最好再运行FastQC查看接头是否去除干净。
任务3:尝试自己写出去接头的命令 提示1:你可以用
# program -h 或 program --help是最常用的获取帮助信息的命令 (通常一个短线后面跟单个字母称为短参数,两个短线后面跟数个单词称为长参数)
# program -help 或 program 或program -?也是偶尔会用到的获取帮助信息的命令,不常用但有,比如blastn -help, samtools -?
# 查看帮助一定要学会
trim_galore -h
查看下Trim Galore
的参数描述。
提示2:仔细阅读上面命令的执行结果 (在最开始使用每个软件前,都需要仔细阅读其帮助文档),鉴于序列中出现的接头十分常见,你觉得去除接头时需要知道接头具体序列吗?
任务3:对trimmed reads
进行再次FastQC质控分析,接头序列都去除干净了吗?
一旦你觉得已经成功去除接头序列并用FastQC评估确认了,你可以在下一节核对你的结果。
解决方案
你可以用下面的命令来去除Nextera
序列接头:
# 注意路径问题
mkdir -p fastqc_trimmed_results
trim_galore --nextera -o fastqc_trimmed_results Share/ERR522959_1.fastq Share/ERR522959_2.fastq
记住为trimmed reads
文件生成新的FastQC报告!在报告里应该可以看到你的reads的Adaptor Content
结果为PASS
了。
祝贺!现在已经生成了reads质量报告并实行了接头去除,下一步,我们会用STAR
(STAR有soft-clip机制,理论上只要文库质量不太差,不进行质控也可以)和Kallisto
把质控后的reads比对到参考转录组。
文件格式
生信宝典的生信分析过程中这些常见文件的格式以及查看方式你都知道吗?有比较详细的介绍,建议跟下面的内容结合着看。
FastQ
FastQ是scRNASeq
数据中最原始数据的格式。所有的scRNA-seq
方案都会进行双端测序,根据文库构建方法不同,条形码序列 (barcodes)可能出现在测序的左端或右端序列。但是使用唯一分子标签 (UMIs)的测序方案会产生包含细胞和UMI barcode
再加接头序列但没有转录本序列的reads
。因此reads虽然是双端测序,但比对时按单端reads对待。
FastQ文件格式如下 (NGS基础 - FASTQ格式解释和质量评估对FASTQ原始数据有比较详细的介绍,如果不熟悉,建议阅读):
>ReadID
READ SEQUENCE
+
SEQUENCING QUALITY SCORES
BAM
BAM文件是存储比对结果的标准有效的高度压缩的二进制格式,其文本格式SAM
是直接可读的。BAM/SAM文件包含一个头部,记录样本准备、测序和比对的信息;后面是每个reads的比对结果,tab
作为列分隔符。
比对行有下列标准格式:
QNAME:read编号(如果是UMI文库,通常包含UMI条形码)
FLAG:数字标记指示reads比对的”类型”,如reads是否比对上,是否为
properly paired
等,Picard网站可以在”类型”和对应的数字之间进行转换,有更详细阐述。RNAME:参考序列编号(比如比对到的染色体名字)。
POS:最左边的比对位置。
MAPQ:比对质量
CIGAR:表示reads的匹配/不匹配部分 (可能包括soft-clipping)
RNEXT:mate/next reads比对到的参考序列编号
PNEXT:mate/next reads比对到的第一个碱基位置
TLEN:模板长度(read比对到的参考区域的长度)
SEQ:read序列信息
QUAL:read质量信息
BAM/SAM文件可以用samtools
互相转换。
# 新版本samtools中-S选项忽略,不需要再加,会自己判断输入的是bam还是sam格式
samtools view -S -b file.sam > file.bam
# -h:包含header
samtools view -h file.bam > file.sam
一些测序服务机构会自动把测序reads比对到标准基因组并提供BAM
或CRAM
格式文件,通常这些基因组不会包含ERCC
序列,继而不会有ERCC reads
比对到BAM/CRAM
文件中。为了量化ERCCs
(或序列有任何其他遗传变异或外源表达需要考虑时),或者如果想使用不同于标准流程(通常是过时的流程,所以要参加易生信单细胞转录组专题培训)中的比对算法,那你需要把BAM/CRAM
文件转回FastQ
:
bedtools
可以把BAM
文件转成FastQ
,为了避免把比对到多个基因组位置的同一个reads转换为FASTQ中的多条reads,需要先把BAM文件按read名称排序,并使用Samtools删除次级比对 (secondary alignments
)。此外Picard里也有把BAM
转成FastQ
文件的方法。
# sort reads by name (-n)
samtools sort -n original.bam -o sorted_by_name.bam
# remove secondary alignments (-F 256)
samtools view -b -F 256 sorted_by_name.bam -o primary_alignment_only.bam
# convert to fastq
bedtools bamtofastq -i primary_alignment_only.bam -fq read1.fq -fq2 read2.fq
bedtools是高通量测序分析的常用工具集,Bedtools使用简介有一些介绍,可以了解下。
CRAM
CRAM文件与BAM文件类似,只是header中包含比对用到的参考基因组的信息。这使得每个read中与参考基因组相同的碱基可以被进一步压缩。CRAM也支持一些有损数据压缩方式来进一步优化储存,CRAMs格式主要是Sanger/EBI测序机构在使用。
CRAM和BAM文件可以用最新一版的samtools(>=v1.0)
相互转换。然而这个转换需要预先下载并缓存参考基因组。可以从CRAM文件的头部元数据中获得参考基因组信息自行下载,具体按下面的操作进行转换:
# 设置环境变量,指定基因组文件放置的位置
export REF_CACHE=/path_to/cache_directory_for_reference_genome
# -T后面直接跟基因组文件名字;如果上一步没设置,直接给全路径也可以
samtools view -b -h -T reference_genome.fasta file.cram -o file.bam
samtools view -C -h -T reference_genome.fasta file.bam -o file.cram
手动查看文件
一些时候,需要自己查看文件 (初学时,一定多看看这些文件格式,理解每一部分的含义和参数的使用),比如查看下文件的header
信息是否正确。less
和more
可以用来在命令行查看任意大小文本文件 (个人更常用less
)。管道符|
可以在多个命令之间传输数据,省却把中间数据存储多个拷贝的过程,既简洁又快速。具体见生信宝典出品的Linux - 管道、标准输入输出教程。
less file.txt
more file.txt
# counts the number of lines in file.txt
wc -l file.txt
samtools view -h file.[cram/bam] | more
# counts the number of lines in the samtools output
samtools view -h file.[cram/bam] | wc -l
练习
假如你已经有了一个小的cram
格式文件:EXAMPLE.cram
任务1:这个文件是怎么获得的?用了什么比对软件?基因组的版本是什么?(提示:检查头部文件)
任务2: 有多少reads比对或没比对上?文件共有多少短序列?
secondary alignments
有多少?(提示:用FLAG)任务3:将CRAM格式转成Fastq文件。转换后的每条read都是只有一个拷贝吗?(转换后的文件命名为
10cells_read1.fastq
10cells_read2.fastq
)
小技巧:如果运行某个软件的帮助命令卡住时,直接输入命令,看看有无提示信息?
答案
samtools view -T 2000_reference.transcripts.fa -H EXAMPLE.cram | less
samtools view -T 2000_reference.transcripts.fa -f 4 EXAMPLE.cram | wc -l # unmapped
samtools view -T 2000_reference.transcripts.fa -F 260 EXAMPLE.cram | wc -l # mapped
samtools view -T 2000_reference.transcripts.fa -F 256 EXAMPLE.cram | wc -l # total
samtools view -T 2000_reference.transcripts.fa -f 256 EXAMPLE.cram | wc -l # secondary alignments
samtools view -b -h -T 2000_reference.transcripts.fa EXAMPLE.cram -o EXAMPLE.bam
samtools sort -n EXAMPLE.bam -o sorted_EXAMPLE.bam
samtools view -b -F 256 sorted_EXAMPLE.bam -o primary_EXAMPLE.bam
# convert to fastq
bedtools bamtofastq -i primary_EXAMPLE.bam -fq 10cells_read1.fq -fq2 10cells_read2.fq
基因组和基因注释(FASTA,GTF)
为了进行序列比对,需要参考基因组和/或基因组注释文件(GTF
格式或GFF
格式)。模式生物的基因组可以从任何主要的数据库下载:Ensembl, NCBI,或者UCSC Genome Browser。具体操作见NGS基础 - 参考基因组和基因注释文件。
GTF文件有基因、转录本和外显子的注释 (NGS基础 - GTF/GFF文件格式解读和转换中描述更详细具体),一个9列的文件:
seq_id:序列的编号,一般为chr或scafold编号;
source: 注释的来源,一般为数据库或者注释的机构,如果未知,则用点
.
代替;type: 注释信息的类型,比如Gene、cDNA、mRNA、CDS等;
start: 该基因或转录本在参考序列上的起始位置 (从1开始,包含);
end: 该基因或转录本在参考序列上的终止位置 (从1开始,包含);
score: 得分,数字,是注释信息可能性的说明,可以是序列相似性比对时的E-values值或者基因预测是的P-values值,
.
表示为空;strand: 该基因或转录本位于参考序列的正链(+)或负链(-)上;
phase: 仅对注释类型为
CDS
有效,表示起始编码的位置,有效值为0,1,2
。(对于编码蛋白质的CDS来说,本列指定下一个密码子开始的位置。每3个核苷酸翻译一个氨基酸,从0开始,CDS的起始位置,除以3,余数就是这个值,表示到达下一个密码子需要跳过的碱基个数。0
表示该编码框的第一个密码子第一个碱基位于其5’末端;1
表示该编码框的第一个密码子的第一个碱基位于该编码区外;2
表示该编码框的第一个密码子的第一、二个碱基位于该编码区外;);attributes: 一个包含众多属性的列表,格式为
标签 值
(tag value
),以多个键值对组成的注释信息描述,键与值之间用`` (空格分割),不同的键值用;
隔开,如gene_id “gene”; transcript_id “geneA.1”; database_id “0012”; modified_by “Damian”; duplicate 0
。
根据我们的经验,Ensembl是最容易使用的,并且具有最大的注释集。NCBI往往更严格,仅包含高可信度的基因注释。而UCSC包含多个使用不同标准的基因注释。
如果你的实验系统含有非标准序列 (比如ERCC spike-ins
),那么这些序列必须加到基因组fasta
和gtf
上来定量它们的表达。另外,对CRISPR相关序列或其他过表达/报告载体也必须进行相同的操作。
为了获得最大的可用性和灵活性,我们建议为任何添加的非标准序列创建完整详细的fasta
序列文件和gtf
文件。
目前还没有标准化的方法来做到这一点。下面是我们写的一个perl
脚本 (和生信宝典写的awk脚本),可以把ERCC
序列转成对应的gtf
和fasta
文件,以便附加到标准基因组中。如果要量化内含子reads时,您可能还需要更改gtf
文件以处理内含子中的重复元件。任何脚本语言甚至是awk
或一些文本编辑器都可以相对有效地完成这项任务,但它们超出了本次课程的范围。(具体教程之前都有过推文介绍:awk学习见Linux - 常用和不太常用的实用awk命令,python学习见Python极简教程(一)。对应的视频见http://bioinfo.ke.qq.com/。)
# 下面两个awk命令可以实现perl脚本的功能
# 如果是windows的文件,替换下末尾的换行符
sed -i 's/^M//' ERCC_Controls_Annotation.txt
# 转成FASTA序列
awk 'BEGIN{OFS=FS="\t"}{if(FNR>1) print ">"$1"\n"$NF"NNNN"}' ERCC_Controls_Annotation.txt >ERCC.fa
# 转成GTF
awk 'BEGIN{OFS=FS="\t"}{if(FNR>1) {seq_len=length($NF)+2; attr="gene_id \""$1"-"$2"\"; transcript_id \""$1"-"$2"\"; exon_number \"1\"; gene_name \""$1"-"$2"\""; print $1,"ERCC","gene",1,seq_len,".","+",".",attr; print $1,"ERCC","transcript",1,seq_len,".","+",".",attr; print $1,"ERCC","exon",1,seq_len,".","+",".",attr;}}' ERCC_Controls_Annotation.txt >ERCC.gtf
下面的perl
脚本存储为文件 erccToAnno.pl
,并与ERCC_Controls_Annotation.txt
置于同一目录下,运行perl erccToAnno.pl
会生成两个文件ERCC_Controls.fa
和ERCC_Controls.gtf
,即为结果。与上面生成的ERCC.fa
和ERCC.gtf
一样。(awk脚本中基因名字做了修改,不允许空格出现)
# Converts the Annotation file from
# https://www.thermofisher.com/order/catalog/product/4456740 to
# gtf and fasta files that can be added to existing genome fasta & gtf files.
# 下面的perl脚本存储为文件 erccToAnno.pl,并与ERCC_Controls_Annotation.txt置于同一目录下,
# 运行perl erccToAnno.pl会生成两个文件ERCC_Controls.fa和ERCC_Controls.gtf。
my @FASTAlines = ();
my @GTFlines = ();
open (my $ifh, "ERCC_Controls_Annotation.txt") or die $!;
<$ifh>; #header
while (<$ifh>) {
# Do all the important stuff
chomp;
my @record = split(/\t/);
my $sequence = $record[4];
$sequence =~ s/\s+//g; # get rid of any preceeding/tailing white space
$sequence = $sequence."NNNN";
my $name = $record[0];
my $genbank = $record[1];
push(@FASTAlines, ">$name\n$sequence\n");
# is GTF 1 indexed or 0 indexed? -> it is 1 indexed
# + or - strand?
push(@GTFlines, "$name\tERCC\tgene\t1\t".(length($sequence)-2)."\t.\t+\t.\tgene_id \"$name-$genbank\"; transcript_id \"$name-$genbank\"; exon_number \"1\"; gene_name \"ERCC $name-$genbank\"\n");
push(@GTFlines, "$name\tERCC\ttranscript\t1\t".(length($sequence)-2)."\t.\t+\t.\tgene_id \"$name-$genbank\"; transcript_id \"$name-$genbank\"; exon_number \"1\"; gene_name \"ERCC $name-$genbank\"\n");
push(@GTFlines, "$name\tERCC\texon\t1\t".(length($sequence)-2)."\t.\t+\t.\tgene_id \"$name-$genbank\"; transcript_id \"$name-$genbank\"; exon_number \"1\"; gene_name \"ERCC $name-$genbank\"\n");
} close($ifh);
# Write output
open(my $ofh, ">", "ERCC_Controls.fa") or die $!;
foreach my $line (@FASTAlines) {
print $ofh $line;
} close ($ofh);
open($ofh, ">", "ERCC_Controls.gtf") or die $!;
foreach my $line (@GTFlines) {
print $ofh $line;
} close ($ofh);