225 lines
6.9 KiB
R
225 lines
6.9 KiB
R
#!/usr/bin/env Rscript
|
|||
|
|
|
||
|
|
args <- commandArgs(trailingOnly = TRUE)
|
||
|
|
|
||
|
|
get_arg <- function(name, default = "") {
|
||
|
|
hit <- which(args == name)
|
||
|
|
if (length(hit) == 0 || hit[1] == length(args)) {
|
||
|
|
return(default)
|
||
|
|
}
|
||
|
|
args[[hit[1] + 1]]
|
||
|
|
}
|
||
|
|
|
||
|
|
write_json <- function(path, values) {
|
||
|
|
escape <- function(x) {
|
||
|
|
x <- as.character(x)
|
||
|
|
x <- gsub("\\\\", "\\\\\\\\", x)
|
||
|
|
x <- gsub('"', '\\"', x)
|
||
|
|
x <- gsub("\n", "\\\\n", x)
|
||
|
|
x
|
||
|
|
}
|
||
|
|
scalar <- function(x) {
|
||
|
|
if (is.logical(x)) {
|
||
|
|
return(ifelse(isTRUE(x), "true", "false"))
|
||
|
|
}
|
||
|
|
if (is.numeric(x)) {
|
||
|
|
return(as.character(x))
|
||
|
|
}
|
||
|
|
paste0('"', escape(x), '"')
|
||
|
|
}
|
||
|
|
lines <- c("{")
|
||
|
|
keys <- names(values)
|
||
|
|
for (idx in seq_along(keys)) {
|
||
|
|
key <- keys[[idx]]
|
||
|
|
comma <- if (idx < length(keys)) "," else ""
|
||
|
|
lines <- c(lines, paste0(' "', key, '": ', scalar(values[[key]]), comma))
|
||
|
|
}
|
||
|
|
lines <- c(lines, "}")
|
||
|
|
writeLines(lines, path)
|
||
|
|
}
|
||
|
|
|
||
|
|
species_hint <- trimws(get_arg("--species", ""))
|
||
|
|
source <- tolower(trimws(get_arg("--source", "auto")))
|
||
|
|
out_file <- get_arg("--out", "")
|
||
|
|
report_file <- get_arg("--report", "")
|
||
|
|
cache_dir <- get_arg("--cache-dir", "")
|
||
|
|
|
||
|
|
if (!nzchar(out_file)) {
|
||
|
|
stop("--out is required")
|
||
|
|
}
|
||
|
|
if (!nzchar(report_file)) {
|
||
|
|
report_file <- paste0(out_file, ".report.json")
|
||
|
|
}
|
||
|
|
|
||
|
|
dir.create(dirname(out_file), recursive = TRUE, showWarnings = FALSE)
|
||
|
|
dir.create(dirname(report_file), recursive = TRUE, showWarnings = FALSE)
|
||
|
|
if (nzchar(cache_dir)) {
|
||
|
|
dir.create(cache_dir, recursive = TRUE, showWarnings = FALSE)
|
||
|
|
if (requireNamespace("AnnotationHub", quietly = TRUE) &&
|
||
|
|
exists("setAnnotationHubOption", asNamespace("AnnotationHub"))) {
|
||
|
|
AnnotationHub::setAnnotationHubOption("CACHE", cache_dir)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
aliases <- c(
|
||
|
|
"at" = "Arabidopsis thaliana",
|
||
|
|
"ath" = "Arabidopsis thaliana",
|
||
|
|
"arabidopsis" = "Arabidopsis thaliana",
|
||
|
|
"arabidopsis_thaliana" = "Arabidopsis thaliana",
|
||
|
|
"os" = "Oryza sativa",
|
||
|
|
"osa" = "Oryza sativa",
|
||
|
|
"rice" = "Oryza sativa",
|
||
|
|
"oryza_sativa" = "Oryza sativa",
|
||
|
|
"sl" = "Solanum lycopersicum",
|
||
|
|
"sly" = "Solanum lycopersicum",
|
||
|
|
"tomato" = "Solanum lycopersicum",
|
||
|
|
"solanum_lycopersicum" = "Solanum lycopersicum",
|
||
|
|
"hsa" = "Homo sapiens",
|
||
|
|
"human" = "Homo sapiens",
|
||
|
|
"mmu" = "Mus musculus",
|
||
|
|
"mouse" = "Mus musculus"
|
||
|
|
)
|
||
|
|
|
||
|
|
normalize_species <- function(x) {
|
||
|
|
key <- tolower(gsub(" ", "_", trimws(x)))
|
||
|
|
if (key %in% names(aliases)) {
|
||
|
|
aliases[[key]]
|
||
|
|
} else {
|
||
|
|
trimws(x)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
species <- normalize_species(species_hint)
|
||
|
|
result <- data.frame(gene_id = character(), go_id = character(), stringsAsFactors = FALSE)
|
||
|
|
method <- ""
|
||
|
|
resource <- ""
|
||
|
|
error_message <- ""
|
||
|
|
|
||
|
|
try_biomart <- function(species) {
|
||
|
|
if (!requireNamespace("biomaRt", quietly = TRUE)) {
|
||
|
|
stop("biomaRt is not installed in this R environment")
|
||
|
|
}
|
||
|
|
datasets <- NULL
|
||
|
|
mart <- NULL
|
||
|
|
mart <- tryCatch(
|
||
|
|
biomaRt::useEnsemblGenomes(biomart = "plants_mart"),
|
||
|
|
error = function(e) biomaRt::useEnsembl(biomart = "genes")
|
||
|
|
)
|
||
|
|
datasets <- biomaRt::listDatasets(mart)
|
||
|
|
species_lower <- tolower(species)
|
||
|
|
ds <- datasets[grepl(gsub(" ", ".*", species_lower), tolower(datasets$description)), , drop = FALSE]
|
||
|
|
if (nrow(ds) == 0) {
|
||
|
|
compact <- gsub("[^a-z]", "", species_lower)
|
||
|
|
ds <- datasets[grepl(compact, gsub("[^a-z]", "", tolower(datasets$description))), , drop = FALSE]
|
||
|
|
}
|
||
|
|
if (nrow(ds) == 0) {
|
||
|
|
stop(paste("No biomaRt dataset matched species", species))
|
||
|
|
}
|
||
|
|
mart <- biomaRt::useDataset(ds$dataset[[1]], mart = mart)
|
||
|
|
attrs <- biomaRt::listAttributes(mart)$name
|
||
|
|
gene_candidates <- attrs[grepl("gene.*id", attrs)]
|
||
|
|
go_candidates <- attrs[grepl("^go", attrs)]
|
||
|
|
gene_attr <- if ("ensembl_gene_id" %in% attrs) "ensembl_gene_id" else if (length(gene_candidates)) gene_candidates[[1]] else ""
|
||
|
|
go_attr <- if ("go_id" %in% attrs) "go_id" else if (length(go_candidates)) go_candidates[[1]] else ""
|
||
|
|
if (!nzchar(gene_attr) || !nzchar(go_attr)) {
|
||
|
|
stop("Could not identify gene/GO attributes in selected biomaRt dataset")
|
||
|
|
}
|
||
|
|
tab <- biomaRt::getBM(attributes = c(gene_attr, go_attr), mart = mart)
|
||
|
|
names(tab) <- c("gene_id", "go_id")
|
||
|
|
tab <- tab[nzchar(tab$gene_id) & grepl("^GO:[0-9]{7}$", tab$go_id), , drop = FALSE]
|
||
|
|
list(data = unique(tab), resource = ds$dataset[[1]])
|
||
|
|
}
|
||
|
|
|
||
|
|
try_annotationhub <- function(species) {
|
||
|
|
if (!requireNamespace("AnnotationHub", quietly = TRUE)) {
|
||
|
|
stop("AnnotationHub is not installed in this R environment")
|
||
|
|
}
|
||
|
|
if (!requireNamespace("AnnotationDbi", quietly = TRUE)) {
|
||
|
|
stop("AnnotationDbi is not installed in this R environment")
|
||
|
|
}
|
||
|
|
ah <- AnnotationHub::AnnotationHub()
|
||
|
|
q <- AnnotationHub::query(ah, c(species, "OrgDb"))
|
||
|
|
if (length(q) == 0) {
|
||
|
|
q <- AnnotationHub::query(ah, c(species, "OrgDb", "plants"))
|
||
|
|
}
|
||
|
|
if (length(q) == 0) {
|
||
|
|
stop(paste("No AnnotationHub OrgDb resource matched species", species))
|
||
|
|
}
|
||
|
|
db <- q[[1]]
|
||
|
|
keytypes <- AnnotationDbi::keytypes(db)
|
||
|
|
preferred <- c("TAIR", "ENSEMBL", "GID", "ENTREZID", "SYMBOL")
|
||
|
|
key_candidates <- preferred[preferred %in% keytypes]
|
||
|
|
if (!length(key_candidates)) {
|
||
|
|
stop("Selected OrgDb resource has no supported gene key type")
|
||
|
|
}
|
||
|
|
keytype <- key_candidates[[1]]
|
||
|
|
keys <- AnnotationDbi::keys(db, keytype = keytype)
|
||
|
|
cols <- intersect(c("GO", "ONTOLOGY"), AnnotationDbi::columns(db))
|
||
|
|
if (!"GO" %in% cols) {
|
||
|
|
stop("Selected OrgDb resource has no GO column")
|
||
|
|
}
|
||
|
|
tab <- AnnotationDbi::select(db, keys = keys, keytype = keytype, columns = cols)
|
||
|
|
tab <- tab[!is.na(tab$GO) & grepl("^GO:[0-9]{7}$", tab$GO), , drop = FALSE]
|
||
|
|
tab <- data.frame(gene_id = as.character(tab[[keytype]]), go_id = as.character(tab$GO), stringsAsFactors = FALSE)
|
||
|
|
list(data = unique(tab), resource = paste0("AnnotationHub:", names(q)[[1]], ":", keytype))
|
||
|
|
}
|
||
|
|
|
||
|
|
attempts <- character()
|
||
|
|
if (source %in% c("auto", "biomart")) {
|
||
|
|
attempts <- c(attempts, "biomart")
|
||
|
|
}
|
||
|
|
if (source %in% c("auto", "annotationhub")) {
|
||
|
|
attempts <- c(attempts, "annotationhub")
|
||
|
|
}
|
||
|
|
|
||
|
|
for (candidate in attempts) {
|
||
|
|
fetched <- tryCatch(
|
||
|
|
{
|
||
|
|
if (candidate == "biomart") {
|
||
|
|
try_biomart(species)
|
||
|
|
} else {
|
||
|
|
try_annotationhub(species)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
error = function(e) {
|
||
|
|
error_message <<- paste(candidate, conditionMessage(e), sep = ": ")
|
||
|
|
NULL
|
||
|
|
}
|
||
|
|
)
|
||
|
|
if (!is.null(fetched) && nrow(fetched$data) > 0) {
|
||
|
|
result <- fetched$data
|
||
|
|
method <- candidate
|
||
|
|
resource <- fetched$resource
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nrow(result) > 0) {
|
||
|
|
result <- unique(result[order(result$gene_id, result$go_id), , drop = FALSE])
|
||
|
|
write.table(result, out_file, sep = "\t", quote = FALSE, row.names = FALSE, col.names = FALSE)
|
||
|
|
write_json(report_file, list(
|
||
|
|
status = "success",
|
||
|
|
species = species,
|
||
|
|
source = method,
|
||
|
|
resource = resource,
|
||
|
|
rows = nrow(result),
|
||
|
|
genes = length(unique(result$gene_id)),
|
||
|
|
go_terms = length(unique(result$go_id)),
|
||
|
|
error = ""
|
||
|
|
))
|
||
|
|
quit(status = 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
writeLines(character(), out_file)
|
||
|
|
write_json(report_file, list(
|
||
|
|
status = "failed",
|
||
|
|
species = species,
|
||
|
|
source = source,
|
||
|
|
resource = resource,
|
||
|
|
rows = 0,
|
||
|
|
genes = 0,
|
||
|
|
go_terms = 0,
|
||
|
|
error = error_message
|
||
|
|
))
|
||
|
|
quit(status = 2)
|