Seurat计算foldchange时报错Error in names(x) <- value : 'names' attribute [3] must be the same length as the vector [2]
起初,在计算一个数据的peak fc 时发现这个报错Error in names(x) <- value : 'names' attribute [3] must be the same length as the vector [2],在网上查了很多方法都没有解决,于是打算跑一遍signac官方教程,在官方教程中计算到peak fc 时也是一样报错,于是想到可能不是个人数据原因,而是环境或者包的问题,后面查看排除后发现是seurat包这个FoldChange()这个函数有bug,在目前新版seurat v5.01中得到解决:
查看当前包版本:
packageVersion("Seurat") #4.3.0.1 old for now
packageVersion("Signac") #1.6.0
旧版代码:
#Unuseful function from seurat v4.3.0.1 <seurat/R/differential_expression.R, line 1182>
FoldChange.Seurat <- function(
object,
ident.1 = NULL,
ident.2 = NULL,
group.by = NULL,
subset.ident = NULL,
assay = NULL,
slot = 'data',
reduction = NULL,
features = NULL,
pseudocount.use = NULL,
mean.fxn = NULL,
base = 2,
fc.name = NULL,
...
) {
if (!is.null(x = group.by)) {
if (!is.null(x = subset.ident)) {
object <- subset(x = object, idents = subset.ident)
}
Idents(object = object) <- group.by
}
if (!is.null(x = assay) && !is.null(x = reduction)) {
stop("Please only specify either assay or reduction.")
}
# select which data to use
if (is.null(x = reduction)) {
assay <- assay %||% DefaultAssay(object = object)
data.use <- object[[assay]]
cellnames.use <- colnames(x = data.use)
} else {
data.use <- object[[reduction]]
cellnames.use <- rownames(data.use)
}
cells <- IdentsToCells(
object = object,
ident.1 = ident.1,
ident.2 = ident.2,
cellnames.use = cellnames.use
)
fc.results <- FoldChange(
object = data.use,
cells.1 = cells$cells.1,
cells.2 = cells$cells.2,
features = features,
slot = slot,
pseudocount.use = pseudocount.use,
mean.fxn = mean.fxn,
base = base,
fc.name = fc.name
)
return(fc.results)
}
IdentsToCells <- function(
object,
ident.1,
ident.2,
cellnames.use
) {
#
if (is.null(x = ident.1)) {
stop("Please provide ident.1")
} else if ((length(x = ident.1) == 1 && ident.1[1] == 'clustertree') || is(object = ident.1, class2 = 'phylo')) {
if (is.null(x = ident.2)) {
stop("Please pass a node to 'ident.2' to run FindMarkers on a tree")
}
tree <- if (is(object = ident.1, class2 = 'phylo')) {
ident.1
} else {
Tool(object = object, slot = 'BuildClusterTree')
}
if (is.null(x = tree)) {
stop("Please run 'BuildClusterTree' or pass an object of class 'phylo' as 'ident.1'")
}
ident.1 <- tree$tip.label[GetLeftDescendants(tree = tree, node = ident.2)]
ident.2 <- tree$tip.label[GetRightDescendants(tree = tree, node = ident.2)]
}
if (length(x = as.vector(x = ident.1)) > 1 &&
any(as.character(x = ident.1) %in% cellnames.use)) {
bad.cells <- cellnames.use[which(x = !as.character(x = ident.1) %in% cellnames.use)]
if (length(x = bad.cells) > 0) {
stop(paste0("The following cell names provided to ident.1 are not present in the object: ", paste(bad.cells, collapse = ", ")))
}
} else {
ident.1 <- WhichCells(object = object, idents = ident.1)
}
# if NULL for ident.2, use all other cells
if (length(x = as.vector(x = ident.2)) > 1 &&
any(as.character(x = ident.2) %in% cellnames.use)) {
bad.cells <- cellnames.use[which(!as.character(x = ident.2) %in% cellnames.use)]
if (length(x = bad.cells) > 0) {
stop(paste0("The following cell names provided to ident.2 are not present in the object: ", paste(bad.cells, collapse = ", ")))
}
} else {
if (is.null(x = ident.2)) {
ident.2 <- setdiff(x = cellnames.use, y = ident.1)
} else {
ident.2 <- WhichCells(object = object, idents = ident.2)
}
}
return(list(cells.1 = ident.1, cells.2 = ident.2))
}
新版代码:
#Useful function from seurat v5.0.1 <seurat/R/differential_expression.R, line1314>
FoldChange.Seurat <- function(
object,
ident.1 = NULL,
ident.2 = NULL,
group.by = NULL,
subset.ident = NULL,
assay = NULL,
slot = 'data',
reduction = NULL,
features = NULL,
pseudocount.use = 1,
mean.fxn = NULL,
base = 2,
fc.name = NULL,
...
) {
if (!is.null(x = group.by)) {
if (!is.null(x = subset.ident)) {
object <- subset(x = object, idents = subset.ident)
}
Idents(object = object) <- group.by
}
if (!is.null(x = assay) && !is.null(x = reduction)) {
stop("Please only specify either assay or reduction.")
}
# select which data to use
if (is.null(x = reduction)) {
assay <- assay %||% DefaultAssay(object = object)
data.use <- object[[assay]]
cellnames.use <- colnames(x = data.use)
} else {
data.use <- object[[reduction]]
cellnames.use <- rownames(data.use)
}
cells <- IdentsToCells(
object = object,
ident.1 = ident.1,
ident.2 = ident.2,
cellnames.use = cellnames.use
)
# check normalization method
norm.command <- paste0("NormalizeData.", assay)
norm.method <- if (norm.command %in% Command(object = object) && is.null(x = reduction)) {
Command(
object = object,
command = norm.command,
value = "normalization.method"
)
} else if (length(x = intersect(x = c("FindIntegrationAnchors", "FindTransferAnchors"), y = Command(object = object)))) {
command <- intersect(x = c("FindIntegrationAnchors", "FindTransferAnchors"), y = Command(object = object))[1]
Command(
object = object,
command = command,
value = "normalization.method"
)
} else {
NULL
}
fc.results <- FoldChange(
object = data.use,
cells.1 = cells$cells.1,
cells.2 = cells$cells.2,
features = features,
slot = slot,
pseudocount.use = pseudocount.use,
mean.fxn = mean.fxn,
base = base,
fc.name = fc.name,
norm.method = norm.method
)
return(fc.results)
}
IdentsToCells <- function(
object,
ident.1,
ident.2,
cellnames.use
) {
#
if (is.null(x = ident.1)) {
stop("Please provide ident.1")
} else if ((length(x = ident.1) == 1 && ident.1[1] == 'clustertree') || is(object = ident.1, class2 = 'phylo')) {
if (is.null(x = ident.2)) {
stop("Please pass a node to 'ident.2' to run FindMarkers on a tree")
}
tree <- if (is(object = ident.1, class2 = 'phylo')) {
ident.1
} else {
Tool(object = object, slot = 'BuildClusterTree')
}
if (is.null(x = tree)) {
stop("Please run 'BuildClusterTree' or pass an object of class 'phylo' as 'ident.1'")
}
ident.1 <- tree$tip.label[GetLeftDescendants(tree = tree, node = ident.2)]
ident.2 <- tree$tip.label[GetRightDescendants(tree = tree, node = ident.2)]
}
if (length(x = as.vector(x = ident.1)) > 1 &&
any(as.character(x = ident.1) %in% cellnames.use)) {
bad.cells <- cellnames.use[which(x = !as.character(x = ident.1) %in% cellnames.use)]
if (length(x = bad.cells) > 0) {
stop(paste0("The following cell names provided to ident.1 are not present in the object: ", paste(bad.cells, collapse = ", ")))
}
} else {
ident.1 <- WhichCells(object = object, idents = ident.1)
}
# if NULL for ident.2, use all other cells
if (length(x = as.vector(x = ident.2)) > 1 &&
any(as.character(x = ident.2) %in% cellnames.use)) {
bad.cells <- cellnames.use[which(!as.character(x = ident.2) %in% cellnames.use)]
if (length(x = bad.cells) > 0) {
stop(paste0("The following cell names provided to ident.2 are not present in the object: ", paste(bad.cells, collapse = ", ")))
}
} else {
if (is.null(x = ident.2)) {
ident.2 <- setdiff(x = cellnames.use, y = ident.1)
} else {
ident.2 <- WhichCells(object = object, idents = ident.2)
}
}
return(list(cells.1 = ident.1, cells.2 = ident.2))
}
可以看出增加了check normalization method这一模块,具体原因还不知道