velocyto.R画图中箭头的指向

作者: 小潤澤 | 来源:发表于2021-10-08 00:46 被阅读0次

    前言

    Gene在转录为mRNA的过程中会经历splicing,RNA刚转录出来(此时称之为前体RNA)是没有经历过splicing的,而剪切过的RNA(此时称之为mRNA)从生成时间上要晚一些。即首先RNA转录出来为前体RNA,经过剪切后形成成熟的mRNA,因此在这个过程中存在时间差。由于每个细胞的RNA速率不同,因此可以从这个角度推测细胞的分化轨迹

    其中,α代表转录速率,β 代表剪切速率,u 代表unspliced mRNA,γ 代表成熟mRNA的降解速率,s 代表spliced mRNA(成熟mRNA)。因此满足于下式:

    上述式子分为两部分,du/dt 代表的是unspliced mRNA所能积累的速率,即转录出来的全部前体mRNA(α)等于剪切的部分 βu 加上积累的部分 du/dt ;而 ds/dt 代表的是spliced mRNA所积累的速率,剪切的部分 βu 等于 spliced mRNA积累的部分加上降解的部分 γs ;u 和 s 分别表示unspliced mRNA和spliced mRNA所积累的量。

    当 t ≤ ts 时,转录开始;当 t > ts 时,转录停止:

    αon表示开启转录时的转录速率,αoff表示关闭转录时的转录速率=0。

    模型解法

    因此有两种模型参数的估计方法:
    (1).Constant velocity assumption:


    则当v < 0时,表现为该基因被下调;其中s0代表spliced mRNA的初值条件

    (2).Constant unspliced molecules assumption:


    其中s0代表spliced mRNA的初值条件,u0代表unspliced mRNA的初值条件,γ代表将解速率

    velocyto.R pipeline

    摘抄自:http://pklab.med.harvard.edu/velocyto/notebooks/R/chromaffin2.nb.html
    现实中可以利用 velocyto.py 来注释 spliced 和 unspliced reads

    library(velocyto.R)
    
    # 加载数据
    ldat <- readRDS(url("http://pklab.med.harvard.edu/velocyto/chromaffin/ldat.rds"))
    cell.colors <- readRDS(url("http://pklab.med.harvard.edu/velocyto/chromaffin/cell.colors.rds"))
    emb <- readRDS(url("http://pklab.med.harvard.edu/velocyto/chromaffin/embedding.rds"))
    
    # 提取unspliced mRNA和spliced mRNA
    # exonic read (spliced) expression matrix
    emat <- ldat$spliced;
    # intronic read (unspliced) expression matrix
    nmat <- ldat$unspliced
    # spanning read (intron+exon) expression matrix
    smat <- ldat$spanning;
    # filter expression matrices based on some minimum max-cluster averages
    emat <- filter.genes.by.cluster.expression(emat,cell.colors,min.max.cluster.average = 5)
    nmat <- filter.genes.by.cluster.expression(nmat,cell.colors,min.max.cluster.average = 1)
    smat <- filter.genes.by.cluster.expression(smat,cell.colors,min.max.cluster.average = 0.5)
    # look at the resulting gene set
    length(intersect(rownames(emat),rownames(nmat)))
    
    # 估计RNA速率
    fit.quantile <- 0.05;
    rvel.qf <- gene.relative.velocity.estimates(emat,nmat,deltaT=1,kCells = 5,fit.quantile = fit.quantile)
    
    # 可视化
    pca.velocity.plot(rvel.qf,nPcs=5,plot.cols=2,cell.colors=ac(cell.colors,alpha=0.7),cex=1.2,pcount=0.1,pc.multipliers=c(1,-1,-1,-1,-1))
    

    R代码详解

    项目地址:传送门

    其中函数t.get.projected.delta()估计一段时间内s(t) 即spliced mRNA的变化采用的既是Constant unspliced molecules assumption模型

    t.get.projected.delta <- function(em,nm,gamma,offset=rep(0,length(gamma)),delta=0.5) {
        # adjust rownames
        gn <- intersect(names(gamma),rownames(em));
        if(is.null(names(offset))) { names(offset) <- names(gamma); }
        em <- em[gn,]; nm <- nm[gn,]; gamma <- gamma[gn]; offset <- offset[gn];
        # time effect constant
        egt <- exp(-gamma*delta);
        
        ## 对nm(unspliced mRNA reads 做矫正)
        y <- nm-offset; y[y<0] <- 0; # zero out entries with a negative n levels after offset adjustment
       
        ## Constant unspliced molecules assumption模型计算一段时间内s(t) 即spliced mRNA的变化
        em*egt + (1-egt)*y/gamma  - em
      }
    

    其中:

    1. em代表每个细胞,每个特定基因spliced mRNA的reads的初值 s0,即从测序测到的reads中得到,测序测到的reads就定义为初值;em可以理解为由 ldat$spliced 而得
    2. nm代表每个细胞,每个特定基因unspliced mRNA的reads的初值 u0;这里用 y = nm-offset 做了个矫正;nm可以理解为由 ldat$unspliced 而得
    3. egt代表
    4. gamma代表 γ,即RNA降解速率,估计gamma的方法在:传送门的第[4]节,估计gamma的代码如下:
    # 作者定义steady.state.cells为 exonic read (spliced) expression cells
    steady.state.cells=colnames(emat)
    
    sfit <- data.frame(do.call(rbind,parallel::mclapply(sn(rownames(conv.emat.norm)),function(gn) {
           # gn 为gene knn聚类所筛选出来的每一个gene
           df <- data.frame(n=(conv.nmat.norm[gn,steady.state.cells]),
                            e=(conv.emat.norm[gn,steady.state.cells]),
                            s=conv.smat.norm[gn,steady.state.cells])
           # 对每一个基因的emat [u(t)] 和 nmat [(s(t))] 建立线性关系,估计比例系数
           # 这里的 n 与 s 是某一个基因在不同细胞中 unspliced 和 spliced 的表达量(列为细胞steady.state.cells,行为某一个基因)
           d <- lm(n~e,data=df,weights=pw)
           # note: re-estimating offset here
          return(c(o=as.numeric(coef(d)[1]),
                   g=as.numeric(coef(d)[2]),
                   r=cor(df$e,df$n,method='spearman')))
           
    
    # omit genes for which sfit didn't work
    ko <- ko[rownames(ko) %in% rownames(sfit),];
    vi <- sfit$r > min.nmat.smat.correlation
    ko <- ko[vi,]
    gamma <- ko$g
    

    conv.nmat.norm和conv.emat.norm描述的是在不同细胞下某个基因unspliced和spliced的表达量,因此假设周期时间很短的话,每个基因在不同细胞中unspliced和spliced counts构成的坐标(如上图的绿点表示的是不同的细胞)大致在一条过原点的直线上;这里的conv.nmat.norm,conv.emat.norm来源于nmat和emat,代码如下:(值得注意的的是这里的基因和细胞都不是选择全部的基因和细胞,而是利用knn筛选了部分的基因和细胞)
    # 值得注意的的是这里的基因和细胞都不是选择全部的基因和细胞
    # 而是利用knn筛选了部分的基因和细胞
    if(!is.null(old.fit)) { cellKNN <- old.fit[['cellKNN']]}
     knn.maxl <- 1e2
     if(kCells>1) {
       if(is.null(cellKNN)) {
         cat("calculating cell knn ... ")
         if(is.null(cell.dist)) {
           cellKNN <- balancedKNN(emat.log.norm,kCells,kCells*knn.maxl,n.threads=n.cores);
         } else {
           cellKNN <- balancedKNN(emat.log.norm,kCells,kCells*knn.maxl,n.threads=n.cores,dist=cell.dist);
         }
         diag(cellKNN) <- 1;
         resl$cellKNN <- cellKNN;
         cat("done\n")
       }
       rm(emat.log.norm);
       # smoothed matrices
       cat("calculating convolved matrices ... ")
       conv.emat <- emat %*% cellKNN[colnames(emat),colnames(emat)]
       conv.nmat <- nmat %*% cellKNN[colnames(nmat),colnames(nmat)]
       conv.emat.cs <- (emat.cs %*% cellKNN[colnames(emat),colnames(emat)])[1,]
       conv.nmat.cs <- (nmat.cs %*% cellKNN[colnames(nmat),colnames(nmat)])[1,]
       cat("done\n")
     } else {
       conv.emat <- emat; conv.nmat <- nmat; cellKNN <- NULL;
       conv.emat.cs <- emat.cs; conv.nmat.cs <- nmat.cs;
     }
    

    也就是说当估计gamma(γ)的值时,作者将不同细胞中对于某个基因实际测到的unspliced和spliced counts画在坐标系中(上图绿点代表不同细胞,横坐标代表 spliced counts,纵坐标代表 unspliced counts),可以看到这些细胞(绿点)大致在一条直线上,并用过原点的直线拟合,直线斜率为gamma(γ)

    我们可以看到作者定义对一段时间内s(t)的变化,即spliced mRNA的变化定义为:



    代码为:

    deltaE <- em*egt + (1-egt)*y/gamma - em
    

    因此,作者定义未来对一段时间内s(t)的变化,即spliced mRNA的终量为:

    delta=1
    deltae=as.matrix(deltaE)
    target.mult=1e3
    model.mult=1e3
    
    # 初始化
    rz <- matrix(0,nrow=nrow(em),ncol=ncol(em))
    colnames(rz) <- colnames(em)
    rownames(rz) <- rownames(em)
    gn <- intersect(rownames(deltae),rownames(rz))
    
    ## 对一段时间内s(t)的变化,即spliced mRNA的变化deltaE进行筛选和矫正
    rz[match(gn,rownames(rz)),colnames(deltae)] <- deltae[gn,]; 
    
    rz <- t(t(rz)*cellSize)
    ## emm为spliced mRNA reads的初始值
    emm <- t(t(em)*cellSize)
    
    ## spliced mRNA reads的终量为spliced mRNA reads的初始值加上
    ## delta=1, rz 代表 deltaE
    emn <- emm + rz*delta
    ## emn为spliced mRNA reads的终量
    emn[emn<0] <- 0;
    newCellSize <- (cellSize+Matrix::colSums(emn-emm)/mult)
    emn <- t(t(emn)/newCellSize)
    

    因此在降维画图的时候,箭头是如何表示出来的呢?以PCA降维为例:



    从代码上来看:

    # 其中vel$current代表spliced mRNA reads的初始值 emm
    x0 <- vel$current
    # 其中vel$projected代表spliced mRNA reads的终值 emn
    x1 <- vel$projected
    
    # transform
    x0.log <- log2(x0+pcount)
    x1.log <- log2(x1+pcount)
     
    cent <- rowMeans(x0.log)
    
    # PCA降维构建低维空间的cell坐标,取PC1和PC2分别作为横纵坐标值,epc
    epc <- pcaMethods::pca(t(x0.log-cent),center=F,nPcs=ifelse(is.na(norm.nPcs),nPcs,norm.nPcs))
      
    # 继续进行变化,epc@loadings代表经过变化后的spliced mRNA reads的初始值
    epc@loadings <- t(t(epc@loadings)*pc.multipliers)
    epc@scores <- scale(epc@completeObs,scale=F,center=T) %*% epc@loadings;
      
    # 继续进行变化,x1.scores代表经过变化后的spliced mRNA reads的终值
    x1.scores <- t(x1.log - cent) %*% epc@loadings
    # 计算spliced mRNA reads的终值和spliced mRNA reads的初始值之差,定义为spliced mRNA reads的变化量
    delta.pcs <- as.matrix(x1.scores-epc@scores)
    

    那么箭头指向的定义如下:

    ## pos代表每个cell spliced mRNA reads的初始值的二维坐标,i 为每一个细胞
    pos <- epc@scores[,c((i-1)+1,(i-1)+2)]
    ## ppos代表每个cell spliced mRNA reads的终值的二维坐标,i 为每一个细胞
    ppos <- pos+delta.pcs[,c((i-1)+1,(i-1)+2)]
    
    ## 将每个细胞的二维坐标画在图上
    plot(pos,bg=cell.colors[rownames(pos)],pch=21,
         col=ac(1,alpha=0.3),lwd=0.5,xlab=paste("PC",(i-1)+1),
         ylab=paste("PC",(i-1)+2),axes=T,
         main=paste('PC',(i-1)+1,' vs. PC',(i-1)+2,sep='')); 
    box();
        
    ## 定义箭头指向
    ars <- data.frame(pos[,1],pos[,2],ppos[,1],ppos[,2])
    colnames(ars) <- c('x0','y0','x1','y1')
    
    ## 定义箭头的变化量
    arsd <- data.frame(xd=ars$x1-ars$x0,yd=ars$y1-ars$y0)
    rownames(ars) <- rownames(arsd) <- rownames(pos)
    
    ## 对箭头指向进行矫正
    rx <- range(c(range(ars$x0),range(ars$x1)))
    ry <- range(c(range(ars$y0),range(ars$y1)))
    gx <- seq(rx[1],rx[2],length.out=grid.n)
    gy <- seq(ry[1],ry[2],length.out=grid.n)
          
    ## 对箭头指向进行矫正  
    garrows <- do.call(rbind,lapply(gx,function(x) {
          cd <- sqrt(outer(pos[,2],-gy,'+')^2 + (x-pos[,1])^2)
          cw <- dnorm(cd,sd=grid.sd)
            
          gw <- Matrix::colSums(cw)
          cws <- pmax(1,Matrix::colSums(cw));
          gxd <- Matrix::colSums(cw*arsd$xd)/cws
          gyd <- Matrix::colSums(cw*arsd$yd)/cws
            
          al <- sqrt(gxd^2+gyd^2);
          vg <- gw>=min.grid.cell.mass & al>=min.arrow.size
            
          cbind(rep(x,sum(vg)),gy[vg],x+gxd[vg],gy[vg]+gyd[vg])
      }))
          
          ## x0:代表spliced mRNA reads的初始值的横坐标;
          ## x1:代表spliced mRNA reads的终值的横坐标;
          ## y0:代表spliced mRNA reads的初始值的纵坐标;
          ## y1:代表spliced mRNA reads的终值的纵坐标;
          colnames(garrows) <- c('x0','y0','x1','y1')
    
    ## 箭头的画图为
    # plot
    alen <- pmin(max.grid.arrow.length,sqrt( ((garrows[,3]-garrows[,1]) * par('pin')[1] / diff(par('usr')[c(1,2)]) )^2 + ((garrows[,4]-garrows[,2])*par('pin')[2] / diff(par('usr')[c(3,4)]) )^2))
    
    ## arrows画箭头指向,i 为每一个细胞
    suppressWarnings(lapply(1:nrow(garrows),function(i) arrows(garrows[i,1],garrows[i,2],garrows[i,3],garrows[i,4],length=alen[i],lwd=arrow.lwd)))
    

    其中对于garrows里面的列元素来说:
    x0:代表spliced mRNA reads的初始值经过PCA降维后的横坐标;
    x1:代表spliced mRNA reads的终值经过PCA降维后的横坐标;
    y0:代表spliced mRNA reads的初始值经过PCA降维后的纵坐标;
    y1:代表spliced mRNA reads的终值经过PCA降维后的纵坐标;

    那么对于每一个细胞来说,在确定箭头指向的时候,并非是选取所有基因来做特征选取,而是利用knn对基因进行一定的筛选,利用表达量特征比较相似的基因来确定箭头的指向

    相关文章

      网友评论

        本文标题:velocyto.R画图中箭头的指向

        本文链接:https://www.haomeiwen.com/subject/ddwanltx.html