RNA-seq转录组差异分析及可视化

关于RNAseq

Nature重磅综述 |关于RNA-seq,你想知道的都在这

准备工作

先在服务器安装conda。安装好通过conda进一步安装所需要的软件。

通过conda安装fastqc(质控), hisat2(比对), multiqc(质控合并), samtools(sam文件转bam文件), subread(featureCounts集合在其中)。建议先创建一个虚拟环境。

SRA toolkit软件(用于下载和处理NCBI的数据)下载,在官网下载自己合适的版本(使用conda安装时失败了)。

参考代码:

conda create -n RNAseq #新建一个名为RNAseq的conda环境
conda activate RNAseq #激活并进入新建的RNAseq环境
conda install fastqc hisat2 samtools subread multiqc trimmomatic #安装所需要的软件

数据准备

数据下载

在GEO数据库下载PRJNA639275数据集,这个数据集共有34个样本(16个新冠患者,17个正常样本),每个样本测序两次。


NCBI数据库

NCBI数据库
prefetch SRRXXXXXX -O output  # output更换为路径
prefetch -O output --option-file SRR_Acc_list.txt #批量下载

数据处理

sra转fastq格式

for name in SRR120078*; do fastq-dump
--split-files #双端测序时需要加这个参数
--gzip #加上-gzip可以使fq文件压缩,节约空间
-O /path to save/  # -O 指定输出位置
/path to input/${name}/*sra; done #遍历处理所有下载的数据 

如果是自己的测序文件则需要对比md5码来检查数据完整性

md5sum *gz > md5.txt && md5sum -c md5.txt
# *gz 任意以gz结尾的文件
# > 运行结果保存至
# && 连接符,前一命令完成继续执行下一命令

质量评估与质控

multiqc是合并报告的一个Python包,报告解读

操作说明见官方用户手册

multiqc只能识别 *report.html

方法一:使用fastp质控

fastp的安装

fastp的数据质控原理

个人感觉fastp比trimmomatic要方便

单端:fastp -i raw.fq -o clean.fq
双端:fastp -i raw_1.fq -I raw_2.fq -o clean_1.fq -O clean_2.fq
参数:
-l 36 #过滤后的最短序列长度,默认为15
-j xxx.json 过滤报告文件
-h xxx.report.html 过滤报告文件

单端测序

for name in *fq;do fastp \
-i ./${name}/*gz \
-o./fastp_clean/clean_${name}.gz \
-l 36 \
-h ./fastp_reports/${name}.html;
done

multiqc ./fastp_reports/ -o ./multiqc_reports/

双端测序

fastp \
-i R1_fastq.gz \
-I R2_fastq.gz \
-o R1_output \
-O R2_output\
-l 36 \
-j jsonfile \
-h htmlfile

方法二:使用fastqc质量评估和trimmomatic质控

fastqc基本介绍

fastqc -o fastqc_output ./rawdata/*gz 
multiqc fastqc_output  -o output
# 对所有gz结尾文件进行质控并对当前目录下所有质控报告进行合并

trimmomatic

参考用法说明

trimmomatic SE -phred33 \
input.fq.gz output_fq.gz \
ILLUMINACLIP:TruSeq3-SE.fa:2:30:10 \
LEADING:3 \
TRAILING:3 \
MINLEN:36  #单端
trimmomatic PE -phred33 \
input_forward.fq.gz input_reverse.fq.gz \
output_forward_paired.fq.gz output_forward_unpaired.fq.gz \
output_reverse_paired.fq.gz output_reverse_unpaired.fq.gz \
ILLUMINACLIP:TruSeq3-PE.fa:2:30:10 \
LEADING:3 \
TRAILING:3 \
MINLEN:36 #双端

hisat2比对

准备工作

官网直接下载对应的基因组索引文件然后解压即可生成8个索引文件。

wget https://genome-idx.s3.amazonaws.com/hisat/grch38_genome.tar.gz
tar -zxvf grch38_genome.tar.gz
#grch38/
#grch38/genome.5.ht2
#grch38/genome.2.ht2
#grch38/make_grch38.sh
#grch38/genome.3.ht2
#grch38/genome.4.ht2
#grch38/genome.7.ht2
#grch38/genome.1.ht2
#grch38/genome.6.ht2
#grch38/genome.8.ht2

或者根据不同需求在genecode下载基因组fa文件和注释GTF文件,然后在通过hisat2-build去建立索引。

比对

hisat2 -p 8 \
-x ref/grch38/genome \
-1 sample_1.fq.gz -2 sample_2.fq.gz \
-S sample.sam \
--summary-file sample.hisat2.summary

-p: 线程数
-x: 基因组索引前缀。所下的基因组索引为多个文件,索引前缀到genome为止。
-1/-2: fastq输入文件。当输入为单端测序时使用-U 指定输入。
单端或双端的输入都可使用逗号分隔输入多个样本,或使用多次-1 -2 / -U 指定多个输入。
e.g.:-U sample1.fq.gz,sample2.fq.gz -U sample3.fq.gz
-S: 输出sam文件路径。
--summary-file: 生成summary文件。

sam转bam

使用samtools将sam文件转换为bam文件,bam文件为二进制文件,能大大压缩体积

samtools sort -@ 8 -o sample.bam sample.sam
# sort:排序
# -@:线程数
# -o:输出bam文件
转换前后体积对比

计数

试用featureCounts进行计数,这一步需要基因组注释文件,在genecode下载GTF文件即可。

featureCounts -p -T 8 -a ref/annotation.gtf.gz -o featurecounts.out \
[sample1.bam sample2.bam ...] *.bam
# -p: 此参数双端测序时使用
# -T: 线程数
# -a: 基因组注释文件
# -o: 输出文件
# 最后为bam文件,可指定多个输入

DESeq2差异表达分析

Ensembl ID和gene symbol相互转换

下载转换参照表

选择对应物种,左侧Attributes只选择Gene stable ID 和 Gene name,然后点击左上角的resuls,最后点击GO导出文件。
根据参考文件在计数文件中添加symbol name。
或用R包实现

R语言实现ID转换

BiocManager::install("org.Mm.eg.db") #Mm:小鼠,Hs:人 
library('org.Mm.eg.db') 

matrix <- read.csv("./featurecounts.txt",sep="\t",stringsAsFactors = F,header = F)
colnames(matrix) <- matrix[2,]
matrix <- matrix[-1:-2,]
rownames(matrix) <- 1:nrow(matrix)
for (i in 1:nrow(matrix)){
  matrix[i,"Geneid"] <- strsplit(matrix[i,"Geneid"], split = "\\.")[[1]][1]
}
mycounts <- matrix[,-2:-6]
colnames(mycounts)[1] <- "ensembl_id" #列名需要更改


g2s=toTable(org.Mm.egSYMBOL)
g2e=toTable(org.Mm.egENSEMBL)
b=merge(mycounts,g2e,by="ensembl_id",all.x=T) 
d=merge(b,g2s,by="gene_id",all.x=T)

d=d[order(d$ensembl_id),]
table(d$symbol)[table(d$symbol)>1] 
d=d[!duplicated(d$symbol),] #去重

d=d[match(mycounts$ensembl_id,d$ensembl_id),]
mycounts$symbol <- d$symbol
mycounts<-subset(mycounts,symbol!="NA") #去缺失值
rownames(mycounts) <- mycounts$symbol

R分析前需要准备的两个文件:

featurecounts计数文件与分组文件

代码部分

DEG分析

library(DESeq2)
setwd("E:/R/DEseq2")
mycounts <- read.csv("counts.csv",header= TRUE,row.names = 2)
mycounts <- mycounts[rowSums(mycounts[-1])!=0,]
mycounts <- mycounts[-1]
mymeta <- read.csv("mymeta heathly_vs_covid.csv",stringsAsFactors = T)
colnames(mycounts)==mymeta$id
dds <- DESeqDataSetFromMatrix(countData = mycounts, colData = mymeta,desig=~dex)
dds <- DESeq(dds)
res <- results(dds,contrast = c("dex","covid","Healthy"))
res <- data.frame(res)
DEG <- res[order(res$padj),]  #按照padj排序
write.csv(DEG,"DEG.csv",quote = F)
save(DEG,file = "DEG_results.Rdata") #保存R数据方便下次继续使用

得到的DEG结果

DEG Results

heatmap

library(pheatmap)
choose_gene=head(rownames(DEG),1000)
choose_matrix=mycounts[choose_gene,]
choose_matrix <- log2(choose_matrix+1)
choose_matrix=t(scale(t(choose_matrix)))
group_list <-c(rep("covid",17),rep("Healthy",19))
ac <- data.frame(dex=group_list)
rownames(ac) <- colnames(choose_matrix)
pheatmap(choose_matrix,filename = "heatmap.png", show_rownames = F, show_colnames = F,
        annotation_col = ac, display_numbers = FALSE)
heatmap

volcano

library(ggpubr)
library(ggthemes)
DEG$change =as.factor(ifelse(DEG$pvalue < 0.05 & DEG$log2FoldChange > 2,'UP',

                            ifelse(DEG$pvalue < 0.05 & DEG$log2FoldChange < -2,'DOWN',

                                    "NOT")))
DEG$logp = -log10(DEG$pvalue)
table(DEG$change)
DEG$label  <- ""
DEG <- DEG[order(DEG$pvalue),]
up_genes <- head(row.names(DEG)[which(DEG$change == "UP")],10)
down_genes <- head(row.names(DEG)[which(DEG$change =="DOWN")],10)
DEG_top10 <- c(as.character(up_genes),as.character(down_genes))
DEG$label[match(DEG_top10,row.names(DEG))] <- DEG_top10
ggscatter(DEG, x = "log2FoldChange", y = "logp",
          color = "change",
          palette = c("#2f5688","#BBBBBB","#CC0000"),
          size = 1,
          label = DEG$label,
          font.label = 8,
          repel = T,
          xlab = "log2FoldChange",
          ylab ="-log10(adjust p value)") + theme_base() +
  geom_hline(yintercept = 1.5,linetype="dashed")+
  geom_vline(xintercept = c(-1,1),linetype="dashed")
ggsave("volcano.png",dpi=600)
volcano

GO And KEGG

#####install packages#####
BiocManager::install("clusterProfiler")  
BiocManager::install("topGO")  
BiocManager::install("Rgraphviz")
BiocManager::install("pathview") 
BiocManager::install("org.Hs.eg.db") 

library(clusterProfiler)
library(topGO)
library(Rgraphviz)
library(pathview)
library(org.Hs.eg.db)
DEG_vector <- (DEG$padj < 0.005 & DEG$log2FoldChange > 3)|(DEG$padj < 0.005 & DEG$log2FoldChange < -3) #Padj根据需要改为pvalue,所有数值可以根据需求更改。
DEG.sign <- DEG[DEG_vector,]
DEG.entrez_id = mapIds(x = org.Hs.eg.db,
                      keys = rownames(DEG.sign),
                      keytype = "SYMBOL",
                      column = "ENTREZID")
DEG.sign$ENTREZID <- DEG.entrez_id
gene_up <- DEG.sign[DEG.sign$change == 'UP','ENTREZID']
gene_down <- DEG.sign[DEG.sign$change == 'DOWN','ENTREZID']
source('kegg_and_go_up_and_down.R') #提前准备好kegg_and_go_up_and_down.R文件
run_go(gene_up,gene_down,pro='convid_VS_healthy')
run_kegg(gene_up,gene_down,pro='convid_VS_healthy')
go enrich

convid_VS_healthy_kegg_up_down

kegg_and_go_up_and_down.R

(via jimmy)

## KEGG pathway analysis
### 做KEGG数据集超几何分布检验分析,重点在结果的可视化及生物学意义的理解。
run_kegg <- function(gene_up,gene_down,geneList=F,pro='test'){
  gene_up=unique(gene_up)
  gene_down=unique(gene_down)
  gene_diff=unique(c(gene_up,gene_down))
  ###  over-representation test
  # 下面把3个基因集分开做超几何分布检验
  # 上调基因集。
  kk.up <- enrichKEGG(gene        = gene_up,
                      organism    = 'hsa',
                      #universe    = gene_all,
                      pvalueCutoff = 0.5,
                      qvalueCutoff = 0.5)
  head(kk.up)[,1:6]
  kk=kk.up
  dotplot(kk)
  kk=DOSE::setReadable(kk, OrgDb='org.Hs.eg.db',keyType = "ENTREZID")
  write.csv(kk@result,paste0("./kegg_results/",pro,'_kk.up.csv'))
  # 下调基因集。
  kk.down <- enrichKEGG(gene        =  gene_down,
                        organism    = 'hsa',
                        #universe    = gene_all,
                        pvalueCutoff = 0.5,
                        qvalueCutoff =0.5)
  head(kk.down)[,1:6]
  kk=kk.down
  dotplot(kk)
  kk=DOSE::setReadable(kk, OrgDb='org.Hs.eg.db',keyType = "ENTREZID")
  write.csv(kk@result,paste0("./kegg_results/",pro,'_kk.down.csv'))
  # 上下调合并后的基因集。
  kk.diff <- enrichKEGG(gene        = gene_diff,
                        organism    = 'hsa',
                        pvalueCutoff = 0.5)
  head(kk.diff)[,1:6]
  kk=kk.diff
  dotplot(kk)
  kk=DOSE::setReadable(kk, OrgDb='org.Hs.eg.db',keyType = "ENTREZID")
  write.csv(kk@result,paste0("./kegg_results/",pro,'_kk.diff.csv'))
  kegg_diff_dt <- as.data.frame(kk.diff)
  kegg_down_dt <- as.data.frame(kk.down)
  kegg_up_dt <- as.data.frame(kk.up)
  down_kegg<-kegg_down_dt[kegg_down_dt$pvalue<0.1,];down_kegg$group=-1
  up_kegg<-kegg_up_dt[kegg_up_dt$pvalue<0.1,];up_kegg$group=1
  #画图设置, 这个图很丑,大家可以自行修改。
  g_kegg=kegg_plot(up_kegg,down_kegg)
  print(g_kegg)
  ggsave(g_kegg,filename = paste0("./kegg_results/",pro,'_kegg_up_down.png'))
  if(geneList){
    ###  GSEA
    ## GSEA算法跟上面的使用差异基因集做超几何分布检验不一样。
    kk_gse <- gseKEGG(geneList    = geneList,
                      organism    = 'hsa',
                      nPerm        = 1000,
                      minGSSize    = 20,
                      pvalueCutoff = 0.9,
                      verbose      = FALSE)
    head(kk_gse)[,1:6]
    gseaplot(kk_gse, geneSetID = rownames(kk_gse[1,]))
    gseaplot(kk_gse, 'hsa04110',title = 'Cell cycle')
    kk=DOSE::setReadable(kk_gse, OrgDb='org.Hs.eg.db',keytype='ENTREZID')
    tmp=kk@result
    write.csv(kk@result,paste0(pro,'_kegg.gsea.csv'))

    # 这里如果找不到显著下调的通路,可以选择调整阈值,或者其它。
    down_kegg<-kk_gse[kk_gse$pvalue<0.01 & kk_gse$enrichmentScore < 0,];down_kegg$group=-1
    up_kegg<-kk_gse[kk_gse$pvalue<0.01 & kk_gse$enrichmentScore > 0,];up_kegg$group=1
    g_kegg=kegg_plot(up_kegg,down_kegg)
    print(g_kegg)
    ggsave(g_kegg,filename = paste0("./kegg_results/",pro,'_kegg_gsea.png'))
  }
}

### GO database analysis
### 做GO数据集超几何分布检验分析,重点在结果的可视化及生物学意义的理解。
run_go <- function(gene_up,gene_down,pro='test'){
  gene_up=unique(gene_up)
  gene_down=unique(gene_down)
  gene_diff=unique(c(gene_up,gene_down))
  g_list=list(gene_up=gene_up,
              gene_down=gene_down,
              gene_diff=gene_diff)
  # 因为go数据库非常多基因集,所以运行速度会很慢。
  if(T){
    go_enrich_results <- lapply( g_list , function(gene) {
      lapply( c('BP','MF','CC') , function(ont) {
        cat(paste('Now process ',ont ))
        ego <- enrichGO(gene          = gene,
                        #universe      = gene_all,
                        OrgDb        = org.Hs.eg.db,
                        ont          = ont ,
                        pAdjustMethod = "BH",
                        pvalueCutoff  = 0.5,
                        qvalueCutoff  = 0.5,
                        readable      = TRUE)
        print( head(ego) )
        return(ego)
      })
    })
    save(go_enrich_results,file =paste0(pro, '_go_enrich_results.Rdata'))
  }

  # 只有第一次需要运行,就保存结果哈,下次需要探索结果,就载入即可。

  load(file=paste0(pro, '_go_enrich_results.Rdata'))
  n1= c('gene_up','gene_down','gene_diff')
  n2= c('BP','MF','CC')
  for (i in 1:3){
    for (j in 1:3){
      fn=paste0("./go_enrich_results/",pro, '_dotplot_',n1[i],'_',n2[j],'.png')
      cat(paste0(fn,'\n'))
    # png(fn,res=150,width = 1080)
    # print( dotplot(go_enrich_results[[i]][[j]] ))
    #dev.off()
      dotplot(go_enrich_results[[i]][[j]] )
      ggsave(fn)
    }
  }
}
kegg_plot <- function(up_kegg,down_kegg){
  dat=rbind(up_kegg,down_kegg)
  colnames(dat)
  dat$pvalue = -log10(dat$pvalue)
  dat$pvalue=dat$pvalue*dat$group
  dat=dat[order(dat$pvalue,decreasing = F),]
  g_kegg<- ggplot(dat, aes(x=reorder(Description,order(pvalue, decreasing = F)), y=pvalue, fill=group)) +
    geom_bar(stat="identity") +
    scale_fill_gradient(low="blue",high="red",guide = FALSE) +
    scale_x_discrete(name ="Pathway names") +
    scale_y_continuous(name ="log10P-value") +
    coord_flip() + theme_bw()+theme(plot.title = element_text(hjust = 0.5))+
    ggtitle("Pathway Enrichment")
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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