抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

SylensHub

吃饭, 睡觉, 打游戏!

从事生物信息分析,研究方向越前沿,就要面临越多来自信息侧的问题。即使是文章发的非常好,原作者共享了代码,甚至写了现成软件工具,也不代表我们能轻松顺利的用这些现成的东西来复现或进行研究,混乱的环境设置只是一方面,更多时候,由于软件作者并不是专业的软件工程师,工具功能大致能用已经谢天谢地了,不能奢望这些软件没有一点毛病,更不能奢望有性能可言(除非开发时性能被来就是开发点)。即使这工具来自于有实力的大实验室,很多时候也不能幸免,比如… Azimuth。

Azimuth 介绍

Azimuth是由Satija实验室开发的单细胞数据注释工具,旨在简化 Seurat 中的 Label Transfer 流程,快速的对待分型细胞进行 Label Transfer。

问题描述

在当前最新的 0.5.0 版本中, 在Jupyter Notebook 中运行 AzimuthReference 会提示 Error in ValidateAzimuthReference(object = object): Reference must contain an AzimuthData object in the tools slot.

谷歌一搜,发现该问题在2024年4月就已经被提出(issue #219)了,提出问题的用户已经给了解决方案,但这个Issue至今开放,且问题仍未被解决(上周又有用户反馈遇到同样的问题)。

解决思路

如前所述,Issue发起人zacharyrs已经提到了问题所在,在b1b6895这个提交中,代码作者使用sys.calls()来判断当前调用的函数名称,并根据这个名称来判断后续处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
tool.name <- as.character(x = sys.calls()) # <-- 这里的sys.calls()会返回一个list,如果不是直接调用AzimuthReference,就会删除对象中的一些信息
tool.name <- lapply(
X = strsplit(x = tool.name, split = "(", fixed = TRUE),
FUN = "[",
1
)[[1]]
if (tool.name != "AzimuthReference") {
slot(object, name = "tools")["AzimuthReference"] <- slot(object, name = "tools")[tool.name]
slot(object, name = "tools")[tool.name] <- NULL
}
object <- DietSeurat(object = object,
counts = FALSE,
assays = c("refAssay", assays),
dimreducs = c("refDR", "refUMAP"))

然而实际上我们很多时候需要将AzimuthReference包到函数里使用,这时候,sys.calls() 返回的list中,第一项内容是最外侧的函数名称,这样就会导致Azimuth运行需要的数据被删除,下面的检查就会报错了。

对于我的情况来说,我也是第一次知道,notebook中所有的代码都是包在IRKernel的函数下的(感谢AI给了我排查方法),所以即使我笔记中直接运行AzimuthReference,也会发生将AzimuthReference放在函数中运行时才触发的错误。

处理也很简单,修改这里的判断,sys.calls()返回list后,去最后一项,再做正则取函数名就行:

1
2
call_list <- sys.calls()
tool.name <- as.character(x = call_list[[length(call_list)]])

在我们的实际代码中,则可以加载Azimuth后,自行用修改后的函数去覆盖原来的AzimuthReference,这样后续代码就能运行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
library(Azimuth)
AzimuthReference <- function (object, refUMAP = "umap", refDR = "spca", refAssay = "SCT",
dims = 1:50, k.param = 31, plotref = "umap", plot.metadata = NULL,
ori.index = NULL, colormap = NULL, assays = NULL, metadata = NULL,
reference.version = "0.0.0", verbose = FALSE)
{
if (!refUMAP %in% Reductions(object = object)) {
stop("refUMAP (", refUMAP, ") not found in Seurat object provided")
}
if (is.null(x = Misc(object = object[[refUMAP]], slot = "model"))) {
stop("refUMAP (", refUMAP, ") does not have the umap model info stored. ",
"Please rerun RunUMAP with return.model = TRUE.")
}
if (!refDR %in% Reductions(object = object)) {
stop("refDR (", refDR, ") not found in Seurat object provided")
}
if (is.null(x = metadata)) {
stop("Please specify at least one metadata field (for transfer and plotting).")
}
for (i in metadata) {
if (!i %in% colnames(x = object[[]])) {
warning(i, " not found in Seurat object metadata")
next
}
if (!is.factor(x = object[[i, drop = TRUE]])) {
warning(i, " is not a factor. Converting to factor with alphabetical ",
"levels.", call. = FALSE)
object[[i, drop = TRUE]] <- factor(x = object[[i,
drop = TRUE]], levels = sort(x = unique(object[[i,
drop = TRUE]])))
}
}
if (!refAssay %in% Assays(object = object)) {
stop("Seurat object provided must have the SCT Assay stored.")
}
if (!inherits(x = object[[refAssay]], what = "SCTAssay")) {
stop("refAssay (", refAssay, ") is not an SCTAssay.")
}
if (length(x = levels(x = object[[refAssay]])) != 1) {
stop("refAssay (", refAssay, ") should contain a single SCT model.")
}
suppressWarnings(expr = object[["refUMAP"]] <- object[[refUMAP]])
suppressWarnings(expr = object[["refDR"]] <- object[[refDR]])
object <- FindNeighbors(object = object, reduction = "refDR",
dims = dims, graph.name = "refdr.annoy.neighbors", k.param = k.param,
nn.method = "annoy", annoy.metric = "cosine", cache.index = TRUE,
return.neighbor = TRUE, l2.norm = FALSE, verbose = verbose)
if (verbose) {
message("Computing pseudobulk averages")
}
features <- rownames(x = Loadings(object = object[["refDR"]]))
plot.metadata <- plot.metadata %||% object[[metadata]]
if (inherits(x = plotref, what = "DimReduc")) {
plot.metadata <- plot.metadata[Cells(x = plotref), ]
}
ad <- CreateAzimuthData(object = object, plotref = plotref,
plot.metadata = plot.metadata, colormap = colormap, reference.version = reference.version)
ori.index <- ori.index %||% match(Cells(x = object), Cells(x = object[["refUMAP"]]))
object$ori.index <- ori.index
DefaultAssay(object = object) <- refAssay
object[[refAssay]] <- subset(x = object[[refAssay]], features = features)
DefaultAssay(object = object[["refDR"]]) <- refAssay
object <- DietSeurat(object = object, counts = FALSE, assays = c(refAssay,
assays), dimreducs = c("refDR", "refUMAP"))
metadata <- c(metadata, "ori.index")
for (i in colnames(x = object[[]])) {
if (!i %in% metadata) {
object[[i]] <- NULL
}
}
sct.model <- slot(object = object[[refAssay]], name = "SCTModel.list")[[1]]
object[["refAssay"]] <- as(object = suppressWarnings(Seurat:::CreateDummyAssay(assay = object[[refAssay]])),
Class = "SCTAssay")
slot(object = object[["refAssay"]], name = "SCTModel.list") <- list(refmodel = sct.model)
DefaultAssay(object = object) <- "refAssay"
DefaultAssay(object = object[["refDR"]]) <- "refAssay"
Tool(object = object) <- ad
call_list <- sys.calls() # use the last element of sys.call() to get the right function name
tool.name <- as.character(x = call_list[[length(call_list)]]) # use the last element of sys.call() to get the right function name
tool.name <- lapply(X = strsplit(x = tool.name, split = "(",
fixed = TRUE), FUN = "[", 1)[[1]]
if (tool.name != "AzimuthReference") {
slot(object, name = "tools")["AzimuthReference"] <- slot(object,
name = "tools")[tool.name]
slot(object, name = "tools")[tool.name] <- NULL
}
object <- DietSeurat(object = object, counts = FALSE, assays = c("refAssay",
assays), dimreducs = c("refDR", "refUMAP"))
ValidateAzimuthReference(object = object)
return(object)
}

Azimuth感觉被放弃了

虽然出自Satija实验室,但总感觉这个项目基本已经被放弃了,github上有近百个开放Issue,去年开始提的PR到现在还有5个未合并也未拒绝。最近他们又弄了个基于Python和深度学习的通用细胞类型Label Transfer项目,感觉是研究进入下一步,老的项目就不准备维护了。

况且要进行Label Transfer,也可以自己跟着教程一步步做,不是非要用Azimuth,也许再过段时间,这个项目就会被Archieve了吧…

评论

留下友善的评论吧~