yulab.utils/0000755000176200001440000000000015140042152012517 5ustar liggesusersyulab.utils/tests/0000755000176200001440000000000015115331244013666 5ustar liggesusersyulab.utils/tests/testthat/0000755000176200001440000000000015140042152015521 5ustar liggesusersyulab.utils/tests/testthat/test-utils.R0000644000176200001440000000106215115331244017765 0ustar liggesuserstest_that("%||% returns fallback only when NULL", { expect_equal(NULL %||% 1, 1) expect_equal(0 %||% 1, 0) expect_equal("" %||% "x", "") }) test_that("parse_ratio handles spaces and invalid inputs", { expect_equal(parse_ratio("1/5"), 0.2) expect_equal(parse_ratio(" 2 / 4 "), 0.5) expect_true(is.na(parse_ratio("a/b"))) expect_true(is.na(parse_ratio("1/0"))) }) test_that("quiet suppresses output and returns value invisibly", { f <- function() { cat("hello\n"); 1 } res <- quiet(f()) expect_equal(res, 1) expect_invisible(quiet(f())) }) yulab.utils/tests/testthat/test-error-utils.R0000644000176200001440000000124015116500304021106 0ustar liggesuserstest_that("check_file validates existence and permissions", { tf <- tempfile() writeLines("x", tf) expect_silent(check_file(tf, operation = "read", must_exist = TRUE)) unlink(tf) expect_error(check_file(tf, operation = "read", must_exist = TRUE)) }) test_that("check_directory can create missing dir", { td <- tempfile() expect_message(check_directory(td, create_if_missing = TRUE), "Created directory") expect_true(dir.exists(td)) unlink(td, recursive = TRUE) }) test_that("check_range validates numeric bounds", { expect_silent(check_range(5, min = 1, max = 10)) expect_error(check_range(0, min = 1)) expect_error(check_range(11, max = 10)) }) yulab.utils/tests/testthat/test-cache.R0000644000176200001440000000164715137763371017717 0ustar liggesuserstest_that("update_cache_item with ttl expires entries", { item <- paste0("ttltest_", as.integer(runif(1) * 1e6)) update_cache_item(item, list(a = 1), ttl = 0.2) val1 <- get_cache_element(item, "a") expect_equal(val1, 1) Sys.sleep(0.3) val2 <- get_cache_element(item, "a") expect_null(val2) }) test_that("with_cache computes and caches results", { item <- paste0("withcache_", as.integer(runif(1) * 1e6)) calls <- 0 f <- function() { calls <<- calls + 1; 42 } v1 <- with_cache(item, "k", f, ttl = 1) v2 <- with_cache(item, "k", f, ttl = 1) expect_equal(v1, 42) expect_equal(v2, 42) expect_equal(calls, 1) }) test_that("cache_save/cache_load round-trip", { item <- paste0("savecache_", as.integer(runif(1) * 1e6)) update_cache_item(item, list(x = 123)) tf <- tempfile(fileext = ".rds") cache_save(tf) rm_cache() cache_load(tf) expect_equal(get_cache_element(item, "x"), 123) unlink(tf) }) yulab.utils/tests/testthat.R0000644000176200001440000000010215115331235015642 0ustar liggesuserslibrary(testthat) library(yulab.utils) test_check("yulab.utils") yulab.utils/MD50000644000176200001440000000760115140042152013033 0ustar liggesusers07046c9877c8b865caa52c261dabe6a0 *DESCRIPTION 3a9095bb4dc09e4123838743c3f3a9a8 *NAMESPACE f1e49eeb86ede053877de3135ec908fb *NEWS.md dea503b7e07e699c2bd4ba8d5d00bc1c *R/bib-ggtree.R d3c9d9b61886ad96130da98b77a825ca *R/bib-knownledge.R 8c817a90acb8deb76024a36d5662c824 *R/biorxiv.R abe3e19657d44f508ad3b08721db0a11 *R/cache.R 95effca842167b8d4ab1d11056e3e84e *R/combinations.R 664948f3ab8aa48e35c8dd268bcdf822 *R/concat.r 1e96bf6a7a239f70663880d5ffea3da8 *R/download.R f41fec88331c3661c32540a19eda1da0 *R/error-utils.r 3f9762b961d4098f7e9eb9980d64cdbb *R/file.R a96cd34294a7a855144c7cd3a3770df8 *R/install_zip.R 8dc56c2701ad2466e927bef5efbd3f51 *R/list.R 2f7f9ed479ca64940466e7607fd2aa7b *R/load-orgdb.r 8252645d719beddb50ac388ea53f218c *R/matrix-utils.R 89e184cc08a87f954498e149088b76bf *R/os.R 8229d906e01f2baa296ec3a8a65fc00a *R/parse_ratio.R fc61bc16540bda29a9045368c58d2a86 *R/pkg-utils.R 1ac93d94e3f802de0cd293a9751cd53f *R/quiet.r f49ce53dbd4709f3ec853cde9db83b3f *R/regexpr.R ac1d7b818e77f68279c01ca8ed44cd1f *R/scale.R 876bd4024b7491400e97c757b8d3398d *R/scihub-dl.R e0f7e2658ee96087159161d6126bf3be *R/str-utils.R a33656388df140e42f096042e4d94c4f *R/sudo-install.R 4915960c0e996ed084d9c9b62195b314 *R/utilities.R fbe4297a8e92938ee8fe8acfe8ddf011 *R/yulab-msg.R da7bac5323d313dfbcdb38f8fbf613f0 *R/yulab-utils-package.R 81128a8e2c6dac0484310aefb614e6c3 *R/zzz.R e102b8ef2ffb9aafef52223a22e88753 *inst/prototype/GEO.r fe6013508f10ad5584815759267861f0 *inst/prototype/sra.r d611cc86140e279caf3e3acb788b6153 *man/c2.Rd cca3079b94e3205eab328338d83472a6 *man/check_directory.Rd 41e2363d0b9dbd7c989135de2d257fa2 *man/check_file.Rd dba97e8704ab033d8ca1a19ef010541e *man/check_input.Rd 0e2b376e4244e8d281bb5bdb089c6c05 *man/check_packages.Rd 7e1a1747edf58ad6661d6b614fadba7e *man/check_range.Rd 740f5276df44ad1e6766f7a37fe1d21a *man/combinations.Rd 53e2e7991daa9f006d949f5a282c5fc8 *man/cran-bioc-pkg.Rd 30244d124db9d30e3aee0968404ad1d3 *man/download_yulab_file.Rd 880045bd07af6869c5d49e6498690bc4 *man/exec.Rd 0e03dbc2bf8b5157dbea8e8400f2f27f *man/get_dependencies.Rd d6c94e132951aa5c506492b32ac47881 *man/get_fun_from_pkg.Rd d73ad3a3ad0f05cd91f6f1b20a9db534 *man/github-pkg.Rd 2582f44cfd945f1061ffd043eeb8db02 *man/has_internet.Rd c8e2293b15f6c8ee6229692984596492 *man/install_zip.Rd 706162775b754111bb910a6ca34bb49c *man/install_zip_gh.Rd 42f5ad71d13e5b9bb13a9af0f591e868 *man/is.installed.Rd df477ec6d0b0b783d7456b75fb647e60 *man/load_OrgDb.Rd e0e8a92b36a60d28d4443bd183196071 *man/ls2df.Rd 6ad39ca2459889f1cdd3f10b50cca2b1 *man/mat2df.Rd 035dbcab8d8db17527a76278426722ca *man/mat2list.Rd 8f7d212a3555294fdf51d4fd17a49751 *man/mypkg.Rd f04b08482d12259ff32747b9cd2ad12b *man/o.Rd fe2d50b228cda6d6e3d273303a7aa8b8 *man/packageTitle.Rd 0deb9a929023b7af75f82f054e58ab52 *man/parse_ratio.Rd 8b5b64fc35189d6bc02370aab93b25c1 *man/pload.Rd 42b3f1127c63dc0d079355e5d890eaeb *man/quiet.Rd aa47acf576dd6ca373c05f848849fc5e *man/rbindlist.Rd 715e6475373b8eb14fac52156029c74f *man/read.cb.Rd cc2839493bf6acf44d44883bfb9edea3 *man/regexpr-style.Rd e4439fe352c1817015d3bc28bd4f5abf *man/scale_range.Rd 7ca4626445edad5c55b084c9a360cff2 *man/scihub-dl.Rd a6e88efcf58d3da72fa22a3c1599ab54 *man/show_in_excel.Rd 53970495fb075dbf109342425fc476f0 *man/str-detect.Rd a0cf2e8b4cd05f4f3e123e90d30d9b5d *man/str-extract.Rd d07a2ecf308318f9102443d48b28552a *man/str-starts-ends.Rd 7dba62bb489bd86d35cea158dda28fb8 *man/str_wrap.Rd 368a8cb1079edd073caf5c30b99c6aaf *man/user_dir.Rd c39f100ffb3e5a4a2ad75cb20c2f64ad *man/yread.Rd f849c9b93ab305daea0fbb2084a830df *man/yulab-cache.Rd 29845f48b7194470367c623b704b9cf9 *man/yulab-message.Rd eedc7b6680597a4df3d869fe84f9ca5c *man/yulab.utils-package.Rd d4fd3e73765c9b7f9e2de1137d9a6dd1 *man/yulab_msg.Rd a4cc960ea1ca60075970eb7923df396c *tests/testthat.R 9acf2bc9f231a93b151790bde74911e8 *tests/testthat/test-cache.R 6b9af5d566b8bf3d16330d4f4b4d7f5f *tests/testthat/test-error-utils.R 772618f20ab0addf9310247e5a7dea35 *tests/testthat/test-utils.R yulab.utils/R/0000755000176200001440000000000015114322400012716 5ustar liggesusersyulab.utils/R/cache.R0000644000176200001440000001277215117723302014126 0ustar liggesusers# caching mechanism # - get_cache_item() auto-initializes cache items if they don't exist # - get_cache_element() retrieves specific elements from cache items # - update_cache_item() stores data in cache items # - rm_cache_item() removes cache items .yulabCache <- new.env(parent = emptyenv()) #' @rdname yulab-cache #' @export #' @family cache-utils initial_cache <- function() { rm(list = ls(envir = .yulabCache), envir = .yulabCache) } #' @rdname yulab-cache #' @export #' @family cache-utils get_cache <- function() { .yulabCache } #' @rdname yulab-cache #' @export #' @family cache-utils rm_cache <- function() { rm(list = ls(envir = .yulabCache), envir = .yulabCache) } #' @rdname yulab-cache #' @export #' @family cache-utils initial_cache_item <- function(item) { env <- get_cache() assign(item, list(), envir = env) } #' @rdname yulab-cache #' @export get_cache_item <- function(item) { env <- get_cache() if (!exists(item, envir = env)) { initial_cache_item(item) } get(item, envir = env, inherits = FALSE) } #' @rdname yulab-cache #' @export rm_cache_item <- function(item) { env <- get_cache() if (exists(item, envir = env)) { rm(list = item, envir = env) } } #' Cache intermediate data #' #' Utilities to cache intermediate data: initialize items, update items, #' remove items, and retrieve elements. #' #' @rdname yulab-cache #' @param item Cache item name #' @param elements Elements to cache #' @param default Default value if cache element is missing #' @param prune_expired Logical, whether to prune expired items #' @param ttl Time-to-live in seconds #' @return Cache environment, item, or selected elements #' @importFrom utils modifyList #' @importFrom stats setNames #' @export #' @examples #' \dontrun{ #' slow_fib <- function(x) { #' if (x < 2) return(1) #' slow_fib(x-2) + slow_fib(x-1) #' } #' #' fast_fib <- function(x) { #' if (x < 2) return(1) #' res <- get_cache_element('fibonacci', as.character(x)) #' if (!is.null(res)) { #' return(res) #' } #' res <- fast_fib(x-2) + fast_fib(x-1) #' e <- list() #' e[[as.character(x)]] <- res #' update_cache_item('fibonacci', e) #' return(res) #' } #' #' system.time(slow_fib(30)) #' system.time(fast_fib(30)) #' #' } #' @family cache-utils update_cache_item <- function(item, elements, ttl = NULL) { msg <- "new elements should be stored as a named list" if (!inherits(elements, 'list')) { stop(msg) } if (is.null(names(elements))) { stop(msg) } if(any(names(elements) == "")) { stop(msg) } if (!is.null(ttl)) { expires <- Sys.time() + as.difftime(ttl, units = "secs") elements <- lapply(elements, function(v) list(value = v, expires = expires)) names(elements) <- names(elements) } env <- get_cache() res <- get_cache_item(item) res <- modifyList(res, elements) assign(item, res, envir = env) } #' @rdname yulab-cache #' @family cache-utils #' @export get_cache_element <- function(item, elements, default = NULL, prune_expired = TRUE) { x <- get_cache_item(item) fetch_one <- function(k) { val <- x[[k]] if (is.null(val)) return(default) if (is.list(val) && !is.null(val$expires)) { if (prune_expired && isTRUE(Sys.time() > val$expires)) { rm_cache_entry(item, k) return(default) } return(val$value) } val } n <- length(elements) if (n == 1) return(fetch_one(elements)) setNames(lapply(elements, fetch_one), elements) } rm_cache_entry <- function(item, key) { env <- get_cache() x <- get_cache_item(item) x[[key]] <- NULL assign(item, x, envir = env) } #' @rdname yulab-cache #' @export prune_cache_item <- function(item) { x <- get_cache_item(item) expired <- vapply(names(x), function(k) { v <- x[[k]] is.list(v) && !is.null(v$expires) && isTRUE(Sys.time() > v$expires) }, logical(1)) if (any(expired)) { x[names(x)[expired]] <- NULL env <- get_cache() assign(item, x, envir = env) } invisible(TRUE) } #' @rdname yulab-cache #' @export cache_list_items <- function() { ls(envir = get_cache()) } #' @rdname yulab-cache #' @export cache_size <- function() { env <- get_cache() items <- ls(envir = env) sizes <- vapply(items, function(k) utils::object.size(get(k, envir = env)), numeric(1)) sum(sizes) } #' @rdname yulab-cache #' @param path File path to save or load cache #' @export cache_save <- function(path) { env <- get_cache() obj <- as.list(env) saveRDS(obj, path) invisible(path) } #' @rdname yulab-cache #' @export cache_load <- function(path) { obj <- readRDS(path) env <- get_cache() for (k in names(obj)) assign(k, obj[[k]], envir = env) invisible(TRUE) } #' @rdname yulab-cache #' @param key Element key #' @param compute Function to compute value when missing #' @param ttl Time-to-live in seconds #' @export with_cache <- function(item, key, compute, ttl = NULL) { k <- as.character(key) val <- get_cache_element(item, k) if (!is.null(val)) return(val) res <- compute() e <- list() e[[k]] <- res update_cache_item(item, e, ttl = ttl) res } yulab.utils/R/pkg-utils.R0000644000176200001440000001414215117723102014771 0ustar liggesusers#' Load a package #' #' Uses `library()` to load `package`. If not installed, attempts installation #' via `rlang::check_installed()` (optionally using `BiocManager::install()`). #' @title pload #' @param package package name #' @param action Installation function; `"auto"` tries `BiocManager::install()` if available #' @return the selected package loaded to the R session #' @importFrom rlang as_name #' @importFrom rlang enquo #' @importFrom rlang check_installed #' @importFrom cli cli_h2 #' @importFrom utils getFromNamespace #' @export #' @author Guangchuang Yu #' @family pkg-utils pload <- function(package, action = "auto") { pkg <- as_name(enquo(package)) if (action == "auto") { if (is.installed("BiocManager")) { install <- getFromNamespace("install", "BiocManager") action <- function(package, ask=FALSE, update=FALSE, ...) { install(package, ask=ask, update = update, ...) } } else { action <- NULL } } check_installed(pkg, action = action) pkg <- sub("\\w+/", "", pkg) # for github pkg: repo/pkg cli::cli_h2(sprintf("loading the package: %s", pkg)) library(pkg, character.only = TRUE) } #' Get reverse dependencies #' #' #' @title get_dependencies #' @param pkg package name #' @param repo 'CRAN' and/or 'BioC' #' @return reverse dependencies ## @importFrom BiocInstaller biocinstallRepos #' @importFrom tools package_dependencies #' @export #' @author Guangchuang Yu #' @family pkg-utils get_dependencies <- function(pkg, repo=c("CRAN", "BioC")) { rp <- get_repo(repo) db <- utils::available.packages(repo=rp) tools::package_dependencies(pkg, db=db, reverse=TRUE) } get_repo <- function(repo = c("CRAN", "BioC")) { rp <- c() if ('CRAN' %in% repo) { cran <- getOption("repos")["CRAN"] if (is.null(cran)) { cran <- "http://cloud.r-project.org/" } rp <- c(rp, cran) } if ('BioC' %in% repo) { bioc <- getOption("BioC_mirror") if (is.null(bioc)) { bioc <- "https://mirrors.tuna.tsinghua.edu.cn/bioconductor/" } rp <- c(rp, bioc) } ## options(repos = biocinstallRepos()) sub("/$", "", rp) } #' Extract package title #' #' #' @title packageTitle #' @param pkg package name #' @param repo 'CRAN' and/or 'BioC' #' @return reverse dependencies #' @importFrom utils packageDescription #' @export #' @author Guangchuang Yu #' @family pkg-utils packageTitle <- function(pkg, repo='CRAN') { title <- tryCatch(packageDescription(pkg)$Title, error=function(e) NULL) if (is.null(title)) { repo_url <- get_repo(repo) if (repo == "CRAN") { url <- sprintf("%s/package=%s", repo_url, pkg) } else { bioc_type <- c("bioc", "workflows", "data/annotation", "data/experiment") url <- sprintf("%s/packages/release/%s/html/%s.html", repo_url, bioc_type, pkg) } for (u in url) { x <- tryCatch({ if (is.installed("httr2")) { req <- httr2::request(u) |> httr2::req_timeout(5) resp <- httr2::req_perform(req) httr2::resp_body_string(resp) } else { yread(u) } }, error = function(e) NULL) if (!is.null(x)) { break() } } if (is.null(x)) { return(NA) } if (length(grep(" tt <- sub(".*\\s*(.*?)\\s*.*", "\\1", paste(x, collapse = " ")) title <- tt } else { i <- grep('^\\s*

