参考资料:
参考生物技能树
Velocyto官网Tutorial
scvelo实战教程
Seurat-to-RNA-Velocity
分析步骤:
本教程是velocyto基于Seurat对象中UMAP和细胞类型进行RNA速率分析,推断细胞Cluster命运的状态(过渡与稳定)和分化方向性(轨迹)。
第一步:在linux系统中用velocyto将bam文件转换成loom文件;
第二步:按照scvelo需要的格式获取seurat中的UMAP坐标和Celltype信息;
第三步:在 python程序中整合loom文件和UMAP坐标和Celltype数据,并进行下游速率分析。
1、将bam文件转换成loom文件(Linux系统操作)
1.1 conda安装velocyto的一些依赖
需要一些依赖
conda create -n velocyto
conda activate velocyto
conda install samtools
conda install numpy scipy cython numba matplotlib scikit-learn h5py click
pip install pysam
pip install velocyto
Successfully installed loompy-3.0.6 numpy-groupies-0.9.13 pandas-1.2.5 pytz-2021.1 velocyto-0.17.17
1.2 下载特定物种的特殊gtf文件(这个步骤是可选的)
你如果要屏蔽repetetive elements,可以使用这一步骤
我们这个单细胞转录组使用cellranger流程的话,需要重复数据的gtf文件,rmsk。
进入UCSC官网,在Tools菜单中打开Table Brower,选择目的物种以及个性化的需求
1.3 bam文件循环进行sort
理论上,这下一步命令,就可以完成bam转换成loom文件,但是因为 samtools问题,上面的流程可能是会失败。这个时候可以自行先运行 samtools sort 命令处理得到 cellsorted_possorted_genome_bam.bam 文件。
ls */outs/possorted_genome_bam.bam|while read id
do new=${id/possorted_genome_bam.bam/cellsorted_possorted_genome_bam.bam}
echo $new
samtools sort -@ 4 -t CB -O BAM -o $new $id
done
1.4 bam文件循环运行velocyto
#! /bin/sh
rmsk_gtf=/lustre/home/acct-medxh/medxh/sccdata/Rawdata/reference/hg38_repeat_rmsk.gtf # 从genome.ucsc.edu下载
cellranger_outDir=/lustre/home/acct-medxh/medxh/sccdata/Rawdata/output_EC3 # 这个输出目录可以随便选择文件夹,但是最后一个文件夹决定了loom的细胞名字如”output_EU1:TTTCCTCAGTCCGCGTx“,所以output_EU1尽量为样品名
cellranger_gtf=/lustre/home/acct-medxh/medxh/yard/reference/refdata-gex-GRCh38-2020-A/genes/genes.gtf # 这个是cellranger官网提供的
ls -lh $rmsk_gtf $cellranger_outDir $cellranger_gtf
ls -d *-*|while read cellranger_outDir
do
velocyto run10x -m $rmsk_gtf $cellranger_outDir $cellranger_gtf
done
2、Seurat UMAP和Celltype提取(R和python)
参考官网https://scvelo.readthedocs.io/getting_started/
2.1 提取seurat中的cells、UMAP、celltype (R studio)
setwd("~/Desktop/bioinformation/End_analysis/velocyto")
library(dplyr)
library(ggplot2)
library(cowplot)
library(patchwork)
suppressMessages(library(Seurat))
End.combined <- readRDS("~/Desktop/bioinformation/End_analysis/End.combined.rds")
2.2 提取对象
table(End.combined$group)
Idents(object=End.combined)<-End.combined$group
Eutopic<-subset(End.combined, idents = c("Eutopic"), invert = F)
2.3 修改Cells名字(”ATCCCTGTCACTGAAC-1_1")保持和loom中cell ID("output_EU3:TTTGACTGTTGCCGACx")一致
df<-data.frame(Cells=Cells(Eutopic),sample=paste("output_EU",Eutopic$sampleID,sep = ""))#制做data.frame,含有cells和output_EU3
df$id<-sapply(df$Cells,function(x)paste(unlist(strsplit(x, "-"))[1],"x",sep = ""))#将“-”之前的字符和“x”连接
df$Cells<-paste(df$sample,df$id,sep = ":")#将“output_EU3”和Cells通过“:”连接
write.csv(df$Cells, file = "cellID_obs.csv", row.names = FALSE) #提取修改后的cell ID
cell_embeddings<-Embeddings(Eutopic, reduction = "umap")#使用Embeddings功能提取seurat UMAP或者TSNE
rownames(cell_embeddings)<-df$Cells #修改rowname的名字使其和cell ID一致
write.csv(cell_embeddings, file = "cell_embeddings.csv")
clusters_obs<-Eutopic$celltype.1 #提取celltype
names(clusters_obs)<-df$Cells #修改名字和保持cell ID一致
write.csv(clusters_obs, file = "clusters_obs.csv")
3、anndata导入loom文件和Seurat中meta-data并进行下游速率分析(多样本整合)
3.1加载依赖包
cona activate velocyto
python
import anndata
import scvelo as scv
import pandas as pd
import numpy as np
import matplotlib as plt
3.2 读取每个样品中的loom文件
sample_one = anndata.read_loom("/Users/linyu1/Desktop/bioinformation/End_analysis/velocyto/output_EU1.loom")
##Variable names are not unique. To make them unique, call `.var_names_make_unique`.
sample_one.var_names_make_unique()
sample_one
##AnnData object with n_obs × n_vars = 5992 × 36601
# obs: 'Clusters', '_X', '_Y'
# var: 'Accession', 'Chromosome', 'End', 'Start', 'Strand'
# layers: 'matrix', 'ambiguous', 'spliced', 'unspliced'
sample_two = anndata.read_loom("/Users/linyu1/Desktop/bioinformation/End_analysis/velocyto/output_EU2.loom")
sample_two.var_names_make_unique()
sample_three = anndata.read_loom("/Users/linyu1/Desktop/bioinformation/End_analysis/velocyto/output_EU3.loom")
sample_three.var_names_make_unique()
3.3 读取seurat中cells、UMAP和celltype的信息
sample_obs = pd.read_csv("/Users/linyu1/Desktop/bioinformation/End_analysis/velocyto/cellID_obs.csv")
umap = pd.read_csv("/Users/linyu1/Desktop/bioinformation/End_analysis/velocyto/cell_embeddings.csv")
cell_clusters = pd.read_csv("/Users/linyu1/Desktop/bioinformation/End_analysis/velocyto/clusters_obs.csv")
3.4 在每个样品loom中过滤出seurat中选择的Cell ID
sample_one = sample_one[np.isin(sample_one.obs.index,sample_obs["x"])]
sample_two = sample_two[np.isin(sample_two.obs.index,sample_obs["x"])]
sample_three = sample_three[np.isin(sample_three.obs.index,sample_obs["x"])]
3.5 将过滤后的文件整合成一个文件
adata = sample_one.concatenate(sample_two, sample_three)
3.6 将umap坐标和celltype添加到anndata 对象中
需要确保我们添加umapCell ID和anndata对象中的Cell ID的顺序完全匹配,Cell ID是对象的观察层中的行名,因此我们可以使用以下方法更改
一步、我们把index提取成表达矩阵并更改列名;
二步、由于多个样品合并成adata时Cell ID后面多了“-0”(如下图),为了完全匹配Cell ID,通过apply和split去除“-0”(保证adata和seurat中barcode名字相同);
三步、umap坐标和celltype添加到anndata 对象。
adata_index = pd.DataFrame(adata.obs.index)
adata_index = adata_index.rename(columns = {0:'Cell ID'})
adata_index = adata_index.rename(columns = {"CellID":'Cell ID'})
rep=lambda x : x.split("-")[0]
adata_index["Cell ID"]=adata_index["Cell ID"].apply(rep)
umap = umap.rename(columns = {'Unnamed: 0':'Cell ID'})#更改umap的列名统一相同的列名Cell ID
umap = umap[np.isin(umap["Cell ID"],adata_index["Cell ID"])] #过滤adata_index在umap中的cell ID
umap=umap.drop_duplicates(subset=["Cell ID"]) #去除重复值
umap_ordered = adata_index.merge(umap, on = "Cell ID")#依据adata_index Cell ID顺序与umap的数据进行合并
umap_ordered = umap_ordered.iloc[:,1:] #去除umap_ordered中的第一列
adata.obsm['X_umap'] = umap_ordered.values #将UMAP并入到adata对象中
cell_clusters=cell_clusters.iloc[:,1:]
cell_clusters = cell_clusters.rename(columns = {'cell':'Cell ID'})
cell_clusters = cell_clusters[np.isin(cell_clusters["Cell ID"],adata_index["Cell ID"])]
cell_clusters=cell_clusters.drop_duplicates(subset=["Cell ID"]) #去除重复值
cell_clusters_ordered = adata_index.merge(cell_clusters, on = "Cell ID")
cell_clusters_ordered = cell_clusters_ordered.iloc[:,1:]
adata.obs['clusters']=cell_clusters_ordered.values
3.8 运行RNA Velocity
我们现在可以运行scVelo命令,并根据Seurat UMAP坐标生成RNA速度图
scv.pp.filter_and_normalize(adata)
scv.pp.moments(adata)
scv.tl.velocity(adata, mode = "stochastic")
scv.tl.velocity_graph(adata)
3.9 spliced/unspliced的比例
scv.pl.proportions(adata)
3.10 可视化
scv.pl.velocity_embedding(adata, basis = 'umap')
scv.pl.velocity_embedding_stream(adata, basis = 'umap')
3.11 解释velocities
这可能是最重要的部分,因为我们建议用户不要将生物学结论局限于预测的速度,而是通过阶段画像来检查个体基因动力学,以了解推断的方向是如何由特定基因支持的。
参考下图思考如何解释spliced vs. unspliced 时相特征[图1.6a]。基因活性是由转录调控调控的。对特定基因的转录的诱导表达,会导致前体unspliced mRNAs 的增加,而相反地,转录抑制或缺失会导致unspliced mRNAs 的减少。spliced mRNA由未剪接的unspliced的mRNA产生,具有相同的趋势,但存在时间滞后。时间是一个隐藏/潜在的变量。因此,动力学需要从实际测量的东西来推断: 在相位图中显示的剪接和未剪接的mrna。
用scv.pl.velocity(adata, gene_names检查某些特定基因的时相特征
scv.pl.velocity(adata, ['Cpe', 'Gnao1', 'Ins2', 'Adk'], ncols=2)
黑线对应于估计的“稳态”比率,即处于恒定转录状态的spliced 和 unspliced mRNA丰度之比。一个特定基因的RNA速度是由残差决定的,即观察值偏离稳态线的程度。正速度表明一个基因被上调,这种现象发生在细胞中,在稳定状态下,该基因的unspliced mRNA的丰度高于预期。相反,负速度表明基因被下调。
例如,Cpe解释了上调的Ngn3(黄色)向Pre-endocrine(橙色)向β-cells(绿色)的方向,而Adk解释了下调的Ductal(深绿色)向Ngn3(黄色)向其余内分泌细胞的方向。
scv.pl.scatter(adata, 'Cpe', color=['clusters', 'velocity'],
add_outline='Ngn3 high EP, Pre-endocrine, Beta')
3.12 鉴定重要基因
我们需要一个系统的方法来识别基因,这可能有助于解释最终的向量场和推断的谱系。为了做到这一点,我们可以测试哪些基因具有集群特有的差异速度表达,与其他种群相比显著地更高或更低。模块scv.tl.rank_velocity_genes运行一个差分速度t检验,并为每个集群输出一个基因排名。可以设置阈值(例如min_corr)来限制对候选基因的测试。
scv.tl.rank_velocity_genes(adata, groupby='clusters', min_corr=.3)
df = scv.DataFrame(adata.uns['rank_velocity_genes']['names'])
df.head()
kwargs = dict(frameon=False, size=10, linewidth=1.5,
add_outline='Ngn3 high EP, Pre-endocrine, Beta')
scv.pl.scatter(adata, df['Ngn3 high EP'][:5], ylabel='Ngn3 high EP', **kwargs)
scv.pl.scatter(adata, df['Pre-endocrine'][:5], ylabel='Pre-endocrine', **kwargs)
例如,基因Ptprs、Pclo、Pam、Abcc8、Gnas支持从Ngn3高EP(黄色)到Pre-endocrine(橙色)再到Beta(绿色)的方向性。
3.13 细胞周期的Velocities分析
由RNA速度检测的细胞周期,在生物学上由细胞周期分数(阶段标志基因平均表达水平的标准化分数) 确定。
scv.tl.score_genes_cell_cycle(adata)
scv.pl.scatter(adata, color_gradients=['S_score', 'G2M_score'], smooth=True, perc=[5, 95])
s_genes, g2m_genes = scv.utils.get_phase_marker_genes(adata)
s_genes = scv.get_df(adata[:, s_genes], 'spearmans_score', sort_values=True).index
g2m_genes = scv.get_df(adata[:, g2m_genes], 'spearmans_score', sort_values=True).index
kwargs = dict(frameon=False, ylabel='cell cycle genes')
scv.pl.scatter(adata, list(s_genes[:2]) + list(g2m_genes[:3]), **kwargs)
特别是hell和Top2a非常适合解释周期祖先中的向量场。Top2a在G2M阶段达到峰值前不久被赋予了一个高速。在这里,负的速度与紧随其后的下调完全匹配。
scv.pl.velocity(adata, ['Hells', 'Top2a'], ncols=2, add_outline=True)
3.14 速度和一致性
两个更有用的stats:-速度或分化率是由速度矢量的长度给出的。-矢量场的一致性(即,速度矢量如何与其邻近速度相关联)提供了一个可信度的度量。
scv.tl.velocity_confidence(adata)
keys = 'velocity_length', 'velocity_confidence'
scv.pl.scatter(adata, c=keys, cmap='coolwarm', perc=[5, 95])
这些提供了细胞在哪里以较慢/较快的速度分化
在集群水平上,我们发现分化在细胞周期退出(Ngn3 low EP)后显著加快,在Beta细胞生产期间保持速度,而在Alpha细胞生产期间减慢速度。
df = adata.obs.groupby('clusters')[keys].mean().T
df.style.background_gradient(cmap='coolwarm', axis=1)
3.15 动力学模型
它在一个基于可能性的期望最大化框架中解决,通过迭代估计反应速率和潜在细胞特异性变量的参数,即转录状态和细胞内部潜伏时间。因此,它的目的是了解每个基因未拼接/已拼接阶段的轨迹。
scv.tl.recover_dynamics(adata)
scv.tl.velocity(adata, mode='dynamical')
scv.tl.velocity_graph(adata)
#adata.write('data/pancreas.h5ad', compression='gzip')
#adata = scv.read('data/pancreas.h5ad')
scv.pl.velocity_embedding_stream(adata, basis='umap')
3.16 动率参数
在不需要任何实验数据的情况下,可以估计RNA转录、剪接和降解的速率。
它们有助于更好地理解细胞的特性和表型异质性。
df = adata.var
df = df[(df['fit_likelihood'] > .1) & df['velocity_genes'] == True]
kwargs = dict(xscale='log', fontsize=16)
with scv.GridSpec(ncols=3) as pl:
pl.hist(df['fit_alpha'], xlabel='transcription rate', **kwargs)
pl.hist(df['fit_beta'] * df['fit_scaling'], xlabel='splicing rate', xticks=[.1, .4, 1], **kwargs)
pl.hist(df['fit_gamma'], xlabel='degradation rate', xticks=[.1, .4, 1], **kwargs)
scv.get_df(adata, 'fit*', dropna=True).head()
The estimated gene-specific parameters comprise rates of transription (fit_alpha), splicing (fit_beta), degradation (fit_gamma), switching time point (fit_t_), a scaling parameter to adjust for under-represented unspliced reads (fit_scaling), standard deviation of unspliced and spliced reads (fit_std_u, fit_std_s), the gene likelihood (fit_likelihood), inferred steady-state levels (fit_steady_u, fit_steady_s) with their corresponding p-values (fit_pval_steady_u, fit_pval_steady_s), the overall model variance (fit_variance), and a scaling factor to align the gene-wise latent times to a universal, gene-shared latent time (fit_alignment_scaling).
3.17 逆时分析
动态模型恢复了潜在细胞过程的潜在时间。这一潜伏时间代表了细胞的内部时钟,仅根据其转录动力学,与细胞分化时所经历的实时时间近似。
scv.tl.latent_time(adata)
scv.pl.scatter(adata, color='latent_time', color_map='gnuplot', size=80)
top_genes = adata.var['fit_likelihood'].sort_values(ascending=False).index[:300]
scv.pl.heatmap(adata, var_names=top_genes, sortby='latent_time', col_color='clusters', n_convolve=100)
2.3 Top-likelihood基因
驱动基因表现出明显的动态行为,并通过动态模型中的高可能性对其特征进行系统地检测。
top_genes = adata.var['fit_likelihood'].sort_values(ascending=False).index
scv.pl.scatter(adata, basis=top_genes[:15], ncols=5, frameon=False)
var_names = ['Actn4', 'Ppp3ca', 'Cpe', 'Nnat']
scv.pl.scatter(adata, var_names, frameon=False)
scv.pl.scatter(adata, x='latent_time', y=var_names, frameon=False)
3.18 Cluster-specific top-likelihood 基因
此外,可以计算每个细胞集群的部分基因可能性,以实现集群特异性识别潜在驱动因素。
scv.tl.rank_dynamical_genes(adata, groupby='clusters')
df = scv.get_df(adata, 'rank_dynamical_genes/names')
df.head(5)
for cluster in ['Ductal', 'Ngn3 high EP', 'Pre-endocrine', 'Beta']:
scv.pl.scatter(adata, df[cluster][:5], ylabel=cluster, frameon=False)