临时修改R 软件包中的错误函数源代码

在不修改已安装的包的代码的情况下修正源码的错误。

问题描述

问题出现在我使用snapatacv1这个软件包时候,报错:

image-20230427165711131

究其原因是因为新版的R matrix包把原来的Matrix::rBind给改成了rbind函数,而这个包是2018年的老古董,没有改过来,因此必须修正源代码才能继续使用。尝试了各种修改源代码的方式之后,只有本笔记的这种方式可以在修改源代码并让其他更上层的函数成功调用修改后的函数

解决方法

首先,在文件'snapRbind.py'中修复错误,修改后的函数名为mysnapRbind:

#把原来的Matrix::rBind改成了rbind
mysnapRbind <- function (obj1, obj2) 
{
    if (!is.snap(obj1)) {
        stop(paste("Error @snapRbind: obj1 is not a snap object!", 
            sep = ""))
    }
    if (!is.snap(obj2)) {
        stop(paste("Error @snapRbind: obj2 is not a snap object!", 
            sep = ""))
    }
    barcode1 = paste(obj1@file, obj1@barcode, sep = ".")
    barcode2 = paste(obj2@file, obj2@barcode, sep = ".")
    if (length(unique(c(barcode1, barcode2))) < length(barcode1) + 
        length(barcode2)) {
        stop("Error: @snapRbind: identifcal barcodes found in obj1 and obj2!")
    }
    rm(barcode1, barcode2)
    gc()
    if (nrow(obj1@metaData) > 0 && nrow(obj2@metaData) > 0) {
        metaData = rbind(obj1@metaData, obj2@metaData)
    }
    else {
        metaData = data.frame()
    }
    feature1 = obj1@feature
    feature2 = obj2@feature
    if ((length(feature1) == 0) != (length(feature2) == 0)) {
        stop("different feature found in obj1 and obj2!")
    }
    else {
        if (length(feature1) > 0) {
            if (FALSE %in% (feature1$name == feature2$name)) {
                stop("Error: @snapRbind: different feature found in obj1 and obj2!")
            }
            feature = feature1
        }
        else {
            feature = feature1
        }
    }
    gc()
    peak1 = obj1@peak
    peak2 = obj2@peak
    if ((length(peak1) == 0) != (length(peak2) == 0)) {
        stop("different peak found in obj1 and obj2!")
    }
    else {
        if (length(peak1) > 0) {
            if (FALSE %in% (peak1$name == peak2$name)) {
                stop("Error: @snapRbind: different feature found in obj1 and obj2!")
            }
            peak = peak1
        }
        else {
            peak = peak1
        }
    }
    rm(peak1, peak2)
    gc()
    bmat1 = obj1@bmat
    bmat2 = obj2@bmat
    if ((length(bmat1) == 0) != (length(bmat2) == 0)) {
        stop("bmat has different dimentions in obj1 and obj2!")
    }
    else {
        bmat = rbind(bmat1, bmat2)
    }
    rm(bmat1, bmat2)
    gc()
    gmat1 = obj1@gmat
    gmat2 = obj2@gmat
    if ((length(gmat1) == 0) != (length(gmat2) == 0)) {
        stop("gmat has different dimentions in obj1 and obj2!")
    }
    else {
        gmat = rbind(gmat1, gmat2)
    }
    rm(gmat1, gmat2)
    gc()
    pmat1 = obj1@pmat
    pmat2 = obj2@pmat
    if ((length(pmat1) == 0) != (length(pmat2) == 0)) {
        stop("pmat has different dimentions in obj1 and obj2!")
    }
    else {
        pmat = rbind(pmat1, pmat2)
    }
    rm(pmat1, pmat2)
    gc()
    dmat1 = obj1@smat@dmat
    dmat2 = obj2@smat@dmat
    if ((length(dmat1) == 0) != (length(dmat2) == 0)) {
        stop("dmat has different dimentions in obj1 and obj2!")
    }
    else {
        dmat = rbind(dmat1, dmat2)
    }
    rm(dmat1, dmat2)
    gc()
    res = newSnap()
    res@feature = feature
    res@barcode = c(obj1@barcode, obj2@barcode)
    res@file = c(obj1@file, obj2@file)
    res@sample = c(obj1@sample, obj2@sample)
    res@metaData = metaData
    res@bmat = bmat
    res@pmat = pmat
    res@peak = peak
    res@gmat = gmat
    res@smat@dmat = dmat
    res@smat@sdev = obj1@smat@sdev
    return(res)
}

其次在R中:

# 读取自定义函数mysnapRbind
source("/home/xlyang/code_with_vs/R/snapatacdemo/snapRbind.r")
# library('Matrix')
# 添加到环境中
snapRbind <- mySnapRbind
#environment(snapRbind) <- environment()
#environment(snapRbind) = asNamespace('SnapATAC')#不能正确覆盖掉函数
# 解除加载
detach("package:SnapATAC", unload = TRUE)
# 重新加载
library(SnapATAC)
assignInNamespace("snapRbind",snapRbind,ns="SnapATAC")#这句代码至关重要,可以解决其它函数调用snapRbind又回到SnapATAC包导致出错的问题。assignInNamespace 函数的作用是将变量或函数分配到指定命名空间中。在这种情况下,assignInNamespace("snapRbind", snapRbind, ns="SnapATAC") 的作用是将自定义的 snapRbind() 函数分配到 SnapATAC 包的命名空间中,以覆盖原始的 snapRbind() 函数。
#与 assign 函数不同,assignInNamespace 函数分配的变量或函数只能在指定的命名空间中得到访问,并且不会出现在其它命名空间或全局环境中。在这种情况下,这是很有用的,因为它确保我们不会修改或破坏 SnapATAC 包中的原始函数,只是覆盖了在命名空间内的函数。

 x.sp = Reduce(snapRbind, x.sp.ls); #修改后直接调用函数不会出错
 x.sp@metaData["sample"] = x.sp@sample;
 x.sp
 table(x.sp@sample);

# 单元矩阵添加
library(GenomicRanges)
x.sp = addBmatToSnap(x.sp, bin.size=5000); #这个函数内部调用了snapRbind,不会出错

还想要更多代码?不知道怎么搭建?想让别人帮忙生信分析?欢迎来我的闲鱼咨询!价格绝对全网最低

IMG_20230725_170507

文章作者: 星落
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 星落_Blog
生信笔记 生信 修改源码 脚本
喜欢就支持一下吧