', x) if (grepl("

$", x[i])) { xx <- x[i] } else { j <- grep('$', x) xx <- paste(x[i:j], collapse=" ") } title <- gsub('$', '', gsub('\\s*

', '', xx)) } } sub("^\\w+\\s*:\\s*", "", gsub("\n", " ", title)) } #' Check whether packages are installed #' @title is.installed #' @param packages package names #' @return logical vector #' @export #' @examples #' is.installed(c("dplyr", "ggplot2")) #' @author Guangchuang Yu #' @family pkg-utils is.installed <- function(packages) { vapply(packages, function(package) { system.file(package=package) != "" }, logical(1)) } #' load function from package #' #' #' @title get_fun_from_pkg #' @param pkg package #' @param fun function #' @return function #' @export #' @examples #' get_fun_from_pkg('utils', 'zip') #' @author Guangchuang Yu #' @family pkg-utils get_fun_from_pkg <- function(pkg, fun) { ## v1 ## ## requireNamespace(pkg) ## eval(parse(text=paste0(pkg, "::", fun))) ## v2 ## ## require(pkg, character.only = TRUE) ## eval(parse(text = fun)) # check_pkg(pkg) utils::getFromNamespace(fun, pkg) } #' Markdown link to CRAN/Bioconductor #' #' #' @rdname cran-bioc-pkg #' @param pkg package name #' @return md text string #' @export #' @author Guangchuang Yu #' @family pkg-utils CRANpkg <- function(pkg) { cran <- "https://CRAN.R-project.org/package" fmt <- "[%s](%s=%s)" sprintf(fmt, pkgfmt(pkg), cran, pkg) } #' @rdname cran-bioc-pkg #' @export Biocpkg <- function(pkg) { sprintf("[%s](http://bioconductor.org/packages/%s)", pkgfmt(pkg), pkg) } #' Markdown link to GitHub #' #' #' @rdname github-pkg #' @param user github user #' @param pkg package name #' @return md text string #' @export #' @author Guangchuang Yu #' @family pkg-utils Githubpkg <- function(user, pkg) { gh <- "https://github.com" fmt <- "[%s](%s/%s/%s)" sprintf(fmt, pkgfmt(pkg), gh, user, pkg) } #' Markdown link to a package #' #' #' @title mypkg #' @param pkg package name #' @param url package url #' @return md text string #' @export #' @author Guangchuang Yu #' @family pkg-utils mypkg <- function(pkg, url) { fmt <- "[%s](%s)" sprintf(fmt, pkgfmt(pkg), url) } pkgfmt <- function(pkg) { fmt <- getOption('yulab.utils_pkgfmt', default="%s") sprintf(fmt, pkg) } yulab.utils/R/download.R0000644000176200001440000000500615117722605014667 0ustar liggesusersmydownload <- function(url, destfile) { if (is.installed('httr2')) { req <- httr2::request(url) |> httr2::req_progress() req |> httr2::req_perform(path = destfile) } else { download.file(url = url, destfile = destfile) } } #' Process YuLab File Download #' #' @param destfile character. Local file path. #' @param urls character vector. Base URLs for download. Remote is is `urls/basename(destfile)` #' @param gzfile logical. Whether the remote file is gzipped. #' @param appname character. R package name. #' @author Guangchuang Yu #' @importFrom utils read.delim #' @export download_yulab_file <- function(destfile, urls, gzfile = FALSE, appname = NULL) { file0 <- basename(destfile) if (!is.null(appname)) { destfile <- file.path(user_dir(appname), file0) } need_dl <- TRUE dl_url <- urls[1] if (file.exists(destfile)) { need_dl <- FALSE for (url in urls) { md5_url <- sprintf("%s/md5.txt", url) md5 <- tryCatch(read.delim(md5_url, header = FALSE), error = function(e) NULL) if (!is.null(md5)) { md5_remote <- md5[md5[, 1] == file0, 2] if (length(md5_remote) > 0) { md5_local <- digest::digest(destfile, algo = 'md5', file = TRUE) if (md5_remote != md5_local) { message(sprintf("%s is outdated, download the latest version...", file0)) need_dl <- TRUE dl_url <- url } break } } } } else { message(sprintf("%s is not found, download it online...", file0)) } if (need_dl) { if (dl_url != urls[1]) { urls <- unique(c(dl_url, urls)) } for (url in urls) { if (gzfile) { furl <- sprintf('%s/%s.gz', url, file0) tpfile <- sprintf("%s.gz", destfile) } else { furl <- sprintf('%s/%s', url, file0) tpfile <- destfile } res <- tryCatch({ mydownload(furl, tpfile) if (gzfile) { check_pkg('R.utils') R.utils::gunzip(tpfile, overwrite = TRUE) } TRUE }, error = function(e) FALSE) if (res) break } } return(destfile) } yulab.utils/R/os.R0000644000176200001440000000406415115331213013471 0ustar liggesusers#' run system command #' @family os-utils #' #' #' @title exec #' @param command system command to run #' @return An `exec` instance that stores system command outputs #' @export #' @author Guangchuang Yu exec <- function(command) { res <- system(command, intern=TRUE) structure(res, class = "exec") } #' @method print exec #' @export print.exec <- function(x, ...) { cat(x, sep='\n') } which_cmd <- function(bin) { os <- which_os() which <- "which" if (os == "Windows") { which <- "where" } command <- sprintf("%s %s", which, bin) return(command) } has_bin <- function(bin) { command <- which_cmd(bin) exit_code <- system(command, ignore.stdout = TRUE, ignore.stderr = TRUE) return(exit_code == 0) } where <- function(bin) { if (!has_bin(bin)) return("") command <- which_cmd(bin) exec(command) } #' test for internect connection via reading lines from a URL #' @family os-utils #' #' #' @title has_internet #' @param site URL to test connection #' @return logical value #' @export #' @author Guangchuang Yu has_internet <- function(site = "https://www.baidu.com/") { ret <- tryCatch( suppressWarnings(readLines(site, n = 1)), error = function(e) NULL ) return(!is.null(ret)) } which_os <- function() { Sys.info()[["sysname"]] } #' get the user dir to save app caches, logs and data (a wrapper function of `rappdirs::user_cache_dir()`) #' @family os-utils #' #' @title user_dir #' @param appname App name #' @param appauthor App author #' @param ... additional parameters #' @return a directory (created if not exists) #' @importFrom rappdirs user_data_dir #' @export #' @author Guangchuang Yu user_dir <- function(appname = NULL, appauthor = NULL, ...) { dir <- rappdirs::user_data_dir( appname = appname, appauthor = appauthor, ...) if (!dir.exists(dir)) dir.create(dir, recursive = TRUE) return(dir) } yulab.utils/R/combinations.R0000644000176200001440000000050014471060615015535 0ustar liggesusers#' all possible combinations of n sets #' #' @title combinations #' @param n number of sets #' @return a list of all combinations #' @importFrom utils combn #' @export combinations <- function(n){ l <- lapply(seq_len(n), function(x){ m <- combn(n,x) mat2list(m) }) unlist(l, recursive = F) } yulab.utils/R/list.R0000644000176200001440000000141415116450416014027 0ustar liggesusers#' Row-bind a list #' #' #' @title rbindlist #' @param x List with similar elements that can be row-bound #' @return `data.frame` #' @author Guangchuang Yu #' @export rbindlist <- function(x) { do.call('rbind', x) } #' Convert a list of vectors to a data.frame #' #' #' @title Convert a list of vectors (e.g., gene IDs) to `data.frame` #' @param inputList List of vectors #' @return `data.frame` #' @export ls2df <- function(inputList) { # ldf <- lapply(1:length(inputList), function(i) { ldf <- lapply(seq_len(length(inputList)), function(i) { data.frame(category=rep(names(inputList[i]), length(inputList[[i]])), value=inputList[[i]]) }) do.call('rbind', ldf) } yulab.utils/R/bib-ggtree.R0000644000176200001440000002311114764742645015101 0ustar liggesusersbib_ggtree <- function(id) { bib <- c( jgg2024 = bib_shinyTempSignal_jgg2024, bib2022 = bib_ggmsa_bib2022, book = bib_ggtree_book2022, imeta2022 = bib_ggtree_imeta2022, cpb2020 = bib_ggtree_cpb2020, mbe2020 = bib_treeio_mbe2020, mbe2018 = bib_ggtree_mbe2018, mee2017 = bib_ggtree_mee2017 ) if (!id %in% names(bib)) return(NULL) bib[id] } ref_ggtree <- function() { refs <- c( shinyTempSignal = paste( "L Zhan, X Luo, W Xie, XA Zhu, Z Xie, J Lin, L Li, W Tang, R Wang, L Deng, Y Liao, B Liu, Y Cai, Q Wang, S Xu, G Yu.", "shinyTempSignal: an R shiny application for exploring temporal and other phylogenetic signals.", "Journal of Genetics and Genomics 2024, 51(7):762-768. doi: 10.1016/j.jgg.2024.02.004"), ggtreeBook = paste( "Guangchuang Yu. ", "Data Integration, Manipulation and Visualization of Phylogenetic Trees (1st edition).", "Chapman and Hall/CRC. 2022, doi:10.1201/9781003279242, ISBN: 9781032233574\n"), ggtreeCPB = paste0( "Guangchuang Yu. ", "Using ggtree to visualize data on tree-like structures. ", "Current Protocols in Bioinformatics. 2020, 69:e96. doi:10.1002/cpbi.96\n" ), ggtree_imeta = paste0( "Shuangbin Xu, Lin Li, Xiao Luo, Meijun Chen, Wenli Tang, Li Zhan, Zehan Dai, Tommy T. Lam, Yi Guan, Guangchuang Yu. ", "Ggtree: A serialized data object for visualization of a phylogenetic tree and annotation data. ", "iMeta 2022, 1(4):e56. doi:10.1002/imt2.56\n"), ggtreeMBE = paste0( "Guangchuang Yu, Tommy Tsan-Yuk Lam, Huachen Zhu, Yi Guan. ", "Two methods for mapping and visualizing associated data on phylogeny using ggtree. ", "Molecular Biology and Evolution. 2018, 35(12):3041-3043. doi:10.1093/molbev/msy194\n" ), ggtree = paste0( "Guangchuang Yu, David Smith, Huachen Zhu, Yi Guan, Tommy Tsan-Yuk Lam. ", "ggtree: an R package for visualization and annotation of phylogenetic trees with their covariates and other associated data. ", "Methods in Ecology and Evolution. 2017, 8(1):28-36. doi:10.1111/2041-210X.12628\n" ), treeio = paste0( "LG Wang, TTY Lam, S Xu, Z Dai, L Zhou, T Feng, P Guo, CW Dunn, BR Jones, T Bradley, H Zhu, Y Guan, Y Jiang, G Yu. ", "treeio: an R package for phylogenetic tree input and output with richly annotated and associated data. ", "Molecular Biology and Evolution. 2020, 37(2):599-603. doi: 10.1093/molbev/msz240\n" ), ggtreeExtra = paste0( "S Xu, Z Dai, P Guo, X Fu, S Liu, L Zhou, W Tang, T Feng, M Chen, L Zhan, T Wu, E Hu, Y Jiang, X Bo, G Yu. ", "ggtreeExtra: Compact visualization of richly annotated phylogenetic data. ", "Molecular Biology and Evolution. 2021, 38(9):4039-4042. doi: 10.1093/molbev/msab166\n" ), ggmsa = paste( "L Zhou, T Feng, S Xu, F Gao, TT Lam, Q Wang, T Wu, H Huang, L Zhan, L Li, Y Guan, Z Dai, G Yu.", "ggmsa: a visual exploration tool for multiple sequence alignment and associated data.", "Bioinformatics. 2022, 23(4):bbac222. 10.1093/bib/bbac222" ) ) return(refs) } refs <- ref_ggtree() bib_ggtree_book2022 <- bibentry( bibtype = "book", title = "Data Integration, Manipulation and Visualization of Phylogenetic Treess", author = person("Guangchuang", "Yu"), publisher = "Chapman and Hall/{CRC}", year = "2022", edition = "1st edition", doi = "10.1201/9781003279242", url = "https://www.amazon.com/Integration-Manipulation-Visualization-Phylogenetic-Computational-ebook/dp/B0B5NLZR1Z/", textVersion = refs['ggtreeBook'] ) bib_ggtree_imeta2022 <- bibentry( bibtype = "article", title = "Ggtree: A serialized data object for visualization of a phylogenetic tree and annotation data", author = personList( person("Shuangbin", "Xu"), person("Lin", "Li"), person("Xiao", "Luo"), person("Meijun", "Chen"), person("Wenli", "Tang"), person("Li", "Zhan"), person("Zehan", "Dai"), person("Tommy T. Lam"), person("Yi", "Guan"), person("Guangchuang", "Yu") ), year = "2022", journal = "iMeta", volume = "1", number = "4", pages = "e56", doi = "10.1002/imt2.56", url = "https://onlinelibrary.wiley.com/doi/full/10.1002/imt2.56", textVersion = refs['ggtree_imeta'] ) bib_ggtree_cpb2020 <- bibentry( bibtype = "article", title = "Using ggtree to Visualize Data on Tree-Like Structures", author = person("Guangchuang", "Yu"), year = "2020", journal = "Current Protocols in Bioinformatics", volume = "69", pages = "e96", number = "1", url = "https://currentprotocols.onlinelibrary.wiley.com/doi/abs/10.1002/cpbi.96", doi = "10.1002/cpbi.96", textVersion = refs['ggtreeCPB'] ) bib_ggtree_mbe2018 <- bibentry( bibtype = "article", title = "Two methods for mapping and visualizing associated data on phylogeny using ggtree.", author = personList( as.person("Guangchuang Yu"), as.person("Tommy Tsan-Yuk Lam"), as.person("Huachen Zhu"), as.person("Yi Guan") ), year = "2018", journal = "Molecular Biology and Evolution", volume = "35", issue = "2", number = "", pages = "3041-3043", doi = "10.1093/molbev/msy194", PMID = "", url = "https://academic.oup.com/mbe/article/35/12/3041/5142656", textVersion = refs['ggtreeMBE'] ) bib_ggtree_mee2017 <- bibentry( bibtype = "article", title = "ggtree: an R package for visualization and annotation of phylogenetic trees with their covariates and other associated data.", author = personList( as.person("Guangchuang Yu"), as.person("David Smith"), as.person("Huachen Zhu"), as.person("Yi Guan"), as.person("Tommy Tsan-Yuk Lam") ), year = "2017", journal = "Methods in Ecology and Evolution", volume = "8", issue = "1", number = "", pages = "28-36", doi = "10.1111/2041-210X.12628", PMID = "", url = "http://onlinelibrary.wiley.com/doi/10.1111/2041-210X.12628/abstract", textVersion = refs['ggtree'] ) #' @importFrom utils bibentry bib_shinyTempSignal_jgg2024 <- bibentry( bibtype = "article", title = "shinyTempSignal: an R shiny application for exploring temporal and other phylogenetic signals.", author = c( person("Li", "Zhan"), person("Xiao", "Luo"), person("Wenqin", "Xie"), person("Xuan-An", "Zhu"), person("Zijing", "Xie"), person("Jianfeng", "Lin"), person("Lin", "Li"), person("Wenli", "Tang"), person("Rui", "Wang"), person("Lin", "Deng"), person("Yufan", "Liao"), person("Bingdong", "Liu"), person("Yantong", "Cai"), person("Qianwen", "Wang"), person("Shuangbin", "Xu"), person("Guangchuang", "Yu") ), year = "2024", journal = "Journal of Genetics and Genomics", volume = "51", issue = "7", number = "", pages = "762-768", doi = "10.1016/j.jgg.2024.02.004", PMID = "", url = "https://www.sciencedirect.com/science/article/pii/S167385272400033X", textVersion = refs['shinyTempSignal'] ) bib_treeio_mbe2020 <- bibentry( bibtype = "article", title = "treeio: an R package for phylogenetic tree input and output with richly annotated and associated data.", author = c( person("Li-Gen", "Wang"), person("Tommy Tsan-Yuk", "Lam"), person("Shuangbin", "Xu"), person("Zehan", "Dai"), person("Lang", "Zhou"), person("Tingze", "Feng"), person("Pingfan", "Guo"), person("Casey W.", "Dunn"), person("Bradley R.", "Jones"), person("Tyler", "Bradley"), person("Huachen", "Zhu"), person("Yi", "Guan"), person("Yong", "Jiang"), person("Guangchuang", "Yu") ), year = "2020", journal = "Molecular Biology and Evolution", volume = "37", issue = "2", number = "", pages = "599-603", doi = "10.1093/molbev/msz240", PMID = "", url = "", textVersion = refs['treeio'] ) bib_ggmsa_bib2022 <- citEntry( entry = "article", title = "ggmsa: a visual exploration tool for multiple sequence alignment and associated data ", author = personList( as.person("Lang Zhou"), as.person("Tingze Feng"), as.person("Shuangbin Xu"), as.person("Fangluan Gao"), as.person("Tommy T Lam"), as.person("Qianwen Wang"), as.person("Tianzhi Wu"), as.person("Huina Huang"), as.person("Li Zhan"), as.person("Lin Li"), as.person("Yi Guan"), as.person("Zehan Dai"), as.person("Guangchuang Yu") ), journal = "BRIEFINGS IN BIOINFORMATICS", volume = "23", issue = "4", year = "2022", month = "06", ISSN = "1467-5463", doi = "10.1093/bib/bbac222", PMID = "35671504", url = "https://academic.oup.com/bib/article-abstract/23/4/bbac222/6603927", textVersion = refs['ggmsa'] ) yulab.utils/R/biorxiv.R0000644000176200001440000000264714404503310014536 0ustar liggesusers## biorxiv_get_publication <- function(url) { ## # url <- "https://www.biorxiv.org/search/visualization%20numresults%3A75%20sort%3Arelevance-rank" ## x <- readLines(url) ## pub <- x[grep("/content/10.1101", x)] ## pub_url <- gsub(".*(/content/[[:digit:]\\.v/]+).*", "\\1", pub) ## pub_url <- paste0("https://www.biorxiv.org", pub_url) ## pub_title <- gsub("<[^>]+>", "", pub) %>% ## sub("^\\s+", "", .) %>% ## sub("\\s+$", "", .) ## data.frame(url = pub_url, ## title = pub_title) ## } ## biorxiv_get_correspondance <- function(url) { ## # url <- "https://www.biorxiv.org/content/10.1101/701680v3" ## x <- readLines(url) ## i <- grep("citation_author\"", x) ## j <- grep("citation_author_email", x) ## idx <- vapply(j, function(ii) { ## jj <- ii - i ## i[which(jj == min(jj[jj >0]))] ## }, numeric(1)) ## author <- x[idx] %>% unique %>% ## sub(".*content=\"([^\"]+).*", "\\1", .) ## email <- x[j] %>% unique %>% ## sub(".*content=\"([^\"]+).*", "\\1", .) ## data.frame(author = author, email = email) %>% unique ## } ## url <- "https://www.biorxiv.org/search/visualization%20numresults%3A75%20sort%3Arelevance-rank" ## y <- biorxiv_get_publication(url) ## xx <- lapply(y$url, function(x) { ## cat("parsing", x, "\n") ## biorxiv_get_correspondance(x) ## }) yulab.utils/R/file.R0000644000176200001440000001077115117723231014000 0ustar liggesusers#' @rdname yread #' @export #' @family io-utils yread_tsv <- function(file, reader = utils::read.delim, params = list(), cache_dir = tempdir() ) { # e.g. params = list(sep = "\t", header = FALSE) yread(file, reader = reader, params = params, cache_dir = cache_dir ) } #' read file with caching #' #' This function read a file (local or url) and cache the content. #' @title yread #' @rdname yread #' @param file a file or url #' @param reader a function to read the 'file_url' #' @param params a list of parameters that passed to the 'reader' #' @param cache_dir a folder to store cache files. If set to NULL will disable cache. #' @return the output of using the 'reader' to read the 'file_url' with parameters specified by the 'params' #' @author Yonghe Xia and Guangchuang Yu #' @importFrom fs path_join #' @importFrom digest digest #' @export #' @family io-utils yread <- function(file, reader = readLines, params = list(), cache_dir = NULL) { if (!is.null(cache_dir)) { # Generate a unique cache filename based on the file URL cache_filename <- fs::path_join(c(cache_dir, paste0(digest::digest(file), ".rds"))) } else { cache_filename <- NULL } # Check if the cached file exists if (!is.null(cache_filename) && file.exists(cache_filename)) { # If cached file exists, load and return the cached data cached_data <- readRDS(cache_filename) return(cached_data) } else { # If cached file does not exist, read and cache the data data <- do.call(reader, args = c(file, params)) if (!is.null(cache_filename)) { saveRDS(data, cache_filename) } return(data) } } #' read clipboard #' #' #' @title read.cb #' @param reader function to read the clipboard #' @param ... parameters for the reader #' @return clipboard content, output type depends on the output of the reader #' @author Guangchuang Yu #' @importFrom utils read.table #' @export #' @family io-utils read.cb <- function(reader = read.table, ...) { os <- which_os() if (os == "Darwin") { clip <- pipe("pbpaste") } else { clip <- "clipboard" } reader(clip, ...) } #' open selected directory or file #' #' #' @title o #' @param file to be open; open working directory by default #' @return No return value, called for opening specific directory or file #' @examples #' \dontrun{ #' ## to open current working directory #' o() #' } #' @export #' @author Guangchuang Yu #' @family io-utils o <- function(file=".") { file <- normalizePath(file) os <- which_os() if (is.rserver()) { if (dir.exists(file)) { stop("open directory in RStudio Server is not supported.") } rserver_ip <- getOption("rserver_ip") if (!is.null(rserver_ip)) { rserver_port <- getOption("rserver_port") %||% '8787' if (!startsWith(rserver_ip, "http")) { rserver_ip <- paste0("http://", rserver_ip) } utils::browseURL( paste0( paste(rserver_ip, rserver_port, sep=":"), "/file_show?path=", file )) } else { file.edit <- get("file.edit") file.edit(file) } } else if (os == "Darwin") { cmd <- paste("open", file) system(cmd) } else if (os == "Linux") { cmd <- paste("xdg-open", file, "&") system(cmd) } else if (os == "Windows") { ## wd <- sub("/", "\\", getwd()) ## cmd <- paste("explorer", wd) ## suppressWarnings(shell(cmd)) cmd <- paste("start", file) shell(cmd) } } is.rserver <- function(){ RStudio.Version <- tryCatch(get("RStudio.Version"), error = function(e) NULL) if(is.null(RStudio.Version)) return(FALSE) if(!is.function(RStudio.Version)) return(FALSE) RStudio.Version()$mode == 'server' } #' Open data frame in Excel. It can be used in pipe. #' #' #' @title show_in_excel #' @param .data a data frame to be open #' @return original .data #' @export #' @author Guangchuang Yu #' @family io-utils show_in_excel <- function(.data) { f <- tempfile(fileext = '.csv') utils::write.csv(.data, file=f) o(f) invisible(.data) } yulab.utils/R/sudo-install.R0000644000176200001440000000113214444013464015470 0ustar liggesuserssudo_install <- function(pkgs) { ## pkgs_str <- paste0('"', pkgs, '"') %>% ## paste(collapse=',') %>% ## paste("c(", ., ")") ## rcmd0 <- 'options(repos = c(CRAN = "https://mirrors.e-ducation.cn/CRAN/"));' os <- Sys.info()[1] if (os == "Windows") { sudo <- "" } else { sudo <- "sudo" } for (pkg in pkgs) { pkg <- paste0('"', pkg, '"') rcmd <- paste0('install.packages(', pkg, ')') ## rcmd <- paste0(rcmd0, rcmd) cmd <- paste0(sudo, " Rscript -e '", rcmd, "'") system(cmd) } } yulab.utils/R/install_zip.R0000644000176200001440000000452015113174124015401 0ustar liggesusers#' install github package #' #' it download the zip file first and use `install_zip` to install it #' @title install_zip_gh #' @param repo github repo #' @param ref github branch, default is HEAD, which means the default branch of the GitHub repo #' @param subdir sub directory that contains R package files, default is NULL #' @param args argument to build package #' @return No return value, called for installing github package #' @importFrom utils download.file #' @export #' @author Guangchuang Yu install_zip_gh <- function(repo, ref = "HEAD", subdir = NULL, args = "--no-build-vignettes") { ## repo <- 'GuangchuangYu/nCov2019' url <- paste0('https://codeload.github.com/', repo, '/zip/', ref) f <- tempfile(fileext=".zip") mydownload(url, destfile = f) if (!is_valid_zip(f)) { stop("Invalid zip file downloaded, please check the 'ref' parameter to set a correct github branch.") } install_zip(f, subdir = subdir, args=args) } #' install R package from zip file of source codes #' #' #' @title install_zip #' @param file zip file #' @param args argument to build package #' @param subdir sub directory that contains R package files, default is NULL #' @return No return value, called for install R package from zip file of source codes #' @export #' @author Guangchuang Yu install_zip <- function(file, subdir = NULL, args = "--no-build-vignettes") { dir <- tempfile() utils::unzip(file, exdir=dir) fs <- list.files(path=dir, full.names=T) #if (length(fs) == 1 && dir.exists(fs)) { # dir <- fs #} ## dir <- paste0(dir, '/', basename(repo), '-master') dir <- fs[which.max(file.info(fs)$atime)] if (!is.null(subdir)) dir <- file.path(dir, subdir) if ("INDEX" %in% list.files(dir)) { # file is binary package pkg <- file } else { # file is zip of package source ## remotes::install_local(path=dir, ..., force=TRUE) ## pkg <- pkgbuild::build(dir, args=args) build <- get_fun_from_pkg('pkgbuild', 'build') pkg <- build(dir, args=args) } utils::install.packages(pkg, repos=NULL) } is_valid_zip <- function(zipfile) { fs <- tryCatch(utils::unzip(zipfile, list=TRUE), error = function(e) NULL) if (is.null(fs)) return(FALSE) return(TRUE) } yulab.utils/R/bib-knownledge.R0000644000176200001440000002516415102535573015756 0ustar liggesusersbib_knownledge <- function(id) { bib <- c( innovation2024 = bib_clusterProfiler_innovation2024, np2024 = bib_clusterProfiler_np2024, innovation2021 = bib_clusterProfiler_innovation2021, omics2012 = bib_clusterProfiler_omics2012, chipseeker2022 = bib_chipseeker_cp2022, chipseeker2015 = bib_chipseeker_bioinfo2015, gosemsim2020 = bib_gosemsim_mmb2020, gosemsim2010 = bib_gosemsim_bioinfo2010, meshes2018 = bib_meshes_bioinfo2018, reactome2016 = bib_reactomepa_mbs20016, dose2015 = bib_dose_bioinfo2015 ) if (!id %in% names(bib)) { return(NULL) } bib[id] } ref_knownledge <- function() { refs <- c( ChIPseeker_CP = paste( "Qianwen Wang, Ming Li, Tianzhi Wu, Li Zhan, Lin Li, Meijun Chen, Wenqin Xie, Zijing Xie, Erqiang Hu, Shuangbin Xu, Guangchuang Yu.", "Exploring epigenomic datasets by ChIPseeker.", "Current Protocols. 2022, 2(10): e585" ), ChIPseeker = paste( "Guangchuang Yu, Li-Gen Wang, and Qing-Yu He.", "ChIPseeker: an R/Bioconductor package for ChIP peak annotation, comparison and visualization.", "Bioinformatics. 2015, 31(14):2382-2383" ), GOSemSim_MMB = paste( "Guangchuang Yu.", "Gene Ontology Semantic Similarity Analysis Using GOSemSim.", "In: Kidder B. (eds) Stem Cell Transcriptional Networks.", "Methods in Molecular Biology. 2020, 2117:207-215.", "Humana, New York, NY." ), GOSemSim = paste( "Guangchuang Yu, Fei Li, Yide Qin, Xiaochen Bo, Yibo Wu and Shengqi Wang.", "GOSemSim: an R package for measuring semantic similarity among GO terms and gene products.", "Bioinformatics. 2010, 26(7):976-978" ), DOSE = paste( "Guangchuang Yu, Li-Gen Wang, Guang-Rong Yan, Qing-Yu He.", "DOSE: an R/Bioconductor package for Disease Ontology Semantic and Enrichment analysis.", "Bioinformatics. 2015, 31(4):608-609" ), ReactomePA = paste( "Guangchuang Yu, Qing-Yu He.", "ReactomePA: an R/Bioconductor package for reactome pathway analysis and visualization.", "Molecular BioSystems. 2016, 12(2):477-479" ), clusterProfiler_NP = paste( "S Xu, E Hu, Y Cai, Z Xie, X Luo, L Zhan, W Tang,", "Q Wang, B Liu, R Wang, W Xie, T Wu, L Xie, G Yu.", "Using clusterProfiler to characterize multiomics data.", "Nature Protocols. 2024, 19(11):3292-3320" ), clusterProfiler_Innovation2024 = paste( "G Yu.", "Thirteen years of clusterProfiler.", "The Innovation. 2024, 5(6):100722" ), clusterProfiler_Innovation = paste( "T Wu, E Hu, S Xu, M Chen, P Guo, Z Dai, T Feng, L Zhou,", "W Tang, L Zhan, X Fu, S Liu, X Bo, and G Yu.", "clusterProfiler 4.0: A universal enrichment tool for interpreting omics data.", "The Innovation. 2021, 2(3):100141" ), clusterProfiler = paste( "Guangchuang Yu, Li-Gen Wang, Yanyan Han and Qing-Yu He.", "clusterProfiler: an R package for comparing biological themes among gene clusters.", "OMICS: A Journal of Integrative Biology. 2012, 16(5):284-287" ), meshes = paste( "Guangchuang Yu.", "Using meshes for MeSH term enrichment and semantic analyses.", "Bioinformatics. 2018, 34(21):3766-3767, doi:10.1093/bioinformatics/bty410" ) ) return(refs) } ref2 <- ref_knownledge() bib_clusterProfiler_innovation2024 <- citEntry( entry = "ARTICLE", title = "Thirteen years of clusterProfiler", author = c(person("Guangchuang", "Yu")), url = "https://doi.org/10.1016/j.xinn.2024.100722", doi = "10.1016/j.xinn.2024.100722", journal = "The Innovation", month = "Nov", year = "2024", volume = "5", number = "6", pages = "100722", textVersion = ref2['clusterProfiler_Innovation2024'] ) bib_clusterProfiler_np2024 <- citEntry( entry = "ARTICLE", title = "Using clusterProfiler to characterize multiomics data", author = c( person("Shuangbin", "Xu"), person("Erqiang", "Hu"), person("Yantong", "Cai"), person("Zijing", "Xie"), person("Xiao", "Luo"), person("Li", "Zhan"), person("Wenli", "Tang"), person("Qianwen", "Wang"), person("Bingdong", "Liu"), person("Rui", "Wang"), person("Wenqin", "Xie"), person("Tianzhi", "Wu"), person("Liwei", "Xie"), person("Guangchuang", "Yu") ), issn = "1750-2799", url = "https://www.nature.com/articles/s41596-024-01020-z", doi = "10.1038/s41596-024-01020-z", journal = "Nature Protocols", month = "Nov", year = "2024", volume = "19", number = "11", pages = "3292-3320", textVersion = ref2['clusterProfiler_NP'] ) bib_clusterProfiler_innovation2021 <- citEntry( entry = "ARTICLE", title = "clusterProfiler 4.0: A universal enrichment tool for interpreting omics data", author = c( person("Tianzhi", "Wu"), person("Erqiang", "Hu"), person("Shuangbin", "Xu"), person("Meijun", "Chen"), person("Pingfan", "Guo"), person("Zehan", "Dai"), person("Tingze", "Feng"), person("Lang", "Zhou"), person("Wenli", "Tang"), person("Li", "Zhan"), person("xiaochong", "Fu"), person("Shanshan", "Liu"), person("Xiaochen", "Bo"), person("Guangchuang", "Yu") ), journal = "The Innovation", year = "2021", volume = "2", number = "3", pages = "100141", PMID = "", doi = "10.1016/j.xinn.2021.100141", textVersion = ref2['clusterProfiler_Innovation'] ) bib_clusterProfiler_omics2012 <- citEntry( entry = "ARTICLE", title = "clusterProfiler: an R package for comparing biological themes among gene clusters", author = personList( as.person("Guangchuang Yu"), as.person("Li-Gen Wang"), as.person("Yanyan Han"), as.person("Qing-Yu He") ), journal = "OMICS: A Journal of Integrative Biology", year = "2012", volume = "16", number = "5", pages = "284-287", PMID = "22455463", doi = "10.1089/omi.2011.0118", textVersion = ref2['clusterProfiler'] ) bib_meshes_bioinfo2018 <- citEntry( entry = "ARTICLE", title = "Using meshes for MeSH term enrichment and semantic analyses ", author = as.person("Guangchuang Yu"), journal = "Bioinformatics", year = "2018", volume = "34", number = "21", pages = "3766-3767", PMID = "29790928", doi = "10.1093/bioinformatics/bty410", textVersion = ref2["meshes"] ) bib_reactomepa_mbs20016 <- citEntry( entry = "ARTICLE", title = "ReactomePA: an R/Bioconductor package for reactome pathway analysis and visualization", author = c( person("Guangchuang", "Yu"), person("Qing-Yu", "He") ), journal = "Molecular BioSystems", year = "2016", volume = "12", number = "12", pages = "477-479", PMID = "26661513", url = "http://pubs.rsc.org/en/Content/ArticleLanding/2015/MB/C5MB00663E", doi = "10.1039/C5MB00663E", textVersion = ref2['ReactomePA'] ) bib_dose_bioinfo2015 <- citEntry( entry = "ARTICLE", title = "DOSE: an R/Bioconductor package for Disease Ontology Semantic and Enrichment analysis", author = c( person("Guangchuang", "Yu"), person("Li-Gen", "Wang"), person("Guang-Rong", "Yan"), person("Qing-Yu", "He") ), journal = "Bioinformatics", year = "2015", volume = "31", number = "4", pages = "608-609", PMID = "", url = "http://bioinformatics.oxfordjournals.org/content/31/4/608", doi = "10.1093/bioinformatics/btu684", textVersion = ref2['DOSE'] ) bib_chipseeker_cp2022 <- citEntry( entry = "ARTICLE", title = "Exploring epigenomic datasets by ChIPseeker", author = c( person("Qianwen", "Wang"), person("Ming", "Li"), person("Tianzhi", "Wu"), person("Li", "Zhan"), person("Lin", "Li"), person("Meijun", "Chen"), person("Wenqin", "Xie"), person("Zijing", "Xie"), person("Erqiang", "Hu"), person("Shuangbin", "Xu"), person("Guangchuang", "Yu", email = "guangchuangyu@gmail.com") ), journal = "Current Protocols", year = "2022", volume = "2", number = "10", pages = "e585", PMID = "36286622", doi = "10.1002/cpz1.585", url = "https://onlinelibrary.wiley.com/share/author/GYJGUBYCTRMYJFN2JFZZ?target=10.1002/cpz1.585", textVersion = ref2['ChIPseeker_CP'] ) bib_chipseeker_bioinfo2015 <- citEntry( entry = "ARTICLE", title = "ChIPseeker: an R/Bioconductor package for ChIP peak annotation, comparison and visualization", author = personList( as.person("Guangchuang Yu"), as.person("Li-Gen Wang"), as.person("Qing-Yu He") ), journal = "Bioinformatics", year = "2015", volume = "31", number = "14", pages = "2382-2383", PMID = "25765347", doi = "10.1093/bioinformatics/btv145", textVersion = ref2['ChIPseeker'] ) bib_gosemsim_mmb2020 <- citEntry( entry = "ARTICLE", title = "Gene Ontology Semantic Similarity Analysis Using GOSemSim", author = person("Guangchuang", "Yu"), journal = "Methods in Molecular Biology", shortjournal = "Methods Mol. Biol.", year = "2020", volume = "2117", pages = "207-215", PMID = "31960380", issn = "1940-6029", doi = "10.1007/978-1-0716-0301-7_11", textVersion = ref2['GOSemSim_MMB'] ) bib_gosemsim_bioinfo2010 <- citEntry( entry = "ARTICLE", title = "GOSemSim: an R package for measuring semantic similarity among GO terms and gene products", author = personList( as.person("Guangchuang Yu"), as.person("Fei Li"), as.person("Yide Qin"), as.person("Xiaochen Bo"), as.person("Yibo Wu"), as.person("Shengqi Wang") ), journal = "Bioinformatics", year = "2010", volume = "26", number = "7", pages = "976-978", PMID = "20179076", doi = "10.1093/bioinformatics/btq064", textVersion = ref2['GOSemSim'] ) yulab.utils/R/utilities.R0000644000176200001440000000254015115330064015063 0ustar liggesusers`%||%` <- function(a, b) if (is.null(a)) b else a .hi <- function(package = NULL, n=2L) { env <- sys.parent(n) if (!is.null(env)) { caller <- deparse(sys.call(env)) caller <- sub("(\\w+)\\(.*", "\\1", caller) if (is.null(package)) return(FALSE) if (get_caller_package(caller) %in% package) return(TRUE) } return(FALSE) } get_caller_package <- function(caller) { if (is.character(caller)) { fn <- tryCatch(get(caller, mode = "function"), error = function(e) NULL) if (is.null(fn)) return("") } else { fn <- caller } environmentName(environment(fn)) } .called_by_package <- function(package) { call_stack <- sys.calls() pattern <- sprintf("^package:%s", package) for (call in call_stack) { call <- as.character(as.expression(call)) if (grepl(pattern, call)) { return(TRUE) } } return(FALSE) } assert_single_string <- function(x, name) { if (!is.character(x) || length(x) != 1 || x == "") { yulab_abort(sprintf("%s must be a single non-empty character string", name), class = "parameter_error") } invisible(TRUE) } normalize_path2 <- function(path) { normalizePath(path, winslash = "/", mustWork = FALSE) } has_permission <- function(path, mode) { file.access(path, mode) == 0 } yulab.utils/R/error-utils.r0000644000176200001440000003066115117723164015415 0ustar liggesusers #' Standardized error handling #' #' Provides `rlang`-based wrappers for messaging: `yulab_abort()`, `yulab_warn()`, #' and `yulab_inform()`. #' #' @param message Message string #' @param class Custom class for categorization #' @param ... Additional context #' @return No return value #' @importFrom rlang abort #' @rdname yulab-message #' @export #' @family messages yulab_abort <- function(message, class = "yulab_error", ...) { abort( message = message, class = c(class, "yulab_error"), ... ) } #' @importFrom rlang warn #' @rdname yulab-message #' @export yulab_warn <- function(message, class = "yulab_warning", ...) { warn( message = message, class = c(class, "yulab_warning"), ... ) } #' @importFrom rlang inform #' @rdname yulab-message #' @export yulab_inform <- function(message, class = "yulab_info", ...) { inform( message = message, class = c(class, "yulab_info"), ... ) } #' Validate input with type/length constraints #' #' Enhanced input validation supporting base types and class checks. #' @param x Object to check #' @param type Expected type (e.g., `"numeric"`, `"character"`, or class name) #' @param length Expected length #' @param min_length Minimum length #' @param max_length Maximum length #' @param allow_null Whether `NULL` is allowed #' @param arg_name Argument name for messages #' @return Invisible `TRUE` on success #' @export #' @family validate-utils check_input <- function(x, type = NULL, length = NULL, min_length = NULL, max_length = NULL, allow_null = FALSE, arg_name = "input") { # Validate function parameters assert_single_string(arg_name, "arg_name") if (!is.null(type) && (!is.character(type) || length(type) != 1)) { yulab_abort("type must be a single character string or NULL", class = "parameter_error") } if (!is.null(length) && (!is.numeric(length) || length(length) != 1 || length <= 0)) { yulab_abort("length must be a single positive number or NULL", class = "parameter_error") } if (!is.null(min_length) && (!is.numeric(min_length) || length(min_length) != 1 || min_length < 0)) { yulab_abort("min_length must be a single non-negative number or NULL", class = "parameter_error") } if (!is.null(max_length) && (!is.numeric(max_length) || length(max_length) != 1 || max_length <= 0)) { yulab_abort("max_length must be a single positive number or NULL", class = "parameter_error") } # Check for NULL values if (allow_null && is.null(x)) { return(invisible(TRUE)) } if (is.null(x)) { yulab_abort( paste0("Invalid ", arg_name, ": cannot be NULL"), class = "null_error" ) } # Enhanced type checking with support for basic types if (!is.null(type)) { # Check for basic types first basic_types <- c("numeric", "character", "logical", "integer", "double", "complex", "raw") if (type %in% basic_types) { if (typeof(x) != type) { yulab_abort( paste0("Invalid ", arg_name, ": expected ", type, ", got ", typeof(x)), class = "type_error" ) } } else { # Check for S3/S4 classes if (!inherits(x, type)) { yulab_abort( paste0("Invalid ", arg_name, ": expected ", type, ", got ", class(x)[1]), class = "type_error" ) } } } # Length validation x_length <- length(x) if (!is.null(length) && x_length != length) { yulab_abort( paste0("Invalid ", arg_name, ": expected length ", length, ", got ", x_length), class = "length_error" ) } if (!is.null(min_length) && x_length < min_length) { yulab_abort( paste0("Invalid ", arg_name, ": minimum length is ", min_length, ", got ", x_length), class = "length_error" ) } if (!is.null(max_length) && x_length > max_length) { yulab_abort( paste0("Invalid ", arg_name, ": maximum length is ", max_length, ", got ", x_length), class = "length_error" ) } invisible(TRUE) } #' Check if required packages are installed with informative errors #' #' Enhanced package checking with better error messages and validation #' @rdname check_packages #' @param packages Character vector of package names #' @param reason Reason why these packages are needed #' @return Invisible TRUE if all packages are available, throws error otherwise #' @export #' @family validate-utils check_packages <- function(packages, reason = "for this functionality") { # Validate input parameters if (!is.character(packages) || length(packages) == 0) { yulab_abort("packages must be a non-empty character vector", class = "parameter_error") } if (is.null(reason)) { call <- sys.call(1L) reason <- sprintf("for %s()", as.character(call)[1]) } if (!is.character(reason) || length(reason) != 1) { yulab_abort("reason must be a single character string", class = "parameter_error") } # Remove duplicates and empty strings packages <- unique(packages[packages != ""]) if (length(packages) == 0) { yulab_warn("No valid package names provided", class = "empty_package_list_warning") return(invisible(TRUE)) } # Check for missing packages # missing_pkgs <- packages[!sapply(packages, requireNamespace, quietly = TRUE)] missing_pkgs <- packages[!vapply(packages, is.installed, logical(1))] if (length(missing_pkgs) > 0) { pkg_list <- paste(missing_pkgs, collapse = ", ") yulab_abort( paste0("Missing required packages ", reason, ": ", pkg_list, ". ", "Please install with: install.packages(c(", paste0("\"", missing_pkgs, "\"", collapse = ", "), "))"), class = "missing_package_error" ) } invisible(TRUE) } #' @rdname check_packages #' @export check_pkg <- check_packages #' Handle file operations with proper error messages #' #' Enhanced file validation with comprehensive checks and better error messages #' @param path File path #' @param operation Operation being performed (read, write, etc.) #' @param must_exist Whether the file must exist #' @return Invisible TRUE if operation can proceed, throws error otherwise #' @export #' @family validate-utils check_file <- function(path, operation = "read", must_exist = TRUE) { assert_single_string(path, "path") assert_single_string(operation, "operation") normalized_path <- normalize_path2(path) if (must_exist) { if (!file.exists(path)) { yulab_abort( paste0("File not found for ", operation, ": ", normalized_path), class = "file_not_found_error" ) } if (grepl("read", operation, ignore.case = TRUE)) { if (!has_permission(path, 4)) { yulab_abort( paste0("No read permission for file: ", normalized_path), class = "file_permission_error" ) } } } else { # For files that shouldn't exist (e.g., write operations) if (file.exists(path)) { yulab_warn( paste0("File already exists and will be overwritten: ", normalized_path), class = "file_overwrite_warning" ) if (!has_permission(path, 2)) { yulab_abort( paste0("No write permission for existing file: ", normalized_path), class = "file_permission_error" ) } } } invisible(TRUE) } #' Check if value is within specified range #' #' Validates that a numeric value falls within the specified range #' @param x Numeric value to check #' @param min Minimum allowed value (optional) #' @param max Maximum allowed value (optional) #' @param inclusive Whether bounds are inclusive (default: TRUE) #' @param arg_name Name of the argument for error messages #' @return Invisible TRUE if valid, throws error otherwise #' @export #' @family validate-utils check_range <- function(x, min = NULL, max = NULL, inclusive = TRUE, arg_name = "value") { # Validate parameters if (!is.numeric(x) || length(x) != 1) { yulab_abort(paste0(arg_name, " must be a single numeric value"), class = "parameter_error") } if (!is.null(min) && (!is.numeric(min) || length(min) != 1)) { yulab_abort("min must be a single numeric value or NULL", class = "parameter_error") } if (!is.null(max) && (!is.numeric(max) || length(max) != 1)) { yulab_abort("max must be a single numeric value or NULL", class = "parameter_error") } if (!is.logical(inclusive) || length(inclusive) != 1) { yulab_abort("inclusive must be a single logical value", class = "parameter_error") } # Range validation if (!is.null(min)) { if (inclusive && x < min) { yulab_abort( paste0("Invalid ", arg_name, ": minimum value is ", min, ", got ", x), class = "range_error" ) } else if (!inclusive && x <= min) { yulab_abort( paste0("Invalid ", arg_name, ": must be greater than ", min, ", got ", x), class = "range_error" ) } } if (!is.null(max)) { if (inclusive && x > max) { yulab_abort( paste0("Invalid ", arg_name, ": maximum value is ", max, ", got ", x), class = "range_error" ) } else if (!inclusive && x >= max) { yulab_abort( paste0("Invalid ", arg_name, ": must be less than ", max, ", got ", x), class = "range_error" ) } } invisible(TRUE) } #' Check if directory exists and is accessible #' #' Validates directory existence and accessibility with options to create if missing #' @param path Directory path #' @param create_if_missing Whether to create directory if it doesn't exist #' @param check_write_permission Whether to verify write permissions #' @param arg_name Name of the argument for error messages #' @return Invisible TRUE if valid, throws error otherwise #' @export #' @family validate-utils check_directory <- function(path, create_if_missing = FALSE, check_write_permission = TRUE, arg_name = "directory") { assert_single_string(path, "path") if (!is.logical(create_if_missing) || length(create_if_missing) != 1) { yulab_abort("create_if_missing must be a single logical value", class = "parameter_error") } if (!is.logical(check_write_permission) || length(check_write_permission) != 1) { yulab_abort("check_write_permission must be a single logical value", class = "parameter_error") } normalized_path <- normalize_path2(path) if (!dir.exists(path)) { if (create_if_missing) { # Attempt to create directory dir_created <- tryCatch({ dir.create(path, recursive = TRUE, showWarnings = FALSE) TRUE }, error = function(e) FALSE) if (!dir_created) { yulab_abort( paste0("Failed to create directory: ", normalized_path), class = "directory_creation_error" ) } yulab_inform(paste0("Created directory: ", normalized_path), class = "directory_created_info") } else { yulab_abort( paste0("Directory does not exist: ", normalized_path), class = "directory_not_found_error" ) } } if (check_write_permission) { if (!has_permission(path, 2)) { yulab_abort( paste0("No write permission for directory: ", normalized_path), class = "directory_permission_error" ) } } invisible(TRUE) } yulab.utils/R/zzz.R0000644000176200001440000000034114651121636013711 0ustar liggesusers## @importFrom memoise memoise .onLoad <- function(libname, pkgname) { # yread <<- memoise::memoise(yread) # yread_tsv <<- memoise::memoise(yread_tsv) # packageStartupMessage(yulab_msg(pkgname)) } yulab.utils/R/scale.R0000644000176200001440000000055615113174111014141 0ustar liggesusers#' normalized data by range #' #' #' @title scale-range #' @param data the input data. #' @return normalized data #' @export #' @author Guangchuang Yu scale_range <- function(data) { normalized_data <- apply(data, 2, function(x) { (x - min(x, na.rm = TRUE)) / (max(x, na.rm = TRUE) - min(x, na.rm = TRUE)) }) as.data.frame(normalized_data) } yulab.utils/R/yulab-utils-package.R0000644000176200001440000000004514560213723016716 0ustar liggesusers#' @keywords internal "_PACKAGE" yulab.utils/R/matrix-utils.R0000644000176200001440000000166415113174121015516 0ustar liggesusers#' convert a matrix to a tidy data frame #' (from wide to long format as described in the tidyverse concept) #' #' #' @title mat2df #' @param x the input matrix #' @return a data.frame in long format with the 'value' column stores the original values #' and 'row' and 'col' columns stored in row and column index as in x #' @examples #' x <- matrix(1:15, nrow = 3) #' mat2df(x) #' @export #' @author Guangchuang Yu mat2df <- function(x) { nr <- nrow(x) nc <- ncol(x) d <- data.frame( value = as.vector(x), row = rep(1:nr, times = nc), col = rep(1:nc, each = nr) ) return(d) } #' convert a matrix to a list #' #' #' @title mat2list #' @param x the input matrix #' @return a list that contains matrix columns as its elements #' @examples #' x <- matrix(1:15, nrow = 3) #' mat2list(x) #' @export mat2list <- function(x){ lapply(seq_len(ncol(x)), function(i) x[,i]) } yulab.utils/R/quiet.r0000644000176200001440000000053115116450203014234 0ustar liggesusers#' Suppress messages and output from `x` #' @title quiet #' @param x some code #' @return the result of `x` #' @importFrom utils capture.output #' @export quiet <- function(x) { res <- suppressMessages({ out <- NULL capture.output({ out <- force(x) }, file = NULL) out }) invisible(res) } yulab.utils/R/concat.r0000644000176200001440000000456314723520003014364 0ustar liggesusers#' chunked array #' #' concate two vector/chunked_array into a chunked_array object #' @title c2 #' @param x a vector or chunked_array object #' @param y a vector or chunked_array object #' @return chunked_array object #' @author Guangchuang Yu #' @export c2 <- function(x, y) { if (length(x) == 0) return(y) if (length(y) == 0) return(x) same_mode <- (is.numeric(x) && is.numeric(y)) || (is.character(x) && is.character(y)) if (!same_mode) stop("x and y should be both numeric or character vector.") X <- as_chunked_array(x) Y <- as_chunked_array(y) res <- structure( list( vector_list = c(X$vector_list, Y$vector_list), idx = c(X$idx, Y$idx + length(X)) ), class = "chunked_array" ) return(res) } as_chunked_array <- function(x) { if (inherits(x, "chunked_array")) return(x) if (!is.numeric(x) && !is.character(x)) { stop("only numeric/character vector supported") } structure( list( vector_list = list(x), idx = 0 ), class = "chunked_array" ) } #' @method as.vector chunked_array #' @export as.vector.chunked_array <- function(x, mode = "any") { unlist(x$vector_list) } #' @method print chunked_array #' @export print.chunked_array <- function(x, ...) { n <- length(x) msg <- sprintf("chunked array with size of %d\n", n) cat(msg) } #' @method length chunked_array #' @export length.chunked_array <- function(x) { last_item(x$idx) + length(last_item(x$vector_list)) } last_item <- function(x) { if (is.list(x)) return(x[[length(x)]]) x[length(x)] } #' @method [ chunked_array #' @export `[.chunked_array` <- function(x, i, ...) { # array_idx <- vapply(i, \(ii) last_item(which(ii > x$idx)), numeric(1)) # # pos <- i - x$idx[array_idx] # # output <- ifelse(is.numeric(x), numeric(1), character(1)) # vapply(seq_along(i), \(j) x$vector_list[[array_idx[j]]][pos[j]], output) as.vector(x)[i] # faster :) } #' @method is.numeric chunked_array #' @export is.numeric.chunked_array <- function(x) { is.numeric(x$vector_list[[1]]) } #' @method is.character chunked_array #' @export is.character.chunked_array <- function(x) { is.character(x$vector_list[[1]]) } yulab.utils/R/parse_ratio.R0000644000176200001440000000117415115415657015376 0ustar liggesusers##' Parse character ratio to double, e.g., `1/5` → `0.2` ##' ##' ##' @title parse_ratio ##' @param ratio Character vector of ratios ##' @return Numeric vector ##' @export ##' @author Guangchuang Yu parse_ratio <- function(ratio) { x <- as.character(ratio) x <- sub("^\\s*", "", x) x <- sub("\\s*$", "", x) suppressWarnings({ numerator <- as.numeric(sub("/\\s*\\d+$", "", x)) denominator <- as.numeric(sub("^\\s*\\d+\\s*/\\s*", "", x)) }) bad <- is.na(numerator) | is.na(denominator) | denominator == 0 res <- numerator/denominator res[bad] <- NA_real_ res } yulab.utils/R/regexpr.R0000644000176200001440000000347415117723340014540 0ustar liggesusers#' @rdname regexpr-style #' @export #' @family regex-utils set_PCRE <- function() { options(regexpr_use_perl = TRUE) } #' @rdname regexpr-style #' @export #' @family regex-utils set_TRE <- function() { options(regexpr_use_perl = FALSE) } #' @rdname regexpr-style #' @export #' @family regex-utils use_perl <- function() { res <- getOption("regexpr_use_perl", default = auto_set_regexpr_style()) return(res) } #' Switch regular expression style (PCRE vs TRE) #' #' - `set_regexpr_style()` selects the style explicitly. #' - `auto_set_regexpr_style()` chooses based on OS (TRE on Windows; PCRE elsewhere). #' - `set_PCRE()` and `set_TRE()` force the style. #' #' These functions do not change the behavior of `gsub()`/`regexpr()` directly. #' They set a global option that you can read via `use_perl()` and pass to `gsub()`/`regexpr()`. #' #' @rdname regexpr-style #' @param style one of 'PCRE' or 'TRE' #' @return Logical indicating whether to use `perl` #' @references https://stackoverflow.com/questions/47240375/regular-expressions-in-base-r-perl-true-vs-the-default-pcre-vs-tre #' @export #' @author Guangchuang Yu #' @family regex-utils set_regexpr_style <- function(style) { if (missing(style)) { message("style is not specific, set automatically.") auto_set_regexpr_style() } else { style <- match.arg(style, c("PCRE", "TRE")) if (style == "PCRE") { set_PCRE() } else { set_TRE() } } res <- getOption("regexpr_use_perl") invisible(res) } #' @rdname regexpr-style #' @export auto_set_regexpr_style <- function() { if (which_os() == "Windows") { set_TRE() res <- FALSE } else { set_PCRE() res <- TRUE } invisible(res) } yulab.utils/R/load-orgdb.r0000644000176200001440000000077715115206073015136 0ustar liggesusers#' load OrgDb #' #' #' @title load_OrgDb #' @param OrgDb OrgDb object or OrgDb name #' @return OrgDb object #' @importFrom methods is #' @importFrom utils getFromNamespace #' @export #' @author Guangchuang Yu \url{https://yulab-smu.top} load_OrgDb <- function(OrgDb) { if (is.character(OrgDb)) { check_packages(OrgDb, "for `load_OrgDb()`") # OrgDb <- utils::getFromNamespace(OrgDb, OrgDb) OrgDb <- get(OrgDb, envir = asNamespace(OrgDb)) } return(OrgDb) } yulab.utils/R/scihub-dl.R0000644000176200001440000000157315116451000014722 0ustar liggesusers#' download publication via scihub #' #' using scihub to download publication using doi #' @rdname scihub-dl #' @name scihub_dl #' @param doi doi #' @param scihub scihub website #' @param download whether download the pdf file #' @return pdf url #' @author Guangchuang Yu #' @export scihub_dl <- function(doi, scihub = 'sci-hub.tw', download=TRUE) { url <- paste0('https://', scihub, '/', doi) if (!has_internet()) return(invisible(NA_character_)) x <- tryCatch(readLines(url, warn = FALSE), error = function(e) character()) i <- grep('id = "pdf"', x) if (!length(i)) return(invisible(NA_character_)) pdf_url <- sub(".*(//.*\\.pdf).*", "https:\\1", x[i]) if (download) { outfile <- sub(".*/", "", pdf_url) utils::download.file(pdf_url, destfile = outfile, quiet = TRUE, mode = "wb") } invisible(pdf_url) } yulab.utils/R/str-utils.R0000644000176200001440000000623315115331154015022 0ustar liggesusers#' Wrap long strings to multiple lines #' @family str-utils #' #' #' @title str_wrap #' @param string Input string #' @param width Maximum characters before wrapping #' @return Updated strings with `"\n"` inserted #' @export #' @author Guangchuang Yu str_wrap <- function(string, width = getOption("width")) { result <- vapply(string, FUN = function(st) { if (!is.numeric(width) || length(width) != 1 || width < 1) { return(st) } words <- list() i <- 1 while (nchar(st) > width) { if (!grepl(pattern = " ", x = st, perl = use_perl())) break y <- gregexpr(pattern = ' ', text = st, perl = use_perl()) y <- y[[1]] n <- nchar(st) y <- c(y,n) idx <- which(y < width) # When the length of first word > width if (length(idx) == 0) idx <- 1 # Split the string into two pieces # The length of first piece is small than width words[[i]] <- substring(st, 1, y[idx[length(idx)]] - 1) st <- substring(st, y[idx[length(idx)]] + 1, n) i <- i + 1 } words[[i]] <- st paste0(unlist(words), collapse="\n") }, FUN.VALUE = character(1) ) names(result) <- NULL result } #' Detect patterns at the beginning or end of strings #' @family str-utils #' #' #' @title str_starts #' @rdname str-starts-ends #' @param string Input string #' @param pattern Pattern to match #' @param negate If `TRUE`, return non-matching elements #' @return a logical vector #' @export #' @author Guangchuang Yu str_starts <- function(string, pattern, negate=FALSE) { pattern <- paste0('^', pattern) str_detect(string, pattern, negate) } #' @rdname str-starts-ends #' @export str_ends <- function(string, pattern, negate=FALSE) { pattern <- paste0(pattern, '$') str_detect(string, pattern, negate) } #' Detect presence/absence of a match #' @family str-utils #' #' #' @title str_detect #' @rdname str-detect #' @param string Input string #' @param pattern Pattern to look for #' @param negate If `TRUE`, invert the result #' @return Logical vector #' @export #' @author Guangchuang Yu str_detect <- function(string, pattern, negate = FALSE) { ## faster than stringr::str_detect res <- grepl(pattern = pattern, x = string, perl = use_perl()) if (negate) res <- !res return(res) } #' Extract a substring using a pattern #' @family str-utils #' #' #' @title str_extract #' @rdname str-extract #' @param string Input string #' @param pattern Regular expression to extract #' @return Substring #' @export #' @author Guangchuang Yu str_extract <- function(string, pattern) { i <- regexpr(pattern = pattern, text = string, perl = use_perl()) j <- attr(i, 'match.length') res <- substring(string, i, i+j-1) res[res == ""] <- NA return(res) } yulab.utils/R/yulab-msg.R0000644000176200001440000000551415115330657014764 0ustar liggesusers#' Messages for YuLab packages #' #' #' @title yulab_msg #' @param pkgname Package name #' @param n Number of citation messages #' @return Package message #' @export #' @author Guangchuang Yu yulab_msg <- function(pkgname = NULL, n = 1) { pkgs_knownledge <- c("GOSemSim", "DOSE", "clusterProfiler", "meshes", "ReactomePA", "MicrobiomeProfiler", "enrichplot", "ChIPseeker") pkgs_tree <- c("tidytree", "treeio", "ggtree", "ggtreeExtra", "ggtreeSpace", "shinyTempSignal") if (pkgname %in% pkgs_knownledge) { id <- 1 } else if (pkgname %in% pkgs_tree) { id <- 2 } else { id <- 3 } header_msg <- yulab_msg_header(pkgname, id) if (id == 1) { citation_msg <- random_ref(pkgname, ref_knownledge(), random_n = n) } else if (id == 2) { citation_msg <- random_ref(pkgname, ref_ggtree(), random_n = n) } else { citation_msg <- pkg_ref(pkgname) } if (is.null(citation_msg)) return(header_msg) sprintf("%s%s", header_msg, citation_msg) } #' @importFrom utils packageDescription yulab_msg_header <- function(pkgname = NULL, id = 3) { if (is.null(pkgname)) return(NULL) pages <- c("contribution-knowledge-mining/", "contribution-tree-data/", "") urls <- sprintf("https://yulab-smu.top/%s", pages) pkgVersion <- packageDescription(pkgname, fields = "Version") sprintf("%s v%s Learn more at %s\n\n", pkgname, pkgVersion, urls[id]) } random_ref <- function(pkgname, refs, random_n) { msg <- "Please cite:\n\n" indx <- grep(pkgname, names(refs)) if (length(indx) == 0) { refs <- sample(refs, random_n) } else if (length(indx) > random_n) { refs <- sample(refs[indx], random_n) } else { refs <- c(refs[indx], sample(refs[-indx], random_n - length(indx))) } refs <- paste0(refs, collapse="\n") if (nchar(refs) <= 0) return(NULL) paste(strwrap(paste0(msg, refs)), collapse = "\n") } pkg_ref <- function(pkgname) { refs <- c( fanyi = paste("D Wang, G Chen, L Li, S Wen, Z Xie, X Luo, L Zhan, S Xu, J Li, R Wang, Q Wang, G Yu.", "Reducing language barriers, promoting information absorption, and communication using fanyi.", "Chinese Medical Journal. 2024, 137(16):1950-1956. doi: 10.1097/CM9.0000000000003242") ) ref <- refs[pkgname] if (is.null(ref) || is.na(ref)) return(NULL) msg <- "Please cite:\n\n" str_wrap(paste0(msg, ref, "\n")) } yulab.utils/NAMESPACE0000644000176200001440000000431615117720067013756 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method("[",chunked_array) S3method(as.vector,chunked_array) S3method(is.character,chunked_array) S3method(is.numeric,chunked_array) S3method(length,chunked_array) S3method(print,chunked_array) S3method(print,exec) export(Biocpkg) export(CRANpkg) export(Githubpkg) export(auto_set_regexpr_style) export(c2) export(cache_list_items) export(cache_load) export(cache_save) export(cache_size) export(check_directory) export(check_file) export(check_input) export(check_packages) export(check_pkg) export(check_range) export(combinations) export(download_yulab_file) export(exec) export(get_cache) export(get_cache_element) export(get_cache_item) export(get_dependencies) export(get_fun_from_pkg) export(has_internet) export(initial_cache) export(initial_cache_item) export(install_zip) export(install_zip_gh) export(is.installed) export(load_OrgDb) export(ls2df) export(mat2df) export(mat2list) export(mypkg) export(o) export(packageTitle) export(parse_ratio) export(pload) export(prune_cache_item) export(quiet) export(rbindlist) export(read.cb) export(rm_cache) export(rm_cache_item) export(scale_range) export(scihub_dl) export(set_PCRE) export(set_TRE) export(set_regexpr_style) export(show_in_excel) export(str_detect) export(str_ends) export(str_extract) export(str_starts) export(str_wrap) export(update_cache_item) export(use_perl) export(user_dir) export(with_cache) export(yread) export(yread_tsv) export(yulab_abort) export(yulab_inform) export(yulab_msg) export(yulab_warn) importFrom(cli,cli_h2) importFrom(digest,digest) importFrom(fs,path_join) importFrom(methods,is) importFrom(rappdirs,user_data_dir) importFrom(rlang,abort) importFrom(rlang,as_name) importFrom(rlang,check_installed) importFrom(rlang,enquo) importFrom(rlang,inform) importFrom(rlang,warn) importFrom(stats,setNames) importFrom(tools,package_dependencies) importFrom(utils,bibentry) importFrom(utils,capture.output) importFrom(utils,combn) importFrom(utils,download.file) importFrom(utils,getFromNamespace) importFrom(utils,modifyList) importFrom(utils,packageDescription) importFrom(utils,read.delim) importFrom(utils,read.table) yulab.utils/NEWS.md0000644000176200001440000001262715137764124013645 0ustar liggesusers# yulab.utils 0.2.4 + stabilize cache TTL unit test for r-devel checks (2026-02-02, Mon) # yulab.utils 0.2.3 + `download_yulab_file` (2025-12-15, Mon) + add unit test (2025-12-08, Mon) + Extend cache system with TTL, pruning, persistence and memoization (2025-12-08, Mon) - `update_cache_item(item, elements, ttl=)` sets per-entry expiration - `get_cache_element(item, elements, default=, prune_expired=)` supports default values and auto-pruning of expired entries - `with_cache(item, key, compute, ttl=)` computes and caches results (returns cached value on hit) - `prune_cache_item(item)` prunes expired entries; `rm_cache_entry(item, key)` removes a single entry - `cache_list_items()` and `cache_size()` list items and estimate total cache size - `cache_save(path)` and `cache_load(path)` serialize and restore the cache environment + update man (2025-12-08, Mon) + `load_OrgDb()` to load OrgDb object (2025-12-04, Thu) - move from 'GOSemSim' + `parse_ratio` to parse ratio string, e.g., "1/2" (2025-12-04, Thu) - move from 'DOSE' + set `check_pkg` as an alias of `check_packages` (2025-12-01, Mon) # yulab.utils 0.2.2 + add error handling functions (2025-12-01, Mon) - `yulab_abort()` - `yulab_warn()` - `yulab_inform()` + check input validity with detailed error messages (2025-12-01, Mon) - `check_input()` - `check_package()` - `check_file()` - `check_range()` - `check_directory()` + `quiet()` to suppress messages and output from `x` (2025-12-01, Mon) + add `subdir` parameter in `install_zip` and `install_zip_gh` (2025-09-09, Tue) + `where` return the full path of a command, "" if not found (2025-09-01, Mon) - internally call `which` for OSX and Linux and `where` for Windows # yulab.utils 0.2.1 + export `user_dir()` (2025-08-16, Sat) # yulab.utils 0.2.0 + bug fixed in `get_caller_package()` (2025-01-08, Wed) # yulab.utils 0.1.9 + `c2()` to concate two vectors into a 'chunked_array' object (2024-12-03, Tue) # yulab.utils 0.1.8 + add new citation (The Innovation 2024) (2024-11-07, Thu) + `pload()` now supports github package (2024-11-06, Wed) + bug fixed in `pkg_ref()` (2024-08-26, Mon) # yulab.utils 0.1.7 + `has_internet()` for testing internet connection (2024-08-26, Mon) + `pkg_ref()` to access textVersion of package reference (2024-08-21, Wed) + export `str_detect()` (20024-08-19, Mon) + `user_dir()` to setup user data dir (20024-08-17, Sat) + `which_os()` to return the system name + `has_bin()` to check whether a command is exist in the system # yulab.utils 0.1.6 + `mydownload()` for downloading online file (2024-08-17, Sat) - internally use 'httr2' and is 'https' friendly + update `bib_ggtree()` and `bib_knowledge()` with all previous related publications (2024-08-12, Mon) + remove memory caching and disable file cache by default in `yread()` and `yread_tsv()` (2024-07-27, Sat) + `bib_ggtree()` and `bib_knowledge()` (2024-07-27, Sat) # yulab.utils 0.1.5 + `yulab_msg()` for startup message of packages developed by YuLab (2024-07-26, Fri) # yulab.utils 0.1.4 + `str_extract()` to extract substring using a regular expression pattern (2024--01-25, Thu) # yulab.utils 0.1.3 + with cache ability (2023-12-27, Wed) - `initial_cache()` - `initial_cache_item()` - `get_cache()` - `get_cache_item()` - `get_cache_element()` - `rm_cache_item()` - `rm_cache()` # yulab.utils 0.1.2 + mv translate functions to the 'fanyi' package (2023-12-14, Thu) + tools to switch from PCRE or TRE in regular expression (2023-12-13, Wed) # yulab.utils 0.1.1 + use `normalizePath()` in `o()` to convert file paths to canonical form (2023-10-06, Fri, #4) + change the default parameter, `ref = "master"` to `ref = "HEAD"` in the `install_zip_gh()` function to use the default branch of the GitHub repo (2023-10-02, Mon) # yulab.utils 0.1.0 + `install_zip()` allows both binary and source zip files (2023-09-20, Wed) + `pload()` for loading package with the ability to install it if not available (2023-09-16, Sat) + `get_dependencies()` and `packageTitle()` (2023-09-11, Mon) + import 'fs' and 'digest' (2023-09-07, Thu) # yulab.utils 0.0.9 + `ls2df()` convert list of vector to a data.frame (2023-09-01, Fri) # yulab.utils 0.0.8 + `mat2list()` and `combinations()` (2023-08-22, Tue) + remove default 'params' setting in `yread_tsv()` (2023-08-15, Tue) # yulab.utils 0.0.7 + update `check_pkg()` to call `rlang::check_installed()` with reason set automatically (2023-08-03, Thu) + `yread()` and `yread_tsv()` that read file with caching (2023-08-02, Wed) + `rbindlist()` to rbind a list (2023-08-01, Tue) + `exec()` to run system command (2023-06-19, Mon) + `scale_range()` to normalize data by range (2023-06-18, Sun) # yulab.utils 0.0.6 + `mat2df()` to convert matrix to a tidy data frame (2022-12-20, Tue) + `str_starts()` and `str_ends()` (2022-07-29, Fri) # yulab.utils 0.0.5 + `get_fun_from_pkg()` outputs friendly message if the pkg is not installed (2022-06-08, Wed) + `show_in_excel()`, `CRANpkg()`, `Biocpkg()`, `Githubpkg()`, `mypkg()` (2021-10-13, Wed) # yulab.utils 0.0.4 + `str_wrap()` (2021-10-09, Sat) # yulab.utils 0.0.3 + `read.cb()` (2021-08-17) # yulab.utils 0.0.2 + `o()`, `install_zip()`, `get_fun_from_pkg()` # yulab.utils 0.0.1 + `is.installed()`, `scihub_dl()`, `sudo_install()` yulab.utils/inst/0000755000176200001440000000000014660651434013513 5ustar liggesusersyulab.utils/inst/prototype/0000755000176200001440000000000014723463462015562 5ustar liggesusersyulab.utils/inst/prototype/sra.r0000644000176200001440000000036414712366206016531 0ustar liggesusersget_runinfo <- function(sra_id) { x <- rentrez::entrez_fetch(db='sra', rettype='runinfo', id = sra_id) read.csv(textConnection(x)) } id <- "SRX5137765" d <- get_runinfo(id) head(d,2) sprintf("fastq-dump %s", d$Run[1:3]) yulab.utils/inst/prototype/GEO.r0000644000176200001440000000142014712361503016343 0ustar liggesusers get_gse <- function(gseID) { gsecat <- sub("\\d{3}$", "nnn", gseID) gsesoft <- sprintf("%s_family.soft.gz", gseID) url <- sprintf("https://ftp.ncbi.nlm.nih.gov/geo/series/%s/%s/soft/%s", gsecat, gseID, gsesoft) yulab.utils:::mydownload(url, destfile = gsesoft) GEOquery::getGEO(filename = gsesoft) } get_gsm <- function(gse, item = "supplementary_file_1") { lapply(GEOquery::GSMList(gse), function(x) x@header[item]) } download_gsm <- function(gsm) { for (x in gsm) { destfile <- sub(".*/([^/]+)$", "\\1", x) yulab.utils:::mydownload(x, destfile = destfile) } } gseID <- "GSE123904" gse <- get_gse(gseID) gsm <- get_gsm(gse) get_gsm(gse, 'extract_protocol_ch1') |> head(2) download_gsm(gsm) yulab.utils/man/0000755000176200001440000000000015137764151013312 5ustar liggesusersyulab.utils/man/check_packages.Rd0000644000176200001440000000145515117727205016516 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/error-utils.r \name{check_packages} \alias{check_packages} \alias{check_pkg} \title{Check if required packages are installed with informative errors} \usage{ check_packages(packages, reason = "for this functionality") check_pkg(packages, reason = "for this functionality") } \arguments{ \item{packages}{Character vector of package names} \item{reason}{Reason why these packages are needed} } \value{ Invisible TRUE if all packages are available, throws error otherwise } \description{ Enhanced package checking with better error messages and validation } \seealso{ Other validate-utils: \code{\link{check_directory}()}, \code{\link{check_file}()}, \code{\link{check_input}()}, \code{\link{check_range}()} } \concept{validate-utils} yulab.utils/man/regexpr-style.Rd0000644000176200001440000000211015117727206016403 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/regexpr.R \name{set_PCRE} \alias{set_PCRE} \alias{set_TRE} \alias{use_perl} \alias{set_regexpr_style} \alias{auto_set_regexpr_style} \title{Switch regular expression style (PCRE vs TRE)} \usage{ set_PCRE() set_TRE() use_perl() set_regexpr_style(style) auto_set_regexpr_style() } \arguments{ \item{style}{one of 'PCRE' or 'TRE'} } \value{ Logical indicating whether to use \code{perl} } \description{ \itemize{ \item \code{set_regexpr_style()} selects the style explicitly. \item \code{auto_set_regexpr_style()} chooses based on OS (TRE on Windows; PCRE elsewhere). \item \code{set_PCRE()} and \code{set_TRE()} force the style. } } \details{ These functions do not change the behavior of \code{gsub()}/\code{regexpr()} directly. They set a global option that you can read via \code{use_perl()} and pass to \code{gsub()}/\code{regexpr()}. } \references{ https://stackoverflow.com/questions/47240375/regular-expressions-in-base-r-perl-true-vs-the-default-pcre-vs-tre } \author{ Guangchuang Yu } \concept{regex-utils} yulab.utils/man/install_zip_gh.Rd0000644000176200001440000000136715057724712016616 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/install_zip.R \name{install_zip_gh} \alias{install_zip_gh} \title{install_zip_gh} \usage{ install_zip_gh( repo, ref = "HEAD", subdir = NULL, args = "--no-build-vignettes" ) } \arguments{ \item{repo}{github repo} \item{ref}{github branch, default is HEAD, which means the default branch of the GitHub repo} \item{subdir}{sub directory that contains R package files, default is NULL} \item{args}{argument to build package} } \value{ No return value, called for installing github package } \description{ install github package } \details{ it download the zip file first and use \code{install_zip} to install it } \author{ Guangchuang Yu } yulab.utils/man/yulab_msg.Rd0000644000176200001440000000055415115332234015554 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/yulab-msg.R \name{yulab_msg} \alias{yulab_msg} \title{yulab_msg} \usage{ yulab_msg(pkgname = NULL, n = 1) } \arguments{ \item{pkgname}{Package name} \item{n}{Number of citation messages} } \value{ Package message } \description{ Messages for YuLab packages } \author{ Guangchuang Yu } yulab.utils/man/str_wrap.Rd0000644000176200001440000000110515115332234015424 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/str-utils.R \name{str_wrap} \alias{str_wrap} \title{str_wrap} \usage{ str_wrap(string, width = getOption("width")) } \arguments{ \item{string}{Input string} \item{width}{Maximum characters before wrapping} } \value{ Updated strings with \code{"\\n"} inserted } \description{ Wrap long strings to multiple lines } \seealso{ Other str-utils: \code{\link{str_detect}()}, \code{\link{str_extract}()}, \code{\link{str_starts}()} } \author{ Guangchuang Yu } \concept{str-utils} yulab.utils/man/yulab-cache.Rd0000644000176200001440000000354015117727205015755 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cache.R \name{initial_cache} \alias{initial_cache} \alias{get_cache} \alias{rm_cache} \alias{initial_cache_item} \alias{get_cache_item} \alias{rm_cache_item} \alias{update_cache_item} \alias{get_cache_element} \alias{prune_cache_item} \alias{cache_list_items} \alias{cache_size} \alias{cache_save} \alias{cache_load} \alias{with_cache} \title{Cache intermediate data} \usage{ initial_cache() get_cache() rm_cache() initial_cache_item(item) get_cache_item(item) rm_cache_item(item) update_cache_item(item, elements, ttl = NULL) get_cache_element(item, elements, default = NULL, prune_expired = TRUE) prune_cache_item(item) cache_list_items() cache_size() cache_save(path) cache_load(path) with_cache(item, key, compute, ttl = NULL) } \arguments{ \item{item}{Cache item name} \item{elements}{Elements to cache} \item{ttl}{Time-to-live in seconds} \item{default}{Default value if cache element is missing} \item{prune_expired}{Logical, whether to prune expired items} \item{path}{File path to save or load cache} \item{key}{Element key} \item{compute}{Function to compute value when missing} } \value{ Cache environment, item, or selected elements } \description{ Utilities to cache intermediate data: initialize items, update items, remove items, and retrieve elements. } \examples{ \dontrun{ slow_fib <- function(x) { if (x < 2) return(1) slow_fib(x-2) + slow_fib(x-1) } fast_fib <- function(x) { if (x < 2) return(1) res <- get_cache_element('fibonacci', as.character(x)) if (!is.null(res)) { return(res) } res <- fast_fib(x-2) + fast_fib(x-1) e <- list() e[[as.character(x)]] <- res update_cache_item('fibonacci', e) return(res) } system.time(slow_fib(30)) system.time(fast_fib(30)) } } \concept{cache-utils} yulab.utils/man/str-detect.Rd0000644000176200001440000000106315115332234015644 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/str-utils.R \name{str_detect} \alias{str_detect} \title{str_detect} \usage{ str_detect(string, pattern, negate = FALSE) } \arguments{ \item{string}{Input string} \item{pattern}{Pattern to look for} \item{negate}{If \code{TRUE}, invert the result} } \value{ Logical vector } \description{ Detect presence/absence of a match } \seealso{ Other str-utils: \code{\link{str_extract}()}, \code{\link{str_starts}()}, \code{\link{str_wrap}()} } \author{ Guangchuang Yu } \concept{str-utils} yulab.utils/man/scihub-dl.Rd0000644000176200001440000000072614404503310015440 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scihub-dl.R \name{scihub_dl} \alias{scihub_dl} \title{download publication via scihub} \usage{ scihub_dl(doi, scihub = "sci-hub.tw", download = TRUE) } \arguments{ \item{doi}{doi} \item{scihub}{scihub website} \item{download}{whether download the pdf file} } \value{ pdf url } \description{ using scihub to download publication using doi } \author{ Guangchuang Yu } yulab.utils/man/read.cb.Rd0000644000176200001440000000106215115332233015062 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/file.R \name{read.cb} \alias{read.cb} \title{read.cb} \usage{ read.cb(reader = read.table, ...) } \arguments{ \item{reader}{function to read the clipboard} \item{...}{parameters for the reader} } \value{ clipboard content, output type depends on the output of the reader } \description{ read clipboard } \seealso{ Other io-utils: \code{\link{o}()}, \code{\link{show_in_excel}()}, \code{\link{yread_tsv}()} } \author{ Guangchuang Yu } \concept{io-utils} yulab.utils/man/check_directory.Rd0000644000176200001440000000157315117727205016745 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/error-utils.r \name{check_directory} \alias{check_directory} \title{Check if directory exists and is accessible} \usage{ check_directory( path, create_if_missing = FALSE, check_write_permission = TRUE, arg_name = "directory" ) } \arguments{ \item{path}{Directory path} \item{create_if_missing}{Whether to create directory if it doesn't exist} \item{check_write_permission}{Whether to verify write permissions} \item{arg_name}{Name of the argument for error messages} } \value{ Invisible TRUE if valid, throws error otherwise } \description{ Validates directory existence and accessibility with options to create if missing } \seealso{ Other validate-utils: \code{\link{check_file}()}, \code{\link{check_input}()}, \code{\link{check_packages}()}, \code{\link{check_range}()} } \concept{validate-utils} yulab.utils/man/install_zip.Rd0000644000176200001440000000110215057724712016123 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/install_zip.R \name{install_zip} \alias{install_zip} \title{install_zip} \usage{ install_zip(file, subdir = NULL, args = "--no-build-vignettes") } \arguments{ \item{file}{zip file} \item{subdir}{sub directory that contains R package files, default is NULL} \item{args}{argument to build package} } \value{ No return value, called for install R package from zip file of source codes } \description{ install R package from zip file of source codes } \author{ Guangchuang Yu } yulab.utils/man/o.Rd0000644000176200001440000000111315115332233014017 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/file.R \name{o} \alias{o} \title{o} \usage{ o(file = ".") } \arguments{ \item{file}{to be open; open working directory by default} } \value{ No return value, called for opening specific directory or file } \description{ open selected directory or file } \examples{ \dontrun{ ## to open current working directory o() } } \seealso{ Other io-utils: \code{\link{read.cb}()}, \code{\link{show_in_excel}()}, \code{\link{yread_tsv}()} } \author{ Guangchuang Yu } \concept{io-utils} yulab.utils/man/check_file.Rd0000644000176200001440000000136015117727205015652 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/error-utils.r \name{check_file} \alias{check_file} \title{Handle file operations with proper error messages} \usage{ check_file(path, operation = "read", must_exist = TRUE) } \arguments{ \item{path}{File path} \item{operation}{Operation being performed (read, write, etc.)} \item{must_exist}{Whether the file must exist} } \value{ Invisible TRUE if operation can proceed, throws error otherwise } \description{ Enhanced file validation with comprehensive checks and better error messages } \seealso{ Other validate-utils: \code{\link{check_directory}()}, \code{\link{check_input}()}, \code{\link{check_packages}()}, \code{\link{check_range}()} } \concept{validate-utils} yulab.utils/man/combinations.Rd0000644000176200001440000000046514471060707016267 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/combinations.R \name{combinations} \alias{combinations} \title{combinations} \usage{ combinations(n) } \arguments{ \item{n}{number of sets} } \value{ a list of all combinations } \description{ all possible combinations of n sets } yulab.utils/man/yread.Rd0000644000176200001440000000201715117727205014702 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/file.R \name{yread_tsv} \alias{yread_tsv} \alias{yread} \title{yread} \usage{ yread_tsv( file, reader = utils::read.delim, params = list(), cache_dir = tempdir() ) yread(file, reader = readLines, params = list(), cache_dir = NULL) } \arguments{ \item{file}{a file or url} \item{reader}{a function to read the 'file_url'} \item{params}{a list of parameters that passed to the 'reader'} \item{cache_dir}{a folder to store cache files. If set to NULL will disable cache.} } \value{ the output of using the 'reader' to read the 'file_url' with parameters specified by the 'params' } \description{ read file with caching } \details{ This function read a file (local or url) and cache the content. } \seealso{ Other io-utils: \code{\link{o}()}, \code{\link{read.cb}()}, \code{\link{show_in_excel}()} Other io-utils: \code{\link{o}()}, \code{\link{read.cb}()}, \code{\link{show_in_excel}()} } \author{ Yonghe Xia and Guangchuang Yu } \concept{io-utils} yulab.utils/man/download_yulab_file.Rd0000644000176200001440000000112015117720071017564 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/download.R \name{download_yulab_file} \alias{download_yulab_file} \title{Process YuLab File Download} \usage{ download_yulab_file(destfile, urls, gzfile = FALSE, appname = NULL) } \arguments{ \item{destfile}{character. Local file path.} \item{urls}{character vector. Base URLs for download. Remote is is \code{urls/basename(destfile)}} \item{gzfile}{logical. Whether the remote file is gzipped.} \item{appname}{character. R package name.} } \description{ Process YuLab File Download } \author{ Guangchuang Yu } yulab.utils/man/mat2df.Rd0000644000176200001440000000110014474263201014737 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/matrix-utils.R \name{mat2df} \alias{mat2df} \title{mat2df} \usage{ mat2df(x) } \arguments{ \item{x}{the input matrix} } \value{ a data.frame in long format with the 'value' column stores the original values and 'row' and 'col' columns stored in row and column index as in x } \description{ convert a matrix to a tidy data frame (from wide to long format as described in the tidyverse concept) } \examples{ x <- matrix(1:15, nrow = 3) mat2df(x) } \author{ Guangchuang Yu } yulab.utils/man/packageTitle.Rd0000644000176200001440000000114115117727206016171 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pkg-utils.R \name{packageTitle} \alias{packageTitle} \title{packageTitle} \usage{ packageTitle(pkg, repo = "CRAN") } \arguments{ \item{pkg}{package name} \item{repo}{'CRAN' and/or 'BioC'} } \value{ reverse dependencies } \description{ Extract package title } \seealso{ Other pkg-utils: \code{\link{CRANpkg}()}, \code{\link{Githubpkg}()}, \code{\link{get_dependencies}()}, \code{\link{get_fun_from_pkg}()}, \code{\link{is.installed}()}, \code{\link{mypkg}()}, \code{\link{pload}()} } \author{ Guangchuang Yu } \concept{pkg-utils} yulab.utils/man/quiet.Rd0000644000176200001440000000042015113172734014716 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quiet.r \name{quiet} \alias{quiet} \title{quiet} \usage{ quiet(x) } \arguments{ \item{x}{some code} } \value{ the result of \code{x} } \description{ Suppress messages and output from \code{x} } yulab.utils/man/has_internet.Rd0000644000176200001440000000072715115332233016256 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/os.R \name{has_internet} \alias{has_internet} \title{has_internet} \usage{ has_internet(site = "https://www.baidu.com/") } \arguments{ \item{site}{URL to test connection} } \value{ logical value } \description{ test for internect connection via reading lines from a URL } \seealso{ Other os-utils: \code{\link{exec}()}, \code{\link{user_dir}()} } \author{ Guangchuang Yu } \concept{os-utils} yulab.utils/man/c2.Rd0000644000176200001440000000061714723464027014110 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/concat.r \name{c2} \alias{c2} \title{c2} \usage{ c2(x, y) } \arguments{ \item{x}{a vector or chunked_array object} \item{y}{a vector or chunked_array object} } \value{ chunked_array object } \description{ chunked array } \details{ concate two vector/chunked_array into a chunked_array object } \author{ Guangchuang Yu } yulab.utils/man/load_OrgDb.Rd0000644000176200001440000000051615114322503015561 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/load-orgdb.r \name{load_OrgDb} \alias{load_OrgDb} \title{load_OrgDb} \usage{ load_OrgDb(OrgDb) } \arguments{ \item{OrgDb}{OrgDb object or OrgDb name} } \value{ OrgDb object } \description{ load OrgDb } \author{ Guangchuang Yu \url{https://yulab-smu.top} } yulab.utils/man/check_range.Rd0000644000176200001440000000151715117727205016033 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/error-utils.r \name{check_range} \alias{check_range} \title{Check if value is within specified range} \usage{ check_range(x, min = NULL, max = NULL, inclusive = TRUE, arg_name = "value") } \arguments{ \item{x}{Numeric value to check} \item{min}{Minimum allowed value (optional)} \item{max}{Maximum allowed value (optional)} \item{inclusive}{Whether bounds are inclusive (default: TRUE)} \item{arg_name}{Name of the argument for error messages} } \value{ Invisible TRUE if valid, throws error otherwise } \description{ Validates that a numeric value falls within the specified range } \seealso{ Other validate-utils: \code{\link{check_directory}()}, \code{\link{check_file}()}, \code{\link{check_input}()}, \code{\link{check_packages}()} } \concept{validate-utils} yulab.utils/man/pload.Rd0000644000176200001440000000154215117727205014677 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pkg-utils.R \name{pload} \alias{pload} \title{pload} \usage{ pload(package, action = "auto") } \arguments{ \item{package}{package name} \item{action}{Installation function; \code{"auto"} tries \code{BiocManager::install()} if available} } \value{ the selected package loaded to the R session } \description{ Load a package } \details{ Uses \code{library()} to load \code{package}. If not installed, attempts installation via \code{rlang::check_installed()} (optionally using \code{BiocManager::install()}). } \seealso{ Other pkg-utils: \code{\link{CRANpkg}()}, \code{\link{Githubpkg}()}, \code{\link{get_dependencies}()}, \code{\link{get_fun_from_pkg}()}, \code{\link{is.installed}()}, \code{\link{mypkg}()}, \code{\link{packageTitle}()} } \author{ Guangchuang Yu } \concept{pkg-utils} yulab.utils/man/cran-bioc-pkg.Rd0000644000176200001440000000120215117727206016206 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pkg-utils.R \name{CRANpkg} \alias{CRANpkg} \alias{Biocpkg} \title{Markdown link to CRAN/Bioconductor} \usage{ CRANpkg(pkg) Biocpkg(pkg) } \arguments{ \item{pkg}{package name} } \value{ md text string } \description{ Markdown link to CRAN/Bioconductor } \seealso{ Other pkg-utils: \code{\link{Githubpkg}()}, \code{\link{get_dependencies}()}, \code{\link{get_fun_from_pkg}()}, \code{\link{is.installed}()}, \code{\link{mypkg}()}, \code{\link{packageTitle}()}, \code{\link{pload}()} } \author{ Guangchuang Yu } \concept{pkg-utils} yulab.utils/man/show_in_excel.Rd0000644000176200001440000000075715115332233016424 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/file.R \name{show_in_excel} \alias{show_in_excel} \title{show_in_excel} \usage{ show_in_excel(.data) } \arguments{ \item{.data}{a data frame to be open} } \value{ original .data } \description{ Open data frame in Excel. It can be used in pipe. } \seealso{ Other io-utils: \code{\link{o}()}, \code{\link{read.cb}()}, \code{\link{yread_tsv}()} } \author{ Guangchuang Yu } \concept{io-utils} yulab.utils/man/exec.Rd0000644000176200001440000000065615115332233014520 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/os.R \name{exec} \alias{exec} \title{exec} \usage{ exec(command) } \arguments{ \item{command}{system command to run} } \value{ An \code{exec} instance that stores system command outputs } \description{ run system command } \seealso{ Other os-utils: \code{\link{has_internet}()}, \code{\link{user_dir}()} } \author{ Guangchuang Yu } \concept{os-utils} yulab.utils/man/rbindlist.Rd0000644000176200001440000000050015115332233015552 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/list.R \name{rbindlist} \alias{rbindlist} \title{rbindlist} \usage{ rbindlist(x) } \arguments{ \item{x}{List with similar elements that can be row-bound} } \value{ \code{data.frame} } \description{ Row-bind a list } \author{ Guangchuang Yu } yulab.utils/man/parse_ratio.Rd0000644000176200001440000000055715115332233016104 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/parse_ratio.R \name{parse_ratio} \alias{parse_ratio} \title{parse_ratio} \usage{ parse_ratio(ratio) } \arguments{ \item{ratio}{Character vector of ratios} } \value{ Numeric vector } \description{ Parse character ratio to double, e.g., \code{1/5} → \code{0.2} } \author{ Guangchuang Yu } yulab.utils/man/get_dependencies.Rd0000644000176200001440000000117315117727205017065 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pkg-utils.R \name{get_dependencies} \alias{get_dependencies} \title{get_dependencies} \usage{ get_dependencies(pkg, repo = c("CRAN", "BioC")) } \arguments{ \item{pkg}{package name} \item{repo}{'CRAN' and/or 'BioC'} } \value{ reverse dependencies } \description{ Get reverse dependencies } \seealso{ Other pkg-utils: \code{\link{CRANpkg}()}, \code{\link{Githubpkg}()}, \code{\link{get_fun_from_pkg}()}, \code{\link{is.installed}()}, \code{\link{mypkg}()}, \code{\link{packageTitle}()}, \code{\link{pload}()} } \author{ Guangchuang Yu } \concept{pkg-utils} yulab.utils/man/yulab-message.Rd0000644000176200001440000000124215117727205016333 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/error-utils.r \name{yulab_abort} \alias{yulab_abort} \alias{yulab_warn} \alias{yulab_inform} \title{Standardized error handling} \usage{ yulab_abort(message, class = "yulab_error", ...) yulab_warn(message, class = "yulab_warning", ...) yulab_inform(message, class = "yulab_info", ...) } \arguments{ \item{message}{Message string} \item{class}{Custom class for categorization} \item{...}{Additional context} } \value{ No return value } \description{ Provides \code{rlang}-based wrappers for messaging: \code{yulab_abort()}, \code{yulab_warn()}, and \code{yulab_inform()}. } \concept{messages} yulab.utils/man/get_fun_from_pkg.Rd0000644000176200001440000000123415117727206017112 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pkg-utils.R \name{get_fun_from_pkg} \alias{get_fun_from_pkg} \title{get_fun_from_pkg} \usage{ get_fun_from_pkg(pkg, fun) } \arguments{ \item{pkg}{package} \item{fun}{function} } \value{ function } \description{ load function from package } \examples{ get_fun_from_pkg('utils', 'zip') } \seealso{ Other pkg-utils: \code{\link{CRANpkg}()}, \code{\link{Githubpkg}()}, \code{\link{get_dependencies}()}, \code{\link{is.installed}()}, \code{\link{mypkg}()}, \code{\link{packageTitle}()}, \code{\link{pload}()} } \author{ Guangchuang Yu } \concept{pkg-utils} yulab.utils/man/user_dir.Rd0000644000176200001440000000111715115332233015401 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/os.R \name{user_dir} \alias{user_dir} \title{user_dir} \usage{ user_dir(appname = NULL, appauthor = NULL, ...) } \arguments{ \item{appname}{App name} \item{appauthor}{App author} \item{...}{additional parameters} } \value{ a directory (created if not exists) } \description{ get the user dir to save app caches, logs and data (a wrapper function of \code{rappdirs::user_cache_dir()}) } \seealso{ Other os-utils: \code{\link{exec}()}, \code{\link{has_internet}()} } \author{ Guangchuang Yu } \concept{os-utils} yulab.utils/man/str-starts-ends.Rd0000644000176200001440000000125315115332234016644 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/str-utils.R \name{str_starts} \alias{str_starts} \alias{str_ends} \title{str_starts} \usage{ str_starts(string, pattern, negate = FALSE) str_ends(string, pattern, negate = FALSE) } \arguments{ \item{string}{Input string} \item{pattern}{Pattern to match} \item{negate}{If \code{TRUE}, return non-matching elements} } \value{ a logical vector } \description{ Detect patterns at the beginning or end of strings } \seealso{ Other str-utils: \code{\link{str_detect}()}, \code{\link{str_extract}()}, \code{\link{str_wrap}()} } \author{ Guangchuang Yu } \concept{str-utils} yulab.utils/man/yulab.utils-package.Rd0000644000176200001440000000121214660773203017437 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/yulab-utils-package.R \docType{package} \name{yulab.utils-package} \alias{yulab.utils} \alias{yulab.utils-package} \title{yulab.utils: Supporting Functions for Packages Maintained by 'YuLab-SMU'} \description{ Miscellaneous functions commonly used by 'YuLab-SMU'. } \seealso{ Useful links: \itemize{ \item \url{https://yulab-smu.top/} \item Report bugs at \url{https://github.com/YuLab-SMU/yulab.utils/issues} } } \author{ \strong{Maintainer}: Guangchuang Yu \email{guangchuangyu@gmail.com} (\href{https://orcid.org/0000-0002-6485-8781}{ORCID}) } \keyword{internal} yulab.utils/man/mypkg.Rd0000644000176200001440000000113015117727206014721 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pkg-utils.R \name{mypkg} \alias{mypkg} \title{mypkg} \usage{ mypkg(pkg, url) } \arguments{ \item{pkg}{package name} \item{url}{package url} } \value{ md text string } \description{ Markdown link to a package } \seealso{ Other pkg-utils: \code{\link{CRANpkg}()}, \code{\link{Githubpkg}()}, \code{\link{get_dependencies}()}, \code{\link{get_fun_from_pkg}()}, \code{\link{is.installed}()}, \code{\link{packageTitle}()}, \code{\link{pload}()} } \author{ Guangchuang Yu } \concept{pkg-utils} yulab.utils/man/check_input.Rd0000644000176200001440000000170215117727205016072 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/error-utils.r \name{check_input} \alias{check_input} \title{Validate input with type/length constraints} \usage{ check_input( x, type = NULL, length = NULL, min_length = NULL, max_length = NULL, allow_null = FALSE, arg_name = "input" ) } \arguments{ \item{x}{Object to check} \item{type}{Expected type (e.g., \code{"numeric"}, \code{"character"}, or class name)} \item{length}{Expected length} \item{min_length}{Minimum length} \item{max_length}{Maximum length} \item{allow_null}{Whether \code{NULL} is allowed} \item{arg_name}{Argument name for messages} } \value{ Invisible \code{TRUE} on success } \description{ Enhanced input validation supporting base types and class checks. } \seealso{ Other validate-utils: \code{\link{check_directory}()}, \code{\link{check_file}()}, \code{\link{check_packages}()}, \code{\link{check_range}()} } \concept{validate-utils} yulab.utils/man/scale_range.Rd0000644000176200001440000000046514443622064016044 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scale.R \name{scale_range} \alias{scale_range} \title{scale-range} \usage{ scale_range(data) } \arguments{ \item{data}{the input data.} } \value{ normalized data } \description{ normalized data by range } \author{ Guangchuang Yu } yulab.utils/man/str-extract.Rd0000644000176200001440000000077215115332234016054 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/str-utils.R \name{str_extract} \alias{str_extract} \title{str_extract} \usage{ str_extract(string, pattern) } \arguments{ \item{string}{Input string} \item{pattern}{Regular expression to extract} } \value{ Substring } \description{ Extract a substring using a pattern } \seealso{ Other str-utils: \code{\link{str_detect}()}, \code{\link{str_starts}()}, \code{\link{str_wrap}()} } \author{ Guangchuang Yu } \concept{str-utils} yulab.utils/man/ls2df.Rd0000644000176200001440000000053115115332233014576 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/list.R \name{ls2df} \alias{ls2df} \title{Convert a list of vectors (e.g., gene IDs) to \code{data.frame}} \usage{ ls2df(inputList) } \arguments{ \item{inputList}{List of vectors} } \value{ \code{data.frame} } \description{ Convert a list of vectors to a data.frame } yulab.utils/man/mat2list.Rd0000644000176200001440000000055414474263201015335 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/matrix-utils.R \name{mat2list} \alias{mat2list} \title{mat2list} \usage{ mat2list(x) } \arguments{ \item{x}{the input matrix} } \value{ a list that contains matrix columns as its elements } \description{ convert a matrix to a list } \examples{ x <- matrix(1:15, nrow = 3) mat2list(x) } yulab.utils/man/github-pkg.Rd0000644000176200001440000000112015117727206015632 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pkg-utils.R \name{Githubpkg} \alias{Githubpkg} \title{Markdown link to GitHub} \usage{ Githubpkg(user, pkg) } \arguments{ \item{user}{github user} \item{pkg}{package name} } \value{ md text string } \description{ Markdown link to GitHub } \seealso{ Other pkg-utils: \code{\link{CRANpkg}()}, \code{\link{get_dependencies}()}, \code{\link{get_fun_from_pkg}()}, \code{\link{is.installed}()}, \code{\link{mypkg}()}, \code{\link{packageTitle}()}, \code{\link{pload}()} } \author{ Guangchuang Yu } \concept{pkg-utils} yulab.utils/man/is.installed.Rd0000644000176200001440000000122615117727206016171 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pkg-utils.R \name{is.installed} \alias{is.installed} \title{is.installed} \usage{ is.installed(packages) } \arguments{ \item{packages}{package names} } \value{ logical vector } \description{ Check whether packages are installed } \examples{ is.installed(c("dplyr", "ggplot2")) } \seealso{ Other pkg-utils: \code{\link{CRANpkg}()}, \code{\link{Githubpkg}()}, \code{\link{get_dependencies}()}, \code{\link{get_fun_from_pkg}()}, \code{\link{mypkg}()}, \code{\link{packageTitle}()}, \code{\link{pload}()} } \author{ Guangchuang Yu } \concept{pkg-utils} yulab.utils/DESCRIPTION0000644000176200001440000000162715140042152014233 0ustar liggesusersPackage: yulab.utils Title: Supporting Functions for Packages Maintained by 'YuLab-SMU' Version: 0.2.4 Authors@R: c(person("Guangchuang", "Yu", email = "guangchuangyu@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-6485-8781"))) Description: Miscellaneous functions commonly used by 'YuLab-SMU'. Depends: R (>= 4.2.0) Imports: cli, digest, fs, methods, rappdirs, rlang, tools, utils Suggests: httr2, jsonlite, openssl, R.utils, testthat (>= 3.0.0) ByteCompile: true License: Artistic-2.0 URL: https://yulab-smu.top/ BugReports: https://github.com/YuLab-SMU/yulab.utils/issues Encoding: UTF-8 RoxygenNote: 7.3.3 Config/testthat/edition: 3 NeedsCompilation: no Packaged: 2026-02-01 23:57:30 UTC; HUAWEI Author: Guangchuang Yu [aut, cre] (ORCID: ) Maintainer: Guangchuang Yu Repository: CRAN Date/Publication: 2026-02-02 06:30:02 UTC