大量Bioconductor包包含扩展的标准SummarizedExperiment
类的SummarizedExperiment包中。这使得开发人员可以利用的bob电竞体育官网力量SummarizedExperiment
同步数据和元数据的表示,同时还容纳专门为特定的科学应用程序数据结构。本文旨在提供一个developer-level“最佳实践”参考这些派生类的创建。
介绍各种概念,我们将开始一个简单的派生类,不添加任何新的插槽。这是额外的约束时偶尔有用需要被放置在派生类。在这个例子中,我们假设我们希望我们班举行一个最小“计数”
分析包含非负价值1为简单起见,我们不会担心执行整数类型,作为分数值是可能的,例如,在处理预期的数量。。
我们名字的新类CountSE
和使用定义它setClass
函数的方法包,作为所有S4类是传统。我们使用Roxygen的#”
标记触发导入/导出报表的生成名称空间
我们的包。
# @export # # @ import方法”@importClassesFrom SummarizedExperiment SummarizedExperiment .CountSE < - setClass (“CountSE”,包含=“SummarizedExperiment”)
我们定义一个构造函数,该函数接受一个矩阵来创建一个计数CountSE
对象。我们使用…
通过进一步的论据SummarizedExperiment
构造函数,它可以让我们避免测量所有的参数。
#“@export #”@importFrom SummarizedExperiment SummarizedExperiment CountSE < -函数(计数,…){se < - SummarizedExperiment(列表(数量=计数),…).CountSE (se)}
我们定义一个有效方法,强制约束,我们前面所述。这是通过定义一个函数使用有效性setValidity2
从S4Vectors包2这让我们关掉有效性检查在中间对象的内部函数可能不是有效的函数的范围内。。返回一个字符串显示,有一个问题和触发器R会话中的一个错误。
setValidity2 (“CountSE函数(对象){味精< - NULL如果(assayNames(对象)[1]! =“计数”){味精< - c(味精,必须首先分析“计数”)}如果(min(化验(对象)< 0){味精< - c(味精、计数”中的“负)}如果(is.null(味精)){真}其他味精})
(在“CountSE # #类。GlobalEnv“# # # #槽:# # # #名称:colData化验名字elementMetadata # #类:DataFrame Assays_OR_NULL character_OR_NULL DataFrame # # # #名:元数据类:# # # # # #扩展列表:# #阶级”SummarizedExperiment”,直接# #类“RectangularData”,按类“SummarizedExperiment”,距离2 # #类“向量”,按类“SummarizedExperiment”,距离2 # #类“注释”,按类“SummarizedExperiment”,距离3 # #类“vector_OR_Vector”,按类“SummarizedExperiment”,距离3
构造函数的收益率预期输出计数时提供:
CountSE(矩阵(rpois(100,λ= 1),ncol = 5))
# # # #类:CountSE暗淡:20 5 # #元数据(0):# #化验(1):计数# # rownames:零构成了rowData名称(0):# # # # colnames:零# # colData名称(0):
…和一个(预期的)错误,否则:
CountSE(矩阵(rnorm (100), ncol = 5))
# # validObject误差(.Object):无效类“CountSE”对象:# #负值在“数量”
一个通用的函数是一组具有相同名称的操作在不同的类。在一个对象上调用通用,S4调度系统将选择最适当的函数使用基于对象类。这允许用户和开发人员编写代码无关的输入类的类bob电竞体育官网型。
假设它是获得特定的科学感兴趣的数量与一个翻转的迹象。我们观察到没有现有的仿制药,做这个任务,例如,在BiocGenerics或S4Vectors3如果你有一个想法一个普遍适用的通用,还不可用,请联系Bioconductor核心团队。。相反,我们定义一个新的通用negcounts
:
# ' @export setGeneric (“negcounts函数(x,…) standardGeneric (“negcounts”))
# # [1]“negcounts”
然后,我们为我们定义一个特定的方法CountSE
类4的…
在泛型函数定义意味着自定义参数withDimnames =
可以提供特定的方法,如果必要的。:
#“@export #”@importFrom SummarizedExperiment化验setMethod (“negcounts”、“CountSE”,函数(x, withDimnames = TRUE){化验(x, withDimnames = withDimnames)})
如果任何其他开发人员需要计bob电竞体育官网算-计数为自己的课程,他们可以简单地使用negcounts
一般定义在我们的包。
惯例是把所有类定义(即。,setClass
文件命名的语句)AllClasses.R
在文件命名,所有新通用的定义AllGenerics.R
字母数字混合,所有方法定义在文件要求低于前两个。这是因为R由字母数字顺序整理文件在构建方案。关键是排序(定义)和泛型类的发生之前相应的方法,否则将会出现错误。如果字母数字排序是不合适的,开发人员可以手动指定排序顺序使用bob电竞体育官网整理:
在描述
文件,请参见编写R扩展为更多的细节。
在实践中,大多数派生类都需要存储特定于应用程序的数据结构。对于本文档的其余部分,我们将考虑到派生类的自定义槽等结构。首先,我们考虑一维数据结构:
rowVec
:1:1的映射每个值的行SummarizedExperiment
。colVec
:1:1的映射每个值的列SummarizedExperiment
。可以使用任何1 d结构是否支持长度
,c
,(
和(< -
。为简单起见,我们将使用整数向量* .vec
槽。
我们也考虑一些二维数据结构:
rowToRowMat
:1:1映射从每一行一行的SummarizedExperiment
。colToColMat
:1:1的每一列一列的映射SummarizedExperiment
。rowToColMat
:1:1的映射每行的列SummarizedExperiment
。colToRowMat
:1:1映射从每一列的行SummarizedExperiment
。可以使用任何二维结构是否支持nrow
,ncol
,cbind
,rbind
,(
和(< -
。为简单起见,我们将使用(数字)的矩阵* .mat
槽。
类的定义是通过使用setClass
,使用槽=
参数指定新的自定义槽5坏处也没有重复Roxygen标记,它显式地指定为每个类和函数所需的进口。。
# @export # # @ import方法”@importClassesFrom SummarizedExperiment SummarizedExperiment .ExampleClass < - setClass (“ExampleClass槽=表示(rowVec =“整数”,colVec =“整数”,rowToRowMat =“矩阵”,colToColMat =“矩阵”,rowToColMat =“矩阵”,colToRowMat =“矩阵”),包含=“SummarizedExperiment”)
构造函数应该提供一些参数设置新的插槽派生类的定义。默认值应该设置这样调用构造函数不带任何参数返回一个有效ExampleClass
对象。
#“@export #”@importFrom SummarizedExperiment SummarizedExperiment ExampleClass < -函数(rowVec =整数(0),colVec =整数(0),rowToRowMat =矩阵(0,0,0),colToColMat =矩阵(0,0,0),rowToColMat =矩阵(0,0,0),colToRowMat =矩阵(0,0,0),…){se < - SummarizedExperiment (…) .ExampleClass (se, rowVec = rowVec colVec = colVec rowToRowMat = rowToRowMat colToColMat = colToColMat rowToColMat = rowToColMat colToRowMat = colToRowMat)}
我们定义一些getter泛型包含1 d的自定义槽结构。
# ' @export setGeneric (“rowVec函数(x,…) standardGeneric (“rowVec”))
# # [1]“rowVec”
# ' @export setGeneric (“colVec函数(x,…) standardGeneric (“colVec”))
# # [1]“colVec”
然后,我们为这些泛型定义特定于类的方法。注意withDimnames = TRUE
参数,执行一致性提取的对象和原始的名字SummarizedExperiment
。可以关掉这个更大的效率,例如,供内部使用,名字不是必要的。
# ' @export setMethod (“rowVec”、“ExampleClass”,函数(x, withDimnames = TRUE) {< - x@rowVec如果(withDimnames)名称()< - rownames (x)}) # ' @export setMethod (“colVec”、“ExampleClass”,函数(x, withDimnames = TRUE) {< - x@colVec如果(withDimnames)名称()< - colnames (x)})
我们重复这个过程的二维结构。
# ' @export setGeneric (“rowToRowMat函数(x,…) standardGeneric (“rowToRowMat”))
# # [1]“rowToRowMat”
# ' @export setGeneric (“colToColMat函数(x,…) standardGeneric (“colToColMat”))
# # [1]“colToColMat”
# ' @export setGeneric (“rowToColMat函数(x,…) standardGeneric (“rowToColMat”))
# # [1]“rowToColMat”
# ' @export setGeneric (“colToRowMat函数(x,…) standardGeneric (“colToRowMat”))
# # [1]“colToRowMat”
再一次,我们为这些泛型定义特定于类的方法。
# ' @export setMethod (“rowToRowMat”、“ExampleClass”,函数(x, withDimnames = TRUE) {< - x@rowToRowMat如果(withDimnames) rownames () < - rownames (x)}) # ' @export setMethod (“colToColMat”、“ExampleClass”,函数(x, withDimnames = TRUE) {< - x@colToColMat如果(withDimnames) colnames () < - colnames (x)}) # ' @export setMethod (“rowToColMat”、“ExampleClass”,函数(x, withDimnames = TRUE) {< - x@rowToColMat如果(withDimnames) rownames () < - colnames (x)}) # ' @export setMethod (“colToRowMat”、“ExampleClass”,函数(x, withDimnames = TRUE) {< - x@colToRowMat如果(withDimnames) colnames () < - rownames (x)})
SummarizedExperiment
槽中定义的getter方法SummarizedExperiment可以直接用于检索数据从槽的基类。这些通常不需要任何派生类求变。然而,如果它是必要的,应当使用的方法callNextMethod
在内部。这将调用该方法的基础SummarizedExperiment
的输出类,可以根据需要修改。
#“@export #”@importMethodsFrom构成了rowData setMethod SummarizedExperiment(构成了rowData”“、“ExampleClass”函数(x,…) {< - callNextMethod() #做额外的事情。额外的< - runif美元(nrow()) #构成了rowData对象返回。})
我们使用setValidity2
定义有效性函数ExampleClass
。我们使用前面定义的getter函数来检索位置值,而不是使用@
。这通常是一个好主意保持接口与实现分离6这防止改变槽的名字,简化了开发当存储模式不同于概念意义的数据,例如,对效率的目的。。我们还设置withDimnames = FALSE
getter调用,为内部函数一致的命名是没有必要的。
# ' @importFrom BiocGenerics NCOL NROW setValidity2 (“ExampleClass函数(对象){NR < - NROW(对象)数控< - NCOL(对象)味精< -零# 1 d如果(长度(rowVec(对象,withDimnames = FALSE)) ! = NR){味精< - c(味精、”“rowVec”应该长度等于的行数”)}如果(长度(colVec(对象,withDimnames = FALSE)) ! = NC){味精< - c(味精、”“colVec”应该长度等于列数”)}# 2 d如果(NROW (rowToRowMat(对象,withDimnames = FALSE)) ! = NR){味精< - c(味精、”“NROW (rowToRowMat)应该等于的行数”)}如果(NCOL (colToColMat(对象,withDimnames = FALSE)) ! = NC){味精< - c(味精、”“NCOL (colToColMat)应该等于列数”)}如果(NROW (rowToColMat(对象,withDimnames = FALSE)) ! = NC){味精< - c(味精、”“NROW (rowToColMat)应该等于列数”)}如果(NCOL (colToRowMat(对象,withDimnames = FALSE)) ! = NR){味精< - c(味精、”“NCOL (colToRowMat)应该等于的行数”)}如果(长度(味精)){味精}其他真正})
(在“ExampleClass # #类。GlobalEnv“# # # #槽:# # # #名称:rowVec colVec rowToRowMat colToColMat # #类:整数整数矩阵矩阵# # # #名称:rowToColMat colToRowMat colData化验# #类:矩阵矩阵DataFrame Assays_OR_NULL # # # #名称:名称elementMetadata # #元数据类:character_OR_NULL DataFrame列表# # # #延伸:# #阶级”SummarizedExperiment”,直接# #类“RectangularData”,按类“SummarizedExperiment”,距离2 # #类“向量”,按类“SummarizedExperiment”,距离2 # #类“注释”,按类“SummarizedExperiment”,距离3 # #类“vector_OR_Vector”,按类“SummarizedExperiment”,距离3
我们使用NCOL
和NROW
方法从BiocGenerics这些支持各种Bioconductor对象,而基本方法不。
显示
方法默认的显示
方法将只显示信息SummarizedExperiment
槽。我们可以增加它显示一些有关方面的自定义槽。这是通过调用基础显示
方法在印刷之前附加字段。
#“@export #”@importMethodsFrom SummarizedExperiment显示setMethod(“秀”,“ExampleClass”,函数(对象){callNextMethod()猫(“rowToRowMat”ncol (rowToRowMat(对象),“列\ n”,“colToColMat”nrow (colToColMat(对象),“\ n行”,“rowToColMat”ncol (rowToRowMat(对象),“列\ n”,“colToRowMat”ncol (rowToRowMat(对象),“行\ n”, 9 = " ")})
我们定义一些setter方法包含1 d的自定义槽结构。这通常需要创建新的泛型。
# ' @export setGeneric (“rowVec < -函数(x,…,值)standardGeneric (rowVec < -))
# # [1]“rowVec < - - - - - -”
# ' @export setGeneric (“colVec < -函数(x,…,值)standardGeneric (colVec < -))
# # [1]“colVec < - - - - - -”
我们为这些泛型定义特定于类的方法。注意,使用validObject
确保分配输入仍是有效的。
# ' @export setReplaceMethod (“rowVec”、“ExampleClass”,函数(x,价值){x@rowVec < -价值validObject x (x)}) # ' @export setReplaceMethod (“colVec”、“ExampleClass”,函数(x,价值){x@colVec < -价值validObject x (x)})
我们重复这个过程的二维结构。
# ' @export setGeneric (“rowToRowMat < -函数(x,…,值)standardGeneric (rowToRowMat < -))
# # [1]“rowToRowMat < - - - - - -”
# ' @export setGeneric (“colToColMat < -函数(x,…,值)standardGeneric (colToColMat < -))
# # [1]“colToColMat < - - - - - -”
# ' @export setGeneric (“rowToColMat < -函数(x,…,值)standardGeneric (rowToColMat < -))
# # [1]“rowToColMat < - - - - - -”
# ' @export setGeneric (“colToRowMat < -函数(x,…,值)standardGeneric (colToRowMat < -))
# # [1]“colToRowMat < - - - - - -”
再一次,我们为这些泛型定义特定于类的方法。
# ' @export setReplaceMethod (“rowToRowMat”、“ExampleClass”,函数(x,价值){x@rowToRowMat < -价值validObject x (x)}) # ' @export setReplaceMethod (“colToColMat”、“ExampleClass”,函数(x,价值){x@colToColMat < -价值validObject x (x)}) # ' @export setReplaceMethod (“rowToColMat”、“ExampleClass”,函数(x,价值){x@rowToColMat < -价值validObject x (x)}) # ' @export setReplaceMethod (“colToRowMat”、“ExampleClass”,函数(x,价值){x@colToRowMat < -价值validObject x (x)})
SummarizedExperiment
槽再一次,我们可以使用setter方法中定义SummarizedExperiment修改基类中的槽。这些通常不需要任何求变。然而,如果它是必要的,应当使用的方法callNextMethod
内部:
构成了rowData < #“@export #”@importMethodsFrom SummarizedExperiment”——“setReplaceMethod(构成了rowData”“、“ExampleClass”函数(x,…值){y < - callNextMethod() #返回一个修改ExampleClass #做额外的事情。消息(“嗨! \ n”) y})
想象一下,我们想写一个函数,返回一个修改ExampleClass
的迹象,例如* .vec
字段是相反的。例如,我们会假装我们想写一个正常化
功能,使用通用的BiocGenerics。
#“@export #”@importFrom BiocGenerics setMethod正常化(“正常化”、“ExampleClass”,函数(对象){#做一些令人兴奋的。,把新迹象。行< - -rowVec(对象,withDimnames = FALSE)。col <- -colVec(object, withDimnames=FALSE) BiocGenerics:::replaceSlots(object, rowVec=new.row, colVec=new.col, check=FALSE) })
我们使用BiocGenerics::: replaceSlots
我们上面定义的setter方法。这是因为我们的setter执行有效性检查是不必要的,如果我们知道修改不能改变对象的有效性。的replaceSlots
函数允许我们跳过这些有效性检查(检查= FALSE
为提高效率)。
的关键力量SummarizedExperiment
类构造子集是同步不同(元)数据字段。这避免了簿记在交互式分析会话错误,保证一致性。我们需要确保我们的自定义槽中的值也子集。
# ' @export setMethod (“(”、“ExampleClass”、功能下降(x, i, j = TRUE){房车< - rowVec (x, withDimnames = FALSE) cv < - colVec (x, withDimnames = FALSE) rrm < - rowToRowMat (x, withDimnames = FALSE) ccm < - colToColMat (x, withDimnames = FALSE) rcm < - rowToColMat (x, withDimnames = FALSE) crm < - colToRowMat (x, withDimnames = FALSE)如果(!失踪(i)) {(is.character(我)){fmt < - paste0(“<”类(x),“>[我]索引越界:% s”)我< - SummarizedExperiment::: .SummarizedExperiment。charbound(我rownames (x), fmt)}我< - as.vector (i)房车< - rv[我]rrm < - rrm(我,放弃= FALSE) crm < - crm(,我滴= FALSE)}如果(!失踪(j)) {(is.character (j)) {fmt < - paste0(“<”类(x),“> [j]索引越界:% s”) < - SummarizedExperiment::: .SummarizedExperiment j。charbound( j, colnames(x), fmt ) } j <- as.vector(j) cv <- cv[j] ccm <- ccm[,j,drop=FALSE] rcm <- rcm[j,,drop=FALSE] } out <- callNextMethod() BiocGenerics:::replaceSlots(out, rowVec=rv, colVec=cv, rowToRowMat=rrm, colToColMat=ccm, rowToColMat=rcm, colToRowMat=crm, check=FALSE) })
注意特殊的代码来处理字符索引,和使用callNextMethod
子集的基础SummarizedExperiment
槽。
任务可以执行类似的组成部分,但需要指定签名,以便替换值是相同的类。这通常是必要的合理的更换自定义槽。
# ' @export setReplaceMethod (“[”, c (“ExampleClass”,“任何”,“任何”、“ExampleClass”),函数(x, i, j,……,value) { rv <- rowVec(x, withDimnames=FALSE) cv <- colVec(x, withDimnames=FALSE) rrm <- rowToRowMat(x, withDimnames=FALSE) ccm <- colToColMat(x, withDimnames=FALSE) rcm <- rowToColMat(x, withDimnames=FALSE) crm <- colToRowMat(x, withDimnames=FALSE) if (!missing(i)) { if (is.character(i)) { fmt <- paste0("<", class(x), ">[i,] index out of bounds: %s") i <- SummarizedExperiment:::.SummarizedExperiment.charbound( i, rownames(x), fmt ) } i <- as.vector(i) rv[i] <- rowVec(value, withDimnames=FALSE) rrm[i,] <- rowToRowMat(value, withDimnames=FALSE) crm[,i] <- colToRowMat(value, withDimnames=FALSE) } if (!missing(j)) { if (is.character(j)) { fmt <- paste0("<", class(x), ">[,j] index out of bounds: %s") j <- SummarizedExperiment:::.SummarizedExperiment.charbound( j, colnames(x), fmt ) } j <- as.vector(j) cv[j] <- colVec(value, withDimnames=FALSE) ccm[,j] <- colToColMat(value, withDimnames=FALSE) rcm[j,] <- rowToColMat(value, withDimnames=FALSE) } out <- callNextMethod() BiocGenerics:::replaceSlots(out, rowVec=rv, colVec=cv, rowToRowMat=rrm, colToColMat=ccm, rowToColMat=rcm, colToRowMat=crm, check=FALSE) })
我们需要定义一个rbind
我们的自定义类的方法。这是通过结合自定义在类实例进行槽。
# ' @export setMethod (“rbind”、“ExampleClass”,函数(…deparse.level = 1) {args < -列表(…)。房车< -拉普(args, rowVec withDimnames = FALSE)。rrm < -拉普(args, rowToRowMat withDimnames = FALSE)。crm < -拉普(args, colToRowMat withDimnames = FALSE)。房车< -。call(c, all.rv) all.rrm <- do.call(rbind, all.rrm) all.crm <- do.call(cbind, all.crm) # Checks for identical column state. ref <- args[[1]] ref.cv <- colVec(ref, withDimnames=FALSE) ref.ccm <- colToColMat(ref, withDimnames=FALSE) ref.rcm <- rowToColMat(ref, withDimnames=FALSE) for (x in args[-1]) { if (!identical(ref.cv, colVec(x, withDimnames=FALSE)) || !identical(ref.ccm, colToColMat(x, withDimnames=FALSE)) || !identical(ref.rcm, rowToColMat(x, withDimnames=FALSE))) { stop("per-column values are not compatible") } } old.validity <- S4Vectors:::disableValidity() S4Vectors:::disableValidity(TRUE) on.exit(S4Vectors:::disableValidity(old.validity)) out <- callNextMethod() BiocGenerics:::replaceSlots(out, rowVec=all.rv, rowToRowMat=all.rrm, colToRowMat=all.crm, check=FALSE) })
我们检查每列的插槽在所有元素以确保它们是相同的。这个保护用户免受结合不兼容的对象。然而,这取决于应用程序,这可能不是必要的所有槽(或成本太高),在这种情况下,它可以是有限的关键时段。
我们也使用disableValidity
方法以避免基地的有效性检查cbind
方法。这是因为对象是技术无效时,基槽结合但之前更新新的自定义槽的组合值。的on.exit
调用确保恢复初始设置有效性函数的退出。
我们同样定义一个cbind
方法来处理自定义槽。
# ' @export setMethod (“cbind”、“ExampleClass”,函数(…deparse.level = 1) {args < -列表(…)。cv <- lapply(args, colVec, withDimnames=FALSE) all.ccm <- lapply(args, colToColMat, withDimnames=FALSE) all.rcm <- lapply(args, rowToColMat, withDimnames=FALSE) all.cv <- do.call(c, all.cv) all.ccm <- do.call(cbind, all.ccm) all.rcm <- do.call(rbind, all.rcm) # Checks for identical column state. ref <- args[[1]] ref.rv <- rowVec(ref, withDimnames=FALSE) ref.rrm <- rowToRowMat(ref, withDimnames=FALSE) ref.crm <- colToRowMat(ref, withDimnames=FALSE) for (x in args[-1]) { if (!identical(ref.rv, rowVec(x, withDimnames=FALSE)) || !identical(ref.rrm, rowToRowMat(x, withDimnames=FALSE)) || !identical(ref.crm, colToRowMat(x, withDimnames=FALSE))) { stop("per-row values are not compatible") } } old.validity <- S4Vectors:::disableValidity() S4Vectors:::disableValidity(TRUE) on.exit(S4Vectors:::disableValidity(old.validity)) out <- callNextMethod() BiocGenerics:::replaceSlots(out, colVec=all.cv, colToColMat=all.ccm, rowToColMat=all.rcm, check=FALSE) })
SummarizedExperiment
我们定义了一个强制的方法SummarizedExperiment
为我们的新对象ExampleClass
类。
# ' @exportMethods强迫刚毛(“SummarizedExperiment”、“ExampleClass”,函数(){新(“ExampleClass”,从rowVec =整数(nrow(从),colVec =整数(ncol(从),rowToRowMat =矩阵(0,nrow(从),0),colToColMat =矩阵(0,0,ncol(从),rowToColMat =矩阵(0,ncol(从),0),colToRowMat =矩阵(0,0,nrow(从)))})
…这是预期:
se < - SummarizedExperiment(矩阵(rpois(100,λ= 1),ncol = 5)), (se,“CountSE”)
# # # #类:CountSE暗淡:20 5 # #元数据(0):# #化验(1):“# # rownames:零构成了rowData名称(0):# # # # colnames:零# # colData名称(0):
这不是严格我们之前所必需的CountSE
类没有添加新的插槽。当然,开发者仍然可以显bob电竞体育官网式编写转换方法执行额外的工作来实现一个“明智的”转换——例如,一个可能需要第一个矩阵的绝对所有条目的值,以确保CountSE
所有的输入是有效的吗SummarizedExperiment
对象。
RangedSummarizedExperiment
注意,如果我们推导的RangedSummarizedExperiment
(例如,对于一些ExampleClassRanged
),它会从两个必要定义显式转换RangedSummarizedExperiment
和SummarizedExperment
来ExampleClassRanged
。从理论上讲,我们应该只需要定义一个转换RangedSummarizedExperiment
来ExampleClassRanged
——然后,任何试图转换从一个SummarizedExperiment
来ExampleClassRanged
将:
SummarizedExperiment
来RangedSummarizedExperiment
转换器中定义SummarizedExperiment,然后RangedSummarizedExperiment
来ExampleClassRanged
我们刚才定义转换器。不幸的是,在涉及间接转换成子类,S4系统自动创建的任何转换的方法没有明确的定义。这意味着正确的方法不使用上面列出的“链”,当从一个转换SummarizedExperiment
到一个ExampleClassRanged
对象。自动生成的方法相反,这可能不会产生一个有效的对象时转换的细节被忽略了。我们避免这种场景通过显式地定义两个转换器SummarizedExperiment
和RangedSummarizedExperiment
来ExampleClassRanged
。
我们测试使用的新方法expect_ *
函数的testthat包中。每个函数将测试一个表达式和报错并不如预期的输出。这可以用来构造单元测试的测试/
子目录的包。单元测试确保方法的行为符合预期时,特别是在任何可能在未来执行的重构。
测试中,我们将构建的一个实例ExampleClass
有10行和7列:
房车< - 1:10 CV < -样例(50,7)RRM < -矩阵(runif (30), nrow = 10) CCM < -矩阵(rnorm (14), ncol = 7) RCM < -矩阵(runif (21), nrow = 7) CRM < -矩阵(rnorm (20), ncol = 10)的< - ExampleClass (rowVec =房车,colVec =简历,rowToRowMat = RRM colToColMat = CCM, rowToColMat = RCM colToRowMat = CRM,化验=列表(数量=矩阵(rnorm (70), nrow = 10)), colData = DataFrame(哟=信[1:7]),rowData = DataFrame(耶=信[1:10]))
我们还将添加一些行和列的名称,后面我们将派上用场。
rownames(事)< - paste0 (“FEATURE_ seq_len (nrow(东西)))colnames(事)< - paste0 (“SAMPLE_ seq_len (ncol(东西)))的事情
# # # #类:ExampleClass暗淡:10 7 # #元数据(0):# #化验(1):计数# # rownames (10): FEATURE_1 FEATURE_2……构成了rowData名字FEATURE_9 FEATURE_10 # #(2):耶额外# # colnames (7): SAMPLE_1 SAMPLE_2……SAMPLE_6 SAMPLE_7 # # colData名称(1):啊# # rowToRowMat有3列# # # # rowToColMat colToColMat有2行3列# # colToRowMat 3行
我们测试,的事情
我们构造的对象是有效的:
expect_true (validObject(的事)
另一个有用的单元测试包括检查默认构造函数(内部和出口)产生有效的对象:
expect_true (validObject (.ExampleClass())) #内部expect_true (validObject (ExampleClass())) #出口
我们也可以验证有效性方法无效的对象上的失败:
expect_error (ExampleClass (rowVec = 1),“rowVec”) expect_error (ExampleClass (colVec = 1),“colVec”) expect_error (ExampleClass (rowToRowMat = rbind (1)),“rowToRowMat”) expect_error (ExampleClass (colToColMat = rbind (1)),“colToColMat”) expect_error (ExampleClass (rowToColMat = rbind (1)),“rowToColMat”) expect_error (ExampleClass (colToRowMat = rbind (1)),“colToRowMat”)
最后,我们检查强制方法产生一个有效的对象。
se <——(的事情,“SummarizedExperiment”) conv <——(se, ExampleClass) expect_true (validObject (conv))
测试1 d getter方法:
expect_identical(名字(rowVec(的事),rownames(东西))expect_identical (rowVec(东西,withDimnames = FALSE), RV) expect_identical(名字(colVec(的事),colnames(东西))expect_identical (colVec(东西,withDimnames = FALSE),简历)
测试2 d getter方法:
expect_identical (rowToRowMat(东西,withDimnames = FALSE), RRM) expect_identical (rownames (rowToRowMat(的事),rownames(东西))expect_identical (colToColMat(东西,withDimnames = FALSE), CCM) expect_identical (colnames (colToColMat(的事),colnames(东西))expect_identical (rowToColMat(东西,withDimnames = FALSE), RCM) expect_identical (rownames (rowToColMat(的事),colnames(东西))expect_identical (colToRowMat(东西,withDimnames = FALSE), CRM) expect_identical (colnames (colToRowMat(的事),rownames(东西))
测试自定义rowData
方法:
expect_true(“额外”% % colnames构成了rowData(东西))()
测试1 d setter方法:
rowVec(事)< - 0:9 expect_equivalent (rowVec(的事),0:9)colVec(事)< - 7:1 expect_equivalent (colVec(的事),7:1)
测试2 d setter方法:
老< - rowToRowMat(事)rowToRowMat(事)< -孩子expect_equivalent (rowToRowMat(的事),孩子)老< - colToColMat(事)colToColMat(事)< - 2 *旧expect_equivalent (colToColMat(的事),2 *旧)老< - rowToColMat(事)rowToColMat(事)< -老+ 1 expect_equivalent (rowToColMat(的事),老+ 1)老< - colToRowMat(事)colToRowMat(事)<岁/ 10 expect_equivalent (colToRowMat(的事),旧/ 10)
测试我们的习俗rowData < -
方法:
expect_message构成了rowData(件)(< - 1,“嗨”)
我们确保我们能够成功地引发错误的有效方法:
expect_error (rowVec(事情)< - 0,“rowVec”) expect_error (colVec(事)< - 0,“colVec”) expect_error (rowToRowMat(事情)<——rbind (0),“rowToRowMat”) expect_error (colToColMat(事情)<——rbind (0),“colToColMat”) expect_error (rowToColMat(事情)<——rbind (0),“rowToColMat”) expect_error (colToRowMat(事情)<——rbind (0),“colToRowMat”)
我们测试我们的新正常化
方法:
修改< -正常化(事)expect_equal (rowVec(修改),-rowVec(东西))expect_equal (colVec(修改),-colVec(东西))
由行构造子集:
subbyrow < -件事[1:5]expect_identical (rowVec (subbyrow) rowVec(事)[1:5])expect_identical (rowToRowMat (subbyrow) rowToRowMat(事)[1:5,])expect_identical (colToRowMat (subbyrow) colToRowMat(事)[1:5])#列影响……expect_identical (colVec (subbyrow) colVec(东西))expect_identical (colToColMat (subbyrow) colToColMat(东西))expect_identical (rowToColMat (subbyrow) rowToColMat(东西))
通过列构造子集:
subbycol < -件事[1:2]expect_identical (colVec (subbycol) colVec(事)[1:2])expect_identical (colToColMat (subbycol) colToColMat(事)[1:2])expect_identical (rowToColMat (subbycol) rowToColMat(事)[1:2,])#行影响……expect_identical (rowVec (subbycol) rowVec(东西))expect_identical (rowToRowMat (subbycol) rowToRowMat(东西))expect_identical (colToRowMat (subbycol) colToRowMat(东西))
检查构造子集创建一个空对象是可能的:
norow < -件事[0]expect_true (validObject (norow)) expect_identical (nrow (norow), 0 l) nocol < -件事[0]expect_true (validObject (nocol)) expect_identical (ncol (nocol), 0 l)
子集的任务:
修改< -修改(1:5,1:2)< -东西[5:1,2:1]rperm < - c (5:1, 6: nrow(东西))expect_identical (rowVec(修改),rowVec(事)[rperm]) expect_identical (rowToRowMat(修改),rowToRowMat(事)[rperm,]) expect_identical (colToRowMat(修改),colToRowMat(事)[,rperm]) cperm < - c (2:1, 3: ncol(东西))expect_identical (colVec(修改),colVec(事)[cperm]) expect_identical (colToColMat(修改),colToColMat(事)[,cperm]) expect_identical (rowToColMat(修改),rowToColMat(件)(cperm,))
检查后我们获得相同的对象简单赋值操作:
修改< -修改[0]< -东西[0]expect_equal修改(修改件)[1]< -件事[1]expect_equal(修改件)修改[0]< -件事[0]expect_equal修改(修改件)[1]< -件事[1]expect_equal(修改)
我们仔细检查,我们可以得到一个错误无效的任务:
expect_error(修改[1]< -(0,0),更换长度为0)
结合行:
结合< - rbind(东西,东西)rtwice <——代表(seq_len (nrow(的事),2)expect_identical (rowVec(组合),rowVec(事)[rtwice]) expect_identical (rowToRowMat(组合),rowToRowMat(事)[rtwice,]) expect_identical (colToRowMat(组合),colToRowMat(事)[,rtwice]) #列不受影响:expect_identical (colVec(组合),colVec(东西))expect_identical (colToColMat(组合),colToColMat(东西))expect_identical (rowToColMat(组合),rowToColMat(东西))
并结合所列。我们使用test_equivalent
为简单起见,在列名修改保持唯一性。
结合< - cbind(东西,东西)ctwice <——代表(seq_len (ncol(的事),2)expect_equivalent (colVec(组合),colVec(事)[ctwice]) expect_equivalent (colToColMat(组合),colToColMat(事)[,ctwice]) expect_equivalent (rowToColMat(组合),rowToColMat(事)[ctwice,]) #行不受影响:expect_equivalent (rowVec(组合),rowVec(东西))expect_equivalent (rowToRowMat(组合),rowToRowMat(东西))expect_equivalent (colToRowMat(组合),colToRowMat(东西))
检查我们得到相同的对象如果我们把一个对象或一个空对象:
expect_equal(东西,rbind(东西))expect_equal(东西,rbind(东西,东西[0]))expect_equal(东西,cbind(东西))expect_equal(东西,cbind(东西,东西[0]))
和检查兼容性错误是正确的:
[expect_error (rbind(东西,东西,ncol(的事):1]),“不兼容”)expect_error (cbind(东西,东西[nrow(的事):1)),“不兼容”)
我们建议(即至少创建两个单独的文档。* .Rd
)文件。第一个文件文档类和构造函数:
\名字{ExampleClass类}\别名{ExampleClass-class} {ExampleClass} \ \别名标题{ExampleClass类}\描述{ExampleClass类的概述和构造函数。}\使用{ExampleClass (rowVec =整数(0),colVec =整数(0),#等等,等等,这里我就不写出来。)}\参数{\项{rowVec}{整数向量映射到行,代表了重要的事情。}\item{colVec}{An integer vector mapping to the columns, representing something else that's important.} % And so on... } \details{ % Some context on why this class and its slots are necessary. The ExampleClass provides an example of how to derive from the SummarizedExperiment class. Its slots have no scientific meaning and are purely for demonstration purposes. }
第二个文件会记录所有个人的方法:
名字\ {ExampleClass方法}%新的泛型:{rowVec} \ \别名别名{rowVec, ExampleClass-method} {{rowVec < -} \ \别名别名rowVec < - - - - - -, ExampleClass-method} % %等等…%已经有一个通用的:{{[,ExampleClass-method} \ \别名别名(ExampleClass,任何方法}\别名{[ExampleClass,任何,任何方法}{rbind, ExampleClass-method} % % \别名等等……描述\标题{ExampleClass方法}\ {ExampleClass类的方法。}\usage{ \S4method{rowVec}{ExampleClass}(x, withDimnames=FALSE) \S4method{rowVec}{ExampleClass}(x) <- value \S4method{[}{ExampleClass}(x, i, j, drop=TRUE) \S4method{rbind}{ExampleClass}(..., , i, j, drop=TRUE) %% And so on... } \arguments{ \item{x}{An ExampleClass object.} \item{withDimnames}{A logical scalar indicating whether dimension names from \code{x} should be returned.} \item{value}{ For \code{rowVec}, an integer vector of length equal to the number of rows. For \code{colVec}, an integer vector of length equal to the number of columns. } %% And so on... } \section{Accessors}{ % Add some details about accessor behaviour here. } \section{Subsetting}{ % Add some details about subsetting behaviour here. } \section{Combining}{ % Add some details about combining behaviour here. }
sessionInfo ()
# # R版本4.1.0(2021-05-18)# #平台:x86_64-pc-linux-gnu(64位)# #下运行:Ubuntu 20.04.2 LTS # # # #矩阵产品:默认# #布拉斯特区:/home/biocbuild/bbs - 3.13 - bioc / R / lib / libRblas。所以# # LAPACK: /home/biocbuild/bbs - 3.13 - bioc / R / lib / libRlapack。# # # #语言环境:# # [1]LC_CTYPE = en_US。utf - 8 LC_NUMERIC = C # #[3]而= en_GB LC_COLLATE = C # # [5] LC_MONETARY = en_US。utf - 8 LC_MESSAGES = en_US。utf - 8 # # [7] LC_PAPER = en_US。utf - 8 LC_NAME = C # # [9] LC_ADDRESS C = C LC_TELEPHONE = # # [11] LC_MEASUREMENT = en_US。utf - 8 LC_IDENTIFICATION = C附加基本包:# # # # # #[1]平行stats4统计图形grDevices跑龙套数据集# #[8]方法基础# # # #其他附加包:# # [1]testthat_3.0.2 SummarizedExperiment_1.22.0 # # [3] Biobase_2.52.0 GenomicRanges_1.44.0 # # [5] GenomeInfoDb_1.28.0 IRanges_2.26.0 # # [7] S4Vectors_0.30.0 BiocGenerics_0.38.0 # # [9] MatrixGenerics_1.4.0 matrixStats_0.58.0 # # [11] BiocStyle_2.20.0 # # # #通过加载一个名称空间(而不是附加):# # [1]bslib_0.2.5.1 compiler_4.1.0 BiocManager_1.30.15 # # [4] jquerylib_0.1.4 XVector_0.32.0 bitops_1.0-7 # # [7] tools_4.1.0 zlibbioc_1.38.0 pkgload_1.2.1 # # [10] digest_0.6.27 jsonlite_1.7.2 evaluate_0.14 # # [13] lattice_0.20-44 rlang_0.4.11 Matrix_1.3-3 # # [16] DelayedArray_0.18.0 yaml_2.2.1 xfun_0.23 # # [19] GenomeInfoDbData_1.2.6 withr_2.4.2 stringr_1.4.0 # # [22] knitr_1.33 desc_1.3.0 sass_0.4.0 # # [25] rprojroot_2.0.2 grid_4.1.0 glue_1.4.2 # # [28] R6_2.5.0 rmarkdown_2.8 bookdown_0.22 # # [31] waldo_0.2.5 magrittr_2.0.1 htmltools_0.5.1.1 # # [34] stringi_1.6.2 rcurl_1.98 - 1.3 crayon_1.4.1