From 1ce871802647dbd34fa6f8bc76c8dafc5855d614 Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 18:30:13 -0400 Subject: [PATCH 01/13] build: use renv to manage dependencies Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- .Rprofile | 7 + renv.lock | 941 ++++++++++++++++++++++++++++++++++ renv/.gitignore | 7 + renv/activate.R | 1220 ++++++++++++++++++++++++++++++++++++++++++++ renv/settings.json | 19 + 5 files changed, 2194 insertions(+) create mode 100644 .Rprofile create mode 100644 renv.lock create mode 100644 renv/.gitignore create mode 100644 renv/activate.R create mode 100644 renv/settings.json diff --git a/.Rprofile b/.Rprofile new file mode 100644 index 0000000..d645955 --- /dev/null +++ b/.Rprofile @@ -0,0 +1,7 @@ +rprofile <- file.path(Sys.getenv("HOME"), ".Rprofile") + +if (file.exists(rprofile) & interactive()) { + source(rprofile) +} + +source("renv/activate.R") diff --git a/renv.lock b/renv.lock new file mode 100644 index 0000000..47d2b14 --- /dev/null +++ b/renv.lock @@ -0,0 +1,941 @@ +{ + "R": { + "Version": "4.4.1", + "Repositories": [ + { + "Name": "BioCsoft", + "URL": "https://bioconductor.org/packages/3.19/bioc" + }, + { + "Name": "BioCann", + "URL": "https://bioconductor.org/packages/3.19/data/annotation" + }, + { + "Name": "BioCexp", + "URL": "https://bioconductor.org/packages/3.19/data/experiment" + }, + { + "Name": "BioCworkflows", + "URL": "https://bioconductor.org/packages/3.19/workflows" + }, + { + "Name": "BioCbooks", + "URL": "https://bioconductor.org/packages/3.19/books" + }, + { + "Name": "CRAN", + "URL": "https://cloud.r-project.org" + }, + { + "Name": "CDRL", + "URL": "https://cogdisreslab.r-universe.dev" + }, + { + "Name": "ASIMAMI", + "URL": "https://alisajid.r-universe.dev" + } + ] + }, + "Bioconductor": { + "Version": "3.19" + }, + "Packages": { + "AnnotationDbi": { + "Package": "AnnotationDbi", + "Version": "1.66.0", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "Biobase", + "BiocGenerics", + "DBI", + "IRanges", + "KEGGREST", + "R", + "RSQLite", + "S4Vectors", + "methods", + "stats", + "stats4" + ], + "Hash": "b7df9c597fb5533fc8248d73b8c703ac" + }, + "BH": { + "Package": "BH", + "Version": "1.84.0-0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "a8235afbcd6316e6e91433ea47661013" + }, + "Biobase": { + "Package": "Biobase", + "Version": "2.64.0", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "BiocGenerics", + "R", + "methods", + "utils" + ], + "Hash": "9bc4cabd3bfda461409172213d932813" + }, + "BiocGenerics": { + "Package": "BiocGenerics", + "Version": "0.50.0", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "R", + "graphics", + "methods", + "stats", + "utils" + ], + "Hash": "ef32d07aafdd12f24c5827374ae3590d" + }, + "BiocManager": { + "Package": "BiocManager", + "Version": "1.30.25", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "utils" + ], + "Hash": "3aec5928ca10897d7a0a1205aae64627" + }, + "BiocVersion": { + "Package": "BiocVersion", + "Version": "3.19.1", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "R" + ], + "Hash": "b892e27fc9659a4c8f8787d34c37b8b2" + }, + "Biostrings": { + "Package": "Biostrings", + "Version": "2.72.1", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "BiocGenerics", + "GenomeInfoDb", + "IRanges", + "R", + "S4Vectors", + "XVector", + "crayon", + "grDevices", + "methods", + "stats", + "utils" + ], + "Hash": "886ff0ed958d6f839ed2e0d01f6853b3" + }, + "DBI": { + "Package": "DBI", + "Version": "1.2.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "methods" + ], + "Hash": "065ae649b05f1ff66bb0c793107508f5" + }, + "GO.db": { + "Package": "GO.db", + "Version": "3.19.1", + "Source": "Bioconductor", + "Requirements": [ + "AnnotationDbi", + "R", + "methods" + ], + "Hash": "46bfc38370acea3503c223347915e43b" + }, + "GenomeInfoDb": { + "Package": "GenomeInfoDb", + "Version": "1.40.1", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "BiocGenerics", + "GenomeInfoDbData", + "IRanges", + "R", + "S4Vectors", + "UCSC.utils", + "methods", + "stats", + "stats4", + "utils" + ], + "Hash": "171e9becd9bb948b9e64eb3759208c94" + }, + "GenomeInfoDbData": { + "Package": "GenomeInfoDbData", + "Version": "1.2.12", + "Source": "Bioconductor", + "Requirements": [ + "R" + ], + "Hash": "c3c792a7b7f2677be56e8632c5b7543d" + }, + "IRanges": { + "Package": "IRanges", + "Version": "2.38.1", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "BiocGenerics", + "R", + "S4Vectors", + "methods", + "stats", + "stats4", + "utils" + ], + "Hash": "066f3c5d6b022ed62c91ce49e4d8f619" + }, + "KEGGREST": { + "Package": "KEGGREST", + "Version": "1.44.1", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "Biostrings", + "R", + "httr", + "methods", + "png" + ], + "Hash": "017f19c09477c0473073518db9076ac1" + }, + "Matrix": { + "Package": "Matrix", + "Version": "1.7-0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "grDevices", + "graphics", + "grid", + "lattice", + "methods", + "stats", + "utils" + ], + "Hash": "1920b2f11133b12350024297d8a4ff4a" + }, + "R6": { + "Package": "R6", + "Version": "2.5.1", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R" + ], + "Hash": "470851b6d5d0ac559e9d01bb352b4021" + }, + "RSQLite": { + "Package": "RSQLite", + "Version": "2.3.7", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "DBI", + "R", + "bit64", + "blob", + "cpp11", + "memoise", + "methods", + "pkgconfig", + "plogr", + "rlang" + ], + "Hash": "46b45a4dd7bb0e0f4e3fc22245817240" + }, + "Rcpp": { + "Package": "Rcpp", + "Version": "1.0.13", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "methods", + "utils" + ], + "Hash": "f27411eb6d9c3dada5edd444b8416675" + }, + "S4Vectors": { + "Package": "S4Vectors", + "Version": "0.42.1", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "BiocGenerics", + "R", + "methods", + "stats", + "stats4", + "utils" + ], + "Hash": "86398fc7c5f6be4ba29fe23ed08c2da6" + }, + "SparseM": { + "Package": "SparseM", + "Version": "1.84-2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "graphics", + "methods", + "stats", + "utils" + ], + "Hash": "e78499cbcbbca98200254bd171379165" + }, + "UCSC.utils": { + "Package": "UCSC.utils", + "Version": "1.0.0", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "S4Vectors", + "httr", + "jsonlite", + "methods", + "stats" + ], + "Hash": "83d45b690bffd09d1980c224ef329f5b" + }, + "XVector": { + "Package": "XVector", + "Version": "0.44.0", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "BiocGenerics", + "IRanges", + "R", + "S4Vectors", + "methods", + "tools", + "utils", + "zlibbioc" + ], + "Hash": "4245b9938ac74c0dbddbebbec6036ab4" + }, + "askpass": { + "Package": "askpass", + "Version": "1.2.0", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "sys" + ], + "Hash": "cad6cf7f1d5f6e906700b9d3e718c796" + }, + "base64enc": { + "Package": "base64enc", + "Version": "0.1-3", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R" + ], + "Hash": "543776ae6848fde2f48ff3816d0628bc" + }, + "bit": { + "Package": "bit", + "Version": "4.5.0", + "Source": "Repository", + "Repository": "https://cran.r-project.org", + "Requirements": [ + "R" + ], + "Hash": "5dc7b2677d65d0e874fc4aaf0e879987" + }, + "bit64": { + "Package": "bit64", + "Version": "4.5.2", + "Source": "Repository", + "Repository": "https://cran.r-project.org", + "Requirements": [ + "R", + "bit", + "methods", + "stats", + "utils" + ], + "Hash": "e84984bf5f12a18628d9a02322128dfd" + }, + "blob": { + "Package": "blob", + "Version": "1.2.4", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "methods", + "rlang", + "vctrs" + ], + "Hash": "40415719b5a479b87949f3aa0aee737c" + }, + "bslib": { + "Package": "bslib", + "Version": "0.7.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "base64enc", + "cachem", + "fastmap", + "grDevices", + "htmltools", + "jquerylib", + "jsonlite", + "lifecycle", + "memoise", + "mime", + "rlang", + "sass" + ], + "Hash": "8644cc53f43828f19133548195d7e59e" + }, + "cachem": { + "Package": "cachem", + "Version": "1.1.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "fastmap", + "rlang" + ], + "Hash": "cd9a672193789068eb5a2aad65a0dedf" + }, + "cli": { + "Package": "cli", + "Version": "3.6.2", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "utils" + ], + "Hash": "1216ac65ac55ec0058a6f75d7ca0fd52" + }, + "cpp11": { + "Package": "cpp11", + "Version": "0.5.0", + "Source": "Repository", + "Repository": "https://cran.r-project.org", + "Requirements": [ + "R" + ], + "Hash": "91570bba75d0c9d3f1040c835cee8fba" + }, + "crayon": { + "Package": "crayon", + "Version": "1.5.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "grDevices", + "methods", + "utils" + ], + "Hash": "859d96e65ef198fd43e82b9628d593ef" + }, + "curl": { + "Package": "curl", + "Version": "5.2.3", + "Source": "Repository", + "Repository": "https://cran.r-project.org", + "Requirements": [ + "R" + ], + "Hash": "d91263322a58af798f6cf3b13fd56dde" + }, + "digest": { + "Package": "digest", + "Version": "0.6.35", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "utils" + ], + "Hash": "698ece7ba5a4fa4559e3d537e7ec3d31" + }, + "evaluate": { + "Package": "evaluate", + "Version": "0.24.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "methods" + ], + "Hash": "a1066cbc05caee9a4bf6d90f194ff4da" + }, + "fastmap": { + "Package": "fastmap", + "Version": "1.2.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "aa5e1cd11c2d15497494c5292d7ffcc8" + }, + "fontawesome": { + "Package": "fontawesome", + "Version": "0.5.2", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "htmltools", + "rlang" + ], + "Hash": "c2efdd5f0bcd1ea861c2d4e2a883a67d" + }, + "fs": { + "Package": "fs", + "Version": "1.6.4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "methods" + ], + "Hash": "15aeb8c27f5ea5161f9f6a641fafd93a" + }, + "glue": { + "Package": "glue", + "Version": "1.7.0", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "methods" + ], + "Hash": "e0b3a53876554bd45879e596cdb10a52" + }, + "graph": { + "Package": "graph", + "Version": "1.82.0", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "BiocGenerics", + "R", + "methods", + "stats", + "stats4", + "utils" + ], + "Hash": "096137dd6d37588451a82658aa94ecbd" + }, + "highr": { + "Package": "highr", + "Version": "0.11", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "xfun" + ], + "Hash": "d65ba49117ca223614f71b60d85b8ab7" + }, + "htmltools": { + "Package": "htmltools", + "Version": "0.5.8.1", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "base64enc", + "digest", + "fastmap", + "grDevices", + "rlang", + "utils" + ], + "Hash": "81d371a9cc60640e74e4ab6ac46dcedc" + }, + "htmlwidgets": { + "Package": "htmlwidgets", + "Version": "1.6.4", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "grDevices", + "htmltools", + "jsonlite", + "knitr", + "rmarkdown", + "yaml" + ], + "Hash": "04291cc45198225444a397606810ac37" + }, + "httr": { + "Package": "httr", + "Version": "1.4.7", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "R6", + "curl", + "jsonlite", + "mime", + "openssl" + ], + "Hash": "ac107251d9d9fd72f0ca8049988f1d7f" + }, + "igraph": { + "Package": "igraph", + "Version": "2.1.1", + "Source": "Repository", + "Repository": "https://cran.r-project.org", + "Requirements": [ + "Matrix", + "R", + "cli", + "cpp11", + "grDevices", + "graphics", + "lifecycle", + "magrittr", + "methods", + "pkgconfig", + "rlang", + "stats", + "utils", + "vctrs" + ], + "Hash": "c03878b48737a0e2da3b772d7b2e22da" + }, + "jquerylib": { + "Package": "jquerylib", + "Version": "0.1.4", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "htmltools" + ], + "Hash": "5aab57a3bd297eee1c1d862735972182" + }, + "jsonlite": { + "Package": "jsonlite", + "Version": "1.8.8", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "methods" + ], + "Hash": "e1b9c55281c5adc4dd113652d9e26768" + }, + "knitr": { + "Package": "knitr", + "Version": "1.48", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "evaluate", + "highr", + "methods", + "tools", + "xfun", + "yaml" + ], + "Hash": "acf380f300c721da9fde7df115a5f86f" + }, + "lattice": { + "Package": "lattice", + "Version": "0.22-6", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "grDevices", + "graphics", + "grid", + "stats", + "utils" + ], + "Hash": "cc5ac1ba4c238c7ca9fa6a87ca11a7e2" + }, + "lifecycle": { + "Package": "lifecycle", + "Version": "1.0.4", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "cli", + "glue", + "rlang" + ], + "Hash": "b8552d117e1b808b09a832f589b79035" + }, + "magrittr": { + "Package": "magrittr", + "Version": "2.0.3", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R" + ], + "Hash": "7ce2733a9826b3aeb1775d56fd305472" + }, + "matrixStats": { + "Package": "matrixStats", + "Version": "1.4.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "8885ffb1f46e820dede6b2ca9442abca" + }, + "memoise": { + "Package": "memoise", + "Version": "2.0.1", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "cachem", + "rlang" + ], + "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c" + }, + "mime": { + "Package": "mime", + "Version": "0.12", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "tools" + ], + "Hash": "18e9c28c1d3ca1560ce30658b22ce104" + }, + "openssl": { + "Package": "openssl", + "Version": "2.2.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "askpass" + ], + "Hash": "2bcca3848e4734eb3b16103bc9aa4b8e" + }, + "org.Hs.eg.db": { + "Package": "org.Hs.eg.db", + "Version": "3.19.1", + "Source": "Bioconductor", + "Requirements": [ + "AnnotationDbi", + "R", + "methods" + ], + "Hash": "1ac8a004ad2e4f6489dadf3a2ffeb638" + }, + "pkgconfig": { + "Package": "pkgconfig", + "Version": "2.0.3", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "utils" + ], + "Hash": "01f28d4278f15c76cddbea05899c5d6f" + }, + "plogr": { + "Package": "plogr", + "Version": "0.2.0", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "09eb987710984fc2905c7129c7d85e65" + }, + "png": { + "Package": "png", + "Version": "0.1-8", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R" + ], + "Hash": "bd54ba8a0a5faded999a7aab6e46b374" + }, + "rappdirs": { + "Package": "rappdirs", + "Version": "0.3.3", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R" + ], + "Hash": "5e3c5dc0b071b21fa128676560dbe94d" + }, + "renv": { + "Package": "renv", + "Version": "1.0.7", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "utils" + ], + "Hash": "397b7b2a265bc5a7a06852524dabae20" + }, + "rlang": { + "Package": "rlang", + "Version": "1.1.4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "utils" + ], + "Hash": "3eec01f8b1dee337674b2e34ab1f9bc1" + }, + "rmarkdown": { + "Package": "rmarkdown", + "Version": "2.28", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "bslib", + "evaluate", + "fontawesome", + "htmltools", + "jquerylib", + "jsonlite", + "knitr", + "methods", + "tinytex", + "tools", + "utils", + "xfun", + "yaml" + ], + "Hash": "062470668513dcda416927085ee9bdc7" + }, + "sass": { + "Package": "sass", + "Version": "0.4.9", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R6", + "fs", + "htmltools", + "rappdirs", + "rlang" + ], + "Hash": "d53dbfddf695303ea4ad66f86e99b95d" + }, + "sys": { + "Package": "sys", + "Version": "3.4.2", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "3a1be13d68d47a8cd0bfd74739ca1555" + }, + "tinytex": { + "Package": "tinytex", + "Version": "0.51", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "xfun" + ], + "Hash": "d44e2fcd2e4e076f0aac540208559d1d" + }, + "topGO": { + "Package": "topGO", + "Version": "2.56.0", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Requirements": [ + "AnnotationDbi", + "Biobase", + "BiocGenerics", + "DBI", + "GO.db", + "R", + "SparseM", + "graph", + "lattice", + "matrixStats", + "methods" + ], + "Hash": "41e23d477c59be6a405f5239fe507213" + }, + "vctrs": { + "Package": "vctrs", + "Version": "0.6.5", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "cli", + "glue", + "lifecycle", + "rlang" + ], + "Hash": "c03fa420630029418f7e6da3667aac4a" + }, + "visNetwork": { + "Package": "visNetwork", + "Version": "2.1.2", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "grDevices", + "htmltools", + "htmlwidgets", + "jsonlite", + "magrittr", + "methods", + "stats", + "utils" + ], + "Hash": "3e48b097e8d9a91ecced2ed4817a678d" + }, + "xfun": { + "Package": "xfun", + "Version": "0.44", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "grDevices", + "stats", + "tools" + ], + "Hash": "317a0538d32f4a009658bcedb7923f4b" + }, + "yaml": { + "Package": "yaml", + "Version": "2.3.10", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "51dab85c6c98e50a18d7551e9d49f76c" + }, + "zlibbioc": { + "Package": "zlibbioc", + "Version": "1.50.0", + "Source": "Bioconductor", + "Repository": "Bioconductor 3.19", + "Hash": "3db02e3c460e1c852365df117a2b441b" + } + } +} diff --git a/renv/.gitignore b/renv/.gitignore new file mode 100644 index 0000000..0ec0cbb --- /dev/null +++ b/renv/.gitignore @@ -0,0 +1,7 @@ +library/ +local/ +cellar/ +lock/ +python/ +sandbox/ +staging/ diff --git a/renv/activate.R b/renv/activate.R new file mode 100644 index 0000000..d13f993 --- /dev/null +++ b/renv/activate.R @@ -0,0 +1,1220 @@ + +local({ + + # the requested version of renv + version <- "1.0.7" + attr(version, "sha") <- NULL + + # the project directory + project <- Sys.getenv("RENV_PROJECT") + if (!nzchar(project)) + project <- getwd() + + # use start-up diagnostics if enabled + diagnostics <- Sys.getenv("RENV_STARTUP_DIAGNOSTICS", unset = "FALSE") + if (diagnostics) { + start <- Sys.time() + profile <- tempfile("renv-startup-", fileext = ".Rprof") + utils::Rprof(profile) + on.exit({ + utils::Rprof(NULL) + elapsed <- signif(difftime(Sys.time(), start, units = "auto"), digits = 2L) + writeLines(sprintf("- renv took %s to run the autoloader.", format(elapsed))) + writeLines(sprintf("- Profile: %s", profile)) + print(utils::summaryRprof(profile)) + }, add = TRUE) + } + + # figure out whether the autoloader is enabled + enabled <- local({ + + # first, check config option + override <- getOption("renv.config.autoloader.enabled") + if (!is.null(override)) + return(override) + + # if we're being run in a context where R_LIBS is already set, + # don't load -- presumably we're being run as a sub-process and + # the parent process has already set up library paths for us + rcmd <- Sys.getenv("R_CMD", unset = NA) + rlibs <- Sys.getenv("R_LIBS", unset = NA) + if (!is.na(rlibs) && !is.na(rcmd)) + return(FALSE) + + # next, check environment variables + # TODO: prefer using the configuration one in the future + envvars <- c( + "RENV_CONFIG_AUTOLOADER_ENABLED", + "RENV_AUTOLOADER_ENABLED", + "RENV_ACTIVATE_PROJECT" + ) + + for (envvar in envvars) { + envval <- Sys.getenv(envvar, unset = NA) + if (!is.na(envval)) + return(tolower(envval) %in% c("true", "t", "1")) + } + + # enable by default + TRUE + + }) + + # bail if we're not enabled + if (!enabled) { + + # if we're not enabled, we might still need to manually load + # the user profile here + profile <- Sys.getenv("R_PROFILE_USER", unset = "~/.Rprofile") + if (file.exists(profile)) { + cfg <- Sys.getenv("RENV_CONFIG_USER_PROFILE", unset = "TRUE") + if (tolower(cfg) %in% c("true", "t", "1")) + sys.source(profile, envir = globalenv()) + } + + return(FALSE) + + } + + # avoid recursion + if (identical(getOption("renv.autoloader.running"), TRUE)) { + warning("ignoring recursive attempt to run renv autoloader") + return(invisible(TRUE)) + } + + # signal that we're loading renv during R startup + options(renv.autoloader.running = TRUE) + on.exit(options(renv.autoloader.running = NULL), add = TRUE) + + # signal that we've consented to use renv + options(renv.consent = TRUE) + + # load the 'utils' package eagerly -- this ensures that renv shims, which + # mask 'utils' packages, will come first on the search path + library(utils, lib.loc = .Library) + + # unload renv if it's already been loaded + if ("renv" %in% loadedNamespaces()) + unloadNamespace("renv") + + # load bootstrap tools + `%||%` <- function(x, y) { + if (is.null(x)) y else x + } + + catf <- function(fmt, ..., appendLF = TRUE) { + + quiet <- getOption("renv.bootstrap.quiet", default = FALSE) + if (quiet) + return(invisible()) + + msg <- sprintf(fmt, ...) + cat(msg, file = stdout(), sep = if (appendLF) "\n" else "") + + invisible(msg) + + } + + header <- function(label, + ..., + prefix = "#", + suffix = "-", + n = min(getOption("width"), 78)) + { + label <- sprintf(label, ...) + n <- max(n - nchar(label) - nchar(prefix) - 2L, 8L) + if (n <= 0) + return(paste(prefix, label)) + + tail <- paste(rep.int(suffix, n), collapse = "") + paste0(prefix, " ", label, " ", tail) + + } + + heredoc <- function(text, leave = 0) { + + # remove leading, trailing whitespace + trimmed <- gsub("^\\s*\\n|\\n\\s*$", "", text) + + # split into lines + lines <- strsplit(trimmed, "\n", fixed = TRUE)[[1L]] + + # compute common indent + indent <- regexpr("[^[:space:]]", lines) + common <- min(setdiff(indent, -1L)) - leave + paste(substring(lines, common), collapse = "\n") + + } + + startswith <- function(string, prefix) { + substring(string, 1, nchar(prefix)) == prefix + } + + bootstrap <- function(version, library) { + + friendly <- renv_bootstrap_version_friendly(version) + section <- header(sprintf("Bootstrapping renv %s", friendly)) + catf(section) + + # attempt to download renv + catf("- Downloading renv ... ", appendLF = FALSE) + withCallingHandlers( + tarball <- renv_bootstrap_download(version), + error = function(err) { + catf("FAILED") + stop("failed to download:\n", conditionMessage(err)) + } + ) + catf("OK") + on.exit(unlink(tarball), add = TRUE) + + # now attempt to install + catf("- Installing renv ... ", appendLF = FALSE) + withCallingHandlers( + status <- renv_bootstrap_install(version, tarball, library), + error = function(err) { + catf("FAILED") + stop("failed to install:\n", conditionMessage(err)) + } + ) + catf("OK") + + # add empty line to break up bootstrapping from normal output + catf("") + + return(invisible()) + } + + renv_bootstrap_tests_running <- function() { + getOption("renv.tests.running", default = FALSE) + } + + renv_bootstrap_repos <- function() { + + # get CRAN repository + cran <- getOption("renv.repos.cran", "https://cloud.r-project.org") + + # check for repos override + repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) + if (!is.na(repos)) { + + # check for RSPM; if set, use a fallback repository for renv + rspm <- Sys.getenv("RSPM", unset = NA) + if (identical(rspm, repos)) + repos <- c(RSPM = rspm, CRAN = cran) + + return(repos) + + } + + # check for lockfile repositories + repos <- tryCatch(renv_bootstrap_repos_lockfile(), error = identity) + if (!inherits(repos, "error") && length(repos)) + return(repos) + + # retrieve current repos + repos <- getOption("repos") + + # ensure @CRAN@ entries are resolved + repos[repos == "@CRAN@"] <- cran + + # add in renv.bootstrap.repos if set + default <- c(FALLBACK = "https://cloud.r-project.org") + extra <- getOption("renv.bootstrap.repos", default = default) + repos <- c(repos, extra) + + # remove duplicates that might've snuck in + dupes <- duplicated(repos) | duplicated(names(repos)) + repos[!dupes] + + } + + renv_bootstrap_repos_lockfile <- function() { + + lockpath <- Sys.getenv("RENV_PATHS_LOCKFILE", unset = "renv.lock") + if (!file.exists(lockpath)) + return(NULL) + + lockfile <- tryCatch(renv_json_read(lockpath), error = identity) + if (inherits(lockfile, "error")) { + warning(lockfile) + return(NULL) + } + + repos <- lockfile$R$Repositories + if (length(repos) == 0) + return(NULL) + + keys <- vapply(repos, `[[`, "Name", FUN.VALUE = character(1)) + vals <- vapply(repos, `[[`, "URL", FUN.VALUE = character(1)) + names(vals) <- keys + + return(vals) + + } + + renv_bootstrap_download <- function(version) { + + sha <- attr(version, "sha", exact = TRUE) + + methods <- if (!is.null(sha)) { + + # attempting to bootstrap a development version of renv + c( + function() renv_bootstrap_download_tarball(sha), + function() renv_bootstrap_download_github(sha) + ) + + } else { + + # attempting to bootstrap a release version of renv + c( + function() renv_bootstrap_download_tarball(version), + function() renv_bootstrap_download_cran_latest(version), + function() renv_bootstrap_download_cran_archive(version) + ) + + } + + for (method in methods) { + path <- tryCatch(method(), error = identity) + if (is.character(path) && file.exists(path)) + return(path) + } + + stop("All download methods failed") + + } + + renv_bootstrap_download_impl <- function(url, destfile) { + + mode <- "wb" + + # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 + fixup <- + Sys.info()[["sysname"]] == "Windows" && + substring(url, 1L, 5L) == "file:" + + if (fixup) + mode <- "w+b" + + args <- list( + url = url, + destfile = destfile, + mode = mode, + quiet = TRUE + ) + + if ("headers" %in% names(formals(utils::download.file))) + args$headers <- renv_bootstrap_download_custom_headers(url) + + do.call(utils::download.file, args) + + } + + renv_bootstrap_download_custom_headers <- function(url) { + + headers <- getOption("renv.download.headers") + if (is.null(headers)) + return(character()) + + if (!is.function(headers)) + stopf("'renv.download.headers' is not a function") + + headers <- headers(url) + if (length(headers) == 0L) + return(character()) + + if (is.list(headers)) + headers <- unlist(headers, recursive = FALSE, use.names = TRUE) + + ok <- + is.character(headers) && + is.character(names(headers)) && + all(nzchar(names(headers))) + + if (!ok) + stop("invocation of 'renv.download.headers' did not return a named character vector") + + headers + + } + + renv_bootstrap_download_cran_latest <- function(version) { + + spec <- renv_bootstrap_download_cran_latest_find(version) + type <- spec$type + repos <- spec$repos + + baseurl <- utils::contrib.url(repos = repos, type = type) + ext <- if (identical(type, "source")) + ".tar.gz" + else if (Sys.info()[["sysname"]] == "Windows") + ".zip" + else + ".tgz" + name <- sprintf("renv_%s%s", version, ext) + url <- paste(baseurl, name, sep = "/") + + destfile <- file.path(tempdir(), name) + status <- tryCatch( + renv_bootstrap_download_impl(url, destfile), + condition = identity + ) + + if (inherits(status, "condition")) + return(FALSE) + + # report success and return + destfile + + } + + renv_bootstrap_download_cran_latest_find <- function(version) { + + # check whether binaries are supported on this system + binary <- + getOption("renv.bootstrap.binary", default = TRUE) && + !identical(.Platform$pkgType, "source") && + !identical(getOption("pkgType"), "source") && + Sys.info()[["sysname"]] %in% c("Darwin", "Windows") + + types <- c(if (binary) "binary", "source") + + # iterate over types + repositories + for (type in types) { + for (repos in renv_bootstrap_repos()) { + + # retrieve package database + db <- tryCatch( + as.data.frame( + utils::available.packages(type = type, repos = repos), + stringsAsFactors = FALSE + ), + error = identity + ) + + if (inherits(db, "error")) + next + + # check for compatible entry + entry <- db[db$Package %in% "renv" & db$Version %in% version, ] + if (nrow(entry) == 0) + next + + # found it; return spec to caller + spec <- list(entry = entry, type = type, repos = repos) + return(spec) + + } + } + + # if we got here, we failed to find renv + fmt <- "renv %s is not available from your declared package repositories" + stop(sprintf(fmt, version)) + + } + + renv_bootstrap_download_cran_archive <- function(version) { + + name <- sprintf("renv_%s.tar.gz", version) + repos <- renv_bootstrap_repos() + urls <- file.path(repos, "src/contrib/Archive/renv", name) + destfile <- file.path(tempdir(), name) + + for (url in urls) { + + status <- tryCatch( + renv_bootstrap_download_impl(url, destfile), + condition = identity + ) + + if (identical(status, 0L)) + return(destfile) + + } + + return(FALSE) + + } + + renv_bootstrap_download_tarball <- function(version) { + + # if the user has provided the path to a tarball via + # an environment variable, then use it + tarball <- Sys.getenv("RENV_BOOTSTRAP_TARBALL", unset = NA) + if (is.na(tarball)) + return() + + # allow directories + if (dir.exists(tarball)) { + name <- sprintf("renv_%s.tar.gz", version) + tarball <- file.path(tarball, name) + } + + # bail if it doesn't exist + if (!file.exists(tarball)) { + + # let the user know we weren't able to honour their request + fmt <- "- RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist." + msg <- sprintf(fmt, tarball) + warning(msg) + + # bail + return() + + } + + catf("- Using local tarball '%s'.", tarball) + tarball + + } + + renv_bootstrap_download_github <- function(version) { + + enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") + if (!identical(enabled, "TRUE")) + return(FALSE) + + # prepare download options + pat <- Sys.getenv("GITHUB_PAT") + if (nzchar(Sys.which("curl")) && nzchar(pat)) { + fmt <- "--location --fail --header \"Authorization: token %s\"" + extra <- sprintf(fmt, pat) + saved <- options("download.file.method", "download.file.extra") + options(download.file.method = "curl", download.file.extra = extra) + on.exit(do.call(base::options, saved), add = TRUE) + } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { + fmt <- "--header=\"Authorization: token %s\"" + extra <- sprintf(fmt, pat) + saved <- options("download.file.method", "download.file.extra") + options(download.file.method = "wget", download.file.extra = extra) + on.exit(do.call(base::options, saved), add = TRUE) + } + + url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) + name <- sprintf("renv_%s.tar.gz", version) + destfile <- file.path(tempdir(), name) + + status <- tryCatch( + renv_bootstrap_download_impl(url, destfile), + condition = identity + ) + + if (!identical(status, 0L)) + return(FALSE) + + renv_bootstrap_download_augment(destfile) + + return(destfile) + + } + + # Add Sha to DESCRIPTION. This is stop gap until #890, after which we + # can use renv::install() to fully capture metadata. + renv_bootstrap_download_augment <- function(destfile) { + sha <- renv_bootstrap_git_extract_sha1_tar(destfile) + if (is.null(sha)) { + return() + } + + # Untar + tempdir <- tempfile("renv-github-") + on.exit(unlink(tempdir, recursive = TRUE), add = TRUE) + untar(destfile, exdir = tempdir) + pkgdir <- dir(tempdir, full.names = TRUE)[[1]] + + # Modify description + desc_path <- file.path(pkgdir, "DESCRIPTION") + desc_lines <- readLines(desc_path) + remotes_fields <- c( + "RemoteType: github", + "RemoteHost: api.github.com", + "RemoteRepo: renv", + "RemoteUsername: rstudio", + "RemotePkgRef: rstudio/renv", + paste("RemoteRef: ", sha), + paste("RemoteSha: ", sha) + ) + writeLines(c(desc_lines[desc_lines != ""], remotes_fields), con = desc_path) + + # Re-tar + local({ + old <- setwd(tempdir) + on.exit(setwd(old), add = TRUE) + + tar(destfile, compression = "gzip") + }) + invisible() + } + + # Extract the commit hash from a git archive. Git archives include the SHA1 + # hash as the comment field of the tarball pax extended header + # (see https://www.kernel.org/pub/software/scm/git/docs/git-archive.html) + # For GitHub archives this should be the first header after the default one + # (512 byte) header. + renv_bootstrap_git_extract_sha1_tar <- function(bundle) { + + # open the bundle for reading + # We use gzcon for everything because (from ?gzcon) + # > Reading from a connection which does not supply a 'gzip' magic + # > header is equivalent to reading from the original connection + conn <- gzcon(file(bundle, open = "rb", raw = TRUE)) + on.exit(close(conn)) + + # The default pax header is 512 bytes long and the first pax extended header + # with the comment should be 51 bytes long + # `52 comment=` (11 chars) + 40 byte SHA1 hash + len <- 0x200 + 0x33 + res <- rawToChar(readBin(conn, "raw", n = len)[0x201:len]) + + if (grepl("^52 comment=", res)) { + sub("52 comment=", "", res) + } else { + NULL + } + } + + renv_bootstrap_install <- function(version, tarball, library) { + + # attempt to install it into project library + dir.create(library, showWarnings = FALSE, recursive = TRUE) + output <- renv_bootstrap_install_impl(library, tarball) + + # check for successful install + status <- attr(output, "status") + if (is.null(status) || identical(status, 0L)) + return(status) + + # an error occurred; report it + header <- "installation of renv failed" + lines <- paste(rep.int("=", nchar(header)), collapse = "") + text <- paste(c(header, lines, output), collapse = "\n") + stop(text) + + } + + renv_bootstrap_install_impl <- function(library, tarball) { + + # invoke using system2 so we can capture and report output + bin <- R.home("bin") + exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" + R <- file.path(bin, exe) + + args <- c( + "--vanilla", "CMD", "INSTALL", "--no-multiarch", + "-l", shQuote(path.expand(library)), + shQuote(path.expand(tarball)) + ) + + system2(R, args, stdout = TRUE, stderr = TRUE) + + } + + renv_bootstrap_platform_prefix <- function() { + + # construct version prefix + version <- paste(R.version$major, R.version$minor, sep = ".") + prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-") + + # include SVN revision for development versions of R + # (to avoid sharing platform-specific artefacts with released versions of R) + devel <- + identical(R.version[["status"]], "Under development (unstable)") || + identical(R.version[["nickname"]], "Unsuffered Consequences") + + if (devel) + prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") + + # build list of path components + components <- c(prefix, R.version$platform) + + # include prefix if provided by user + prefix <- renv_bootstrap_platform_prefix_impl() + if (!is.na(prefix) && nzchar(prefix)) + components <- c(prefix, components) + + # build prefix + paste(components, collapse = "/") + + } + + renv_bootstrap_platform_prefix_impl <- function() { + + # if an explicit prefix has been supplied, use it + prefix <- Sys.getenv("RENV_PATHS_PREFIX", unset = NA) + if (!is.na(prefix)) + return(prefix) + + # if the user has requested an automatic prefix, generate it + auto <- Sys.getenv("RENV_PATHS_PREFIX_AUTO", unset = NA) + if (is.na(auto) && getRversion() >= "4.4.0") + auto <- "TRUE" + + if (auto %in% c("TRUE", "True", "true", "1")) + return(renv_bootstrap_platform_prefix_auto()) + + # empty string on failure + "" + + } + + renv_bootstrap_platform_prefix_auto <- function() { + + prefix <- tryCatch(renv_bootstrap_platform_os(), error = identity) + if (inherits(prefix, "error") || prefix %in% "unknown") { + + msg <- paste( + "failed to infer current operating system", + "please file a bug report at https://github.com/rstudio/renv/issues", + sep = "; " + ) + + warning(msg) + + } + + prefix + + } + + renv_bootstrap_platform_os <- function() { + + sysinfo <- Sys.info() + sysname <- sysinfo[["sysname"]] + + # handle Windows + macOS up front + if (sysname == "Windows") + return("windows") + else if (sysname == "Darwin") + return("macos") + + # check for os-release files + for (file in c("/etc/os-release", "/usr/lib/os-release")) + if (file.exists(file)) + return(renv_bootstrap_platform_os_via_os_release(file, sysinfo)) + + # check for redhat-release files + if (file.exists("/etc/redhat-release")) + return(renv_bootstrap_platform_os_via_redhat_release()) + + "unknown" + + } + + renv_bootstrap_platform_os_via_os_release <- function(file, sysinfo) { + + # read /etc/os-release + release <- utils::read.table( + file = file, + sep = "=", + quote = c("\"", "'"), + col.names = c("Key", "Value"), + comment.char = "#", + stringsAsFactors = FALSE + ) + + vars <- as.list(release$Value) + names(vars) <- release$Key + + # get os name + os <- tolower(sysinfo[["sysname"]]) + + # read id + id <- "unknown" + for (field in c("ID", "ID_LIKE")) { + if (field %in% names(vars) && nzchar(vars[[field]])) { + id <- vars[[field]] + break + } + } + + # read version + version <- "unknown" + for (field in c("UBUNTU_CODENAME", "VERSION_CODENAME", "VERSION_ID", "BUILD_ID")) { + if (field %in% names(vars) && nzchar(vars[[field]])) { + version <- vars[[field]] + break + } + } + + # join together + paste(c(os, id, version), collapse = "-") + + } + + renv_bootstrap_platform_os_via_redhat_release <- function() { + + # read /etc/redhat-release + contents <- readLines("/etc/redhat-release", warn = FALSE) + + # infer id + id <- if (grepl("centos", contents, ignore.case = TRUE)) + "centos" + else if (grepl("redhat", contents, ignore.case = TRUE)) + "redhat" + else + "unknown" + + # try to find a version component (very hacky) + version <- "unknown" + + parts <- strsplit(contents, "[[:space:]]")[[1L]] + for (part in parts) { + + nv <- tryCatch(numeric_version(part), error = identity) + if (inherits(nv, "error")) + next + + version <- nv[1, 1] + break + + } + + paste(c("linux", id, version), collapse = "-") + + } + + renv_bootstrap_library_root_name <- function(project) { + + # use project name as-is if requested + asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE") + if (asis) + return(basename(project)) + + # otherwise, disambiguate based on project's path + id <- substring(renv_bootstrap_hash_text(project), 1L, 8L) + paste(basename(project), id, sep = "-") + + } + + renv_bootstrap_library_root <- function(project) { + + prefix <- renv_bootstrap_profile_prefix() + + path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) + if (!is.na(path)) + return(paste(c(path, prefix), collapse = "/")) + + path <- renv_bootstrap_library_root_impl(project) + if (!is.null(path)) { + name <- renv_bootstrap_library_root_name(project) + return(paste(c(path, prefix, name), collapse = "/")) + } + + renv_bootstrap_paths_renv("library", project = project) + + } + + renv_bootstrap_library_root_impl <- function(project) { + + root <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) + if (!is.na(root)) + return(root) + + type <- renv_bootstrap_project_type(project) + if (identical(type, "package")) { + userdir <- renv_bootstrap_user_dir() + return(file.path(userdir, "library")) + } + + } + + renv_bootstrap_validate_version <- function(version, description = NULL) { + + # resolve description file + # + # avoid passing lib.loc to `packageDescription()` below, since R will + # use the loaded version of the package by default anyhow. note that + # this function should only be called after 'renv' is loaded + # https://github.com/rstudio/renv/issues/1625 + description <- description %||% packageDescription("renv") + + # check whether requested version 'version' matches loaded version of renv + sha <- attr(version, "sha", exact = TRUE) + valid <- if (!is.null(sha)) + renv_bootstrap_validate_version_dev(sha, description) + else + renv_bootstrap_validate_version_release(version, description) + + if (valid) + return(TRUE) + + # the loaded version of renv doesn't match the requested version; + # give the user instructions on how to proceed + dev <- identical(description[["RemoteType"]], "github") + remote <- if (dev) + paste("rstudio/renv", description[["RemoteSha"]], sep = "@") + else + paste("renv", description[["Version"]], sep = "@") + + # display both loaded version + sha if available + friendly <- renv_bootstrap_version_friendly( + version = description[["Version"]], + sha = if (dev) description[["RemoteSha"]] + ) + + fmt <- heredoc(" + renv %1$s was loaded from project library, but this project is configured to use renv %2$s. + - Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile. + - Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library. + ") + catf(fmt, friendly, renv_bootstrap_version_friendly(version), remote) + + FALSE + + } + + renv_bootstrap_validate_version_dev <- function(version, description) { + expected <- description[["RemoteSha"]] + is.character(expected) && startswith(expected, version) + } + + renv_bootstrap_validate_version_release <- function(version, description) { + expected <- description[["Version"]] + is.character(expected) && identical(expected, version) + } + + renv_bootstrap_hash_text <- function(text) { + + hashfile <- tempfile("renv-hash-") + on.exit(unlink(hashfile), add = TRUE) + + writeLines(text, con = hashfile) + tools::md5sum(hashfile) + + } + + renv_bootstrap_load <- function(project, libpath, version) { + + # try to load renv from the project library + if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) + return(FALSE) + + # warn if the version of renv loaded does not match + renv_bootstrap_validate_version(version) + + # execute renv load hooks, if any + hooks <- getHook("renv::autoload") + for (hook in hooks) + if (is.function(hook)) + tryCatch(hook(), error = warnify) + + # load the project + renv::load(project) + + TRUE + + } + + renv_bootstrap_profile_load <- function(project) { + + # if RENV_PROFILE is already set, just use that + profile <- Sys.getenv("RENV_PROFILE", unset = NA) + if (!is.na(profile) && nzchar(profile)) + return(profile) + + # check for a profile file (nothing to do if it doesn't exist) + path <- renv_bootstrap_paths_renv("profile", profile = FALSE, project = project) + if (!file.exists(path)) + return(NULL) + + # read the profile, and set it if it exists + contents <- readLines(path, warn = FALSE) + if (length(contents) == 0L) + return(NULL) + + # set RENV_PROFILE + profile <- contents[[1L]] + if (!profile %in% c("", "default")) + Sys.setenv(RENV_PROFILE = profile) + + profile + + } + + renv_bootstrap_profile_prefix <- function() { + profile <- renv_bootstrap_profile_get() + if (!is.null(profile)) + return(file.path("profiles", profile, "renv")) + } + + renv_bootstrap_profile_get <- function() { + profile <- Sys.getenv("RENV_PROFILE", unset = "") + renv_bootstrap_profile_normalize(profile) + } + + renv_bootstrap_profile_set <- function(profile) { + profile <- renv_bootstrap_profile_normalize(profile) + if (is.null(profile)) + Sys.unsetenv("RENV_PROFILE") + else + Sys.setenv(RENV_PROFILE = profile) + } + + renv_bootstrap_profile_normalize <- function(profile) { + + if (is.null(profile) || profile %in% c("", "default")) + return(NULL) + + profile + + } + + renv_bootstrap_path_absolute <- function(path) { + + substr(path, 1L, 1L) %in% c("~", "/", "\\") || ( + substr(path, 1L, 1L) %in% c(letters, LETTERS) && + substr(path, 2L, 3L) %in% c(":/", ":\\") + ) + + } + + renv_bootstrap_paths_renv <- function(..., profile = TRUE, project = NULL) { + renv <- Sys.getenv("RENV_PATHS_RENV", unset = "renv") + root <- if (renv_bootstrap_path_absolute(renv)) NULL else project + prefix <- if (profile) renv_bootstrap_profile_prefix() + components <- c(root, renv, prefix, ...) + paste(components, collapse = "/") + } + + renv_bootstrap_project_type <- function(path) { + + descpath <- file.path(path, "DESCRIPTION") + if (!file.exists(descpath)) + return("unknown") + + desc <- tryCatch( + read.dcf(descpath, all = TRUE), + error = identity + ) + + if (inherits(desc, "error")) + return("unknown") + + type <- desc$Type + if (!is.null(type)) + return(tolower(type)) + + package <- desc$Package + if (!is.null(package)) + return("package") + + "unknown" + + } + + renv_bootstrap_user_dir <- function() { + dir <- renv_bootstrap_user_dir_impl() + path.expand(chartr("\\", "/", dir)) + } + + renv_bootstrap_user_dir_impl <- function() { + + # use local override if set + override <- getOption("renv.userdir.override") + if (!is.null(override)) + return(override) + + # use R_user_dir if available + tools <- asNamespace("tools") + if (is.function(tools$R_user_dir)) + return(tools$R_user_dir("renv", "cache")) + + # try using our own backfill for older versions of R + envvars <- c("R_USER_CACHE_DIR", "XDG_CACHE_HOME") + for (envvar in envvars) { + root <- Sys.getenv(envvar, unset = NA) + if (!is.na(root)) + return(file.path(root, "R/renv")) + } + + # use platform-specific default fallbacks + if (Sys.info()[["sysname"]] == "Windows") + file.path(Sys.getenv("LOCALAPPDATA"), "R/cache/R/renv") + else if (Sys.info()[["sysname"]] == "Darwin") + "~/Library/Caches/org.R-project.R/R/renv" + else + "~/.cache/R/renv" + + } + + renv_bootstrap_version_friendly <- function(version, shafmt = NULL, sha = NULL) { + sha <- sha %||% attr(version, "sha", exact = TRUE) + parts <- c(version, sprintf(shafmt %||% " [sha: %s]", substring(sha, 1L, 7L))) + paste(parts, collapse = "") + } + + renv_bootstrap_exec <- function(project, libpath, version) { + if (!renv_bootstrap_load(project, libpath, version)) + renv_bootstrap_run(version, libpath) + } + + renv_bootstrap_run <- function(version, libpath) { + + # perform bootstrap + bootstrap(version, libpath) + + # exit early if we're just testing bootstrap + if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) + return(TRUE) + + # try again to load + if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { + return(renv::load(project = getwd())) + } + + # failed to download or load renv; warn the user + msg <- c( + "Failed to find an renv installation: the project will not be loaded.", + "Use `renv::activate()` to re-initialize the project." + ) + + warning(paste(msg, collapse = "\n"), call. = FALSE) + + } + + renv_json_read <- function(file = NULL, text = NULL) { + + jlerr <- NULL + + # if jsonlite is loaded, use that instead + if ("jsonlite" %in% loadedNamespaces()) { + + json <- tryCatch(renv_json_read_jsonlite(file, text), error = identity) + if (!inherits(json, "error")) + return(json) + + jlerr <- json + + } + + # otherwise, fall back to the default JSON reader + json <- tryCatch(renv_json_read_default(file, text), error = identity) + if (!inherits(json, "error")) + return(json) + + # report an error + if (!is.null(jlerr)) + stop(jlerr) + else + stop(json) + + } + + renv_json_read_jsonlite <- function(file = NULL, text = NULL) { + text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") + jsonlite::fromJSON(txt = text, simplifyVector = FALSE) + } + + renv_json_read_default <- function(file = NULL, text = NULL) { + + # find strings in the JSON + text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") + pattern <- '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' + locs <- gregexpr(pattern, text, perl = TRUE)[[1]] + + # if any are found, replace them with placeholders + replaced <- text + strings <- character() + replacements <- character() + + if (!identical(c(locs), -1L)) { + + # get the string values + starts <- locs + ends <- locs + attr(locs, "match.length") - 1L + strings <- substring(text, starts, ends) + + # only keep those requiring escaping + strings <- grep("[[\\]{}:]", strings, perl = TRUE, value = TRUE) + + # compute replacements + replacements <- sprintf('"\032%i\032"', seq_along(strings)) + + # replace the strings + mapply(function(string, replacement) { + replaced <<- sub(string, replacement, replaced, fixed = TRUE) + }, strings, replacements) + + } + + # transform the JSON into something the R parser understands + transformed <- replaced + transformed <- gsub("{}", "`names<-`(list(), character())", transformed, fixed = TRUE) + transformed <- gsub("[[{]", "list(", transformed, perl = TRUE) + transformed <- gsub("[]}]", ")", transformed, perl = TRUE) + transformed <- gsub(":", "=", transformed, fixed = TRUE) + text <- paste(transformed, collapse = "\n") + + # parse it + json <- parse(text = text, keep.source = FALSE, srcfile = NULL)[[1L]] + + # construct map between source strings, replaced strings + map <- as.character(parse(text = strings)) + names(map) <- as.character(parse(text = replacements)) + + # convert to list + map <- as.list(map) + + # remap strings in object + remapped <- renv_json_read_remap(json, map) + + # evaluate + eval(remapped, envir = baseenv()) + + } + + renv_json_read_remap <- function(json, map) { + + # fix names + if (!is.null(names(json))) { + lhs <- match(names(json), names(map), nomatch = 0L) + rhs <- match(names(map), names(json), nomatch = 0L) + names(json)[rhs] <- map[lhs] + } + + # fix values + if (is.character(json)) + return(map[[json]] %||% json) + + # handle true, false, null + if (is.name(json)) { + text <- as.character(json) + if (text == "true") + return(TRUE) + else if (text == "false") + return(FALSE) + else if (text == "null") + return(NULL) + } + + # recurse + if (is.recursive(json)) { + for (i in seq_along(json)) { + json[i] <- list(renv_json_read_remap(json[[i]], map)) + } + } + + json + + } + + # load the renv profile, if any + renv_bootstrap_profile_load(project) + + # construct path to library root + root <- renv_bootstrap_library_root(project) + + # construct library prefix for platform + prefix <- renv_bootstrap_platform_prefix() + + # construct full libpath + libpath <- file.path(root, prefix) + + # run bootstrap code + renv_bootstrap_exec(project, libpath, version) + + invisible() + +}) diff --git a/renv/settings.json b/renv/settings.json new file mode 100644 index 0000000..74c1d4b --- /dev/null +++ b/renv/settings.json @@ -0,0 +1,19 @@ +{ + "bioconductor.version": null, + "external.libraries": [], + "ignored.packages": [], + "package.dependency.fields": [ + "Imports", + "Depends", + "LinkingTo" + ], + "ppm.enabled": null, + "ppm.ignored.urls": [], + "r.version": null, + "snapshot.type": "explicit", + "use.cache": true, + "vcs.ignore.cellar": true, + "vcs.ignore.library": true, + "vcs.ignore.local": true, + "vcs.manage.ignores": true +} From d4ef629d14b3f7159f9ce483a90f318bb1944a8a Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 18:30:44 -0400 Subject: [PATCH 02/13] docs: update the documentation for the project Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- .Rbuildignore | 2 ++ DESCRIPTION | 2 +- man/PCSF.Rd | 62 ++++++++++++++++++++------------------ man/PCSF_rand.Rd | 4 ++- man/STRING.Rd | 6 ++-- man/Tgfb_phospho.Rd | 6 ++-- man/enrichment_analysis.Rd | 54 ++++++++++++++++----------------- man/plot.PCSF.Rd | 45 ++++++++++++++++----------- man/plot.PCSFe.Rd | 19 +++++++++--- src/RcppExports.cpp | 5 +++ 10 files changed, 120 insertions(+), 85 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index 91114bf..d821302 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,2 +1,4 @@ +^renv$ +^renv\.lock$ ^.*\.Rproj$ ^\.Rproj\.user$ diff --git a/DESCRIPTION b/DESCRIPTION index 076344b..0999724 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -22,4 +22,4 @@ Imports: Rcpp, topGO LinkingTo: Rcpp, BH -RoxygenNote: 6.0.1 +RoxygenNote: 7.3.2 diff --git a/man/PCSF.Rd b/man/PCSF.Rd index d6159ec..eaab1ff 100644 --- a/man/PCSF.Rd +++ b/man/PCSF.Rd @@ -4,13 +4,13 @@ \alias{PCSF} \title{Prize-collecting Steiner Forest (PCSF)} \usage{ -PCSF(ppi, terminals, w = 2, b = 1, mu = 5e-04) +PCSF(ppi, terminals, w = 2, b = 1, mu = 0.0005, dummies) } \arguments{ \item{ppi}{An interaction network, an \pkg{igraph} object.} -\item{terminals}{A list of terminal genes with prizes to be analyzed in the PCSF context. -A named \code{numeric} vector, where terminal genes are named same as in the interaction network +\item{terminals}{A list of terminal genes with prizes to be analyzed in the PCSF context. +A named \code{numeric} vector, where terminal genes are named same as in the interaction network and numeric values correspond to the importance of the gene within the study.} \item{w}{A \code{numeric} value for tuning the number of trees in the output. A default value is 2.} @@ -18,54 +18,56 @@ and numeric values correspond to the importance of the gene within the study.} \item{b}{A \code{numeric} value for tuning the node prizes. A default value is 1.} \item{mu}{A \code{numeric} value for a hub penalization. A default value is 0.0005.} + +\item{dummies}{A list of nodes that are to connected to the root of the tree. If missing the root will be connected to all terminals.} } \value{ -The final subnetwork obtained by the PCSF. +The final subnetwork obtained by the PCSF. It return an \pkg{igraph} object with the node prize and edge cost attributes. } \description{ \code{PCSF} returns a subnetwork obtained by solving the PCSF on the given interaction network. } \details{ -The PCSF is a well-know problem in graph theory. +The PCSF is a well-know problem in graph theory. Given an undirected graph \emph{G = (V, E)}, where the vertices are labeled with prizes \eqn{p_{v}} and the edges are labeled with costs \eqn{c_{e} > 0}, the goal is to identify a subnetwork \emph{G' = (V', E')} with a forest structure. The target is to minimize -the total edge costs in \emph{E'}, the total node prizes left out of \emph{V'}, and the -number of trees in \emph{G'}. This is equivalent to minimization of the following +the total edge costs in \emph{E'}, the total node prizes left out of \emph{V'}, and the +number of trees in \emph{G'}. This is equivalent to minimization of the following objective function: \deqn{F(G')= Minimize \sum_{ e \in E'} c_{e} + \beta*\sum_{v \not\in V'} p_v + \omega*k} where, \emph{k} is the number of trees in the forest, and it is regulated by parameter \eqn{\omega}. -The parameter \eqn{\beta} is used to tune the prizes of nodes. +The parameter \eqn{\beta} is used to tune the prizes of nodes. This optimization problem nicely maps onto the problem of finding differentially -enriched subnetworks in the cell protein-protein interaction (PPI) network. -The vertices of interaction network correspond to genes or proteins, and edges -represent the interactions among them. We can assign prizes -to vertices based on measurements of differential expression, copy number, or -mutation, and costs to edges based on confidence scores for those intra-cellular -interactions from experimental observation, yielding a proper input to the PCSF -problem. Vertices that are assigned a prize are referred to \emph{terminal} nodes, -whereas the vertices which are not observed in patient data are not assigned a -prize and are called \emph{Steiner} nodes. After scoring the interactome, the -PCSF is used to detect a relevant subnetwork (forest), which corresponds to a -portion of the interactome, where many genes are highly correlated in terms of -their functions and may regulate the differentially active biological process -of interest. The PCSF aims to identify neighborhoods in interaction networks +enriched subnetworks in the cell protein-protein interaction (PPI) network. +The vertices of interaction network correspond to genes or proteins, and edges +represent the interactions among them. We can assign prizes +to vertices based on measurements of differential expression, copy number, or +mutation, and costs to edges based on confidence scores for those intra-cellular +interactions from experimental observation, yielding a proper input to the PCSF +problem. Vertices that are assigned a prize are referred to \emph{terminal} nodes, +whereas the vertices which are not observed in patient data are not assigned a +prize and are called \emph{Steiner} nodes. After scoring the interactome, the +PCSF is used to detect a relevant subnetwork (forest), which corresponds to a +portion of the interactome, where many genes are highly correlated in terms of +their functions and may regulate the differentially active biological process +of interest. The PCSF aims to identify neighborhoods in interaction networks potentially belonging to the key dysregulated pathways of a disease. -In order to avoid a bias towards the hub nodes of PPI networks to appear in solution -of PCSF, we penalize the prizes of \emph{Steiner} nodes according to their degree +In order to avoid a bias towards the hub nodes of PPI networks to appear in solution +of PCSF, we penalize the prizes of \emph{Steiner} nodes according to their degree distribution in PPI, and it is regulated by parameter \eqn{\mu}: \deqn{p'_{v} = p_{v} - \mu*degree(v)} - - The parameter \eqn{\mu} also affects the total number of \emph{Steiner} nodes in the solution. - Higher the value of \eqn{\mu} smaller the number of \emph{Steiners} in the subnetwork, - and vice-versa. Based on our previous analysis the recommended range of \eqn{\mu} - for biological networks is between 1e-4 and 5e-2, and users can choose the values - resulting subnetworks with vertex sets that have desirable \emph{Steiner/terminal} - node ratio and average \emph{Steiner/terminal} in-degree ratio + + The parameter \eqn{\mu} also affects the total number of \emph{Steiner} nodes in the solution. + Higher the value of \eqn{\mu} smaller the number of \emph{Steiners} in the subnetwork, + and vice-versa. Based on our previous analysis the recommended range of \eqn{\mu} + for biological networks is between 1e-4 and 5e-2, and users can choose the values + resulting subnetworks with vertex sets that have desirable \emph{Steiner/terminal} + node ratio and average \emph{Steiner/terminal} in-degree ratio in the template interaction network. } \examples{ diff --git a/man/PCSF_rand.Rd b/man/PCSF_rand.Rd index 9519160..c1722a2 100644 --- a/man/PCSF_rand.Rd +++ b/man/PCSF_rand.Rd @@ -4,7 +4,7 @@ \alias{PCSF_rand} \title{Prize-collecting Steiner Forest (PCSF) with randomized edge costs} \usage{ -PCSF_rand(ppi, terminals, n = 10, r = 0.1, w = 2, b = 1, mu = 5e-04) +PCSF_rand(ppi, terminals, n = 10, r = 0.1, w = 2, b = 1, mu = 0.0005, dummies) } \arguments{ \item{ppi}{An interaction network as an \pkg{igraph} object.} @@ -24,6 +24,8 @@ A random noise upto r percent of the edge cost is added to each edge. A default \item{b}{A \code{numeric} value for tuning the node prizes. A default value is 1.} \item{mu}{A \code{numeric} value for a hub penalization. A default value is 0.0005.} + +\item{dummies}{A list of nodes that are to connected to the root of the tree. If missing the root will be connected to all terminals.} } \value{ The final subnetwork obtained by taking the union of the PCSF outputs generated by diff --git a/man/STRING.Rd b/man/STRING.Rd index 0fb05a7..0d90336 100644 --- a/man/STRING.Rd +++ b/man/STRING.Rd @@ -4,9 +4,11 @@ \name{STRING} \alias{STRING} \title{Protein-protein interaction network data} -\format{A data frame with three variables, where each row corresponds to +\format{ +A data frame with three variables, where each row corresponds to an edge in which the first element is a \code{head}, the second -element is a \code{tail}, and the last element represents the \code{cost} of the edge.} +element is a \code{tail}, and the last element represents the \code{cost} of the edge. +} \source{ iref_mitab_miscore_2013_08_12_interactome.txt \url{https://github.com/fraenkel-lab/OmicsIntegrator/tree/master/data} } diff --git a/man/Tgfb_phospho.Rd b/man/Tgfb_phospho.Rd index f2c484f..45de9e6 100644 --- a/man/Tgfb_phospho.Rd +++ b/man/Tgfb_phospho.Rd @@ -4,9 +4,11 @@ \name{Tgfb_phospho} \alias{Tgfb_phospho} \title{Phosphoproteomic data} -\format{A named \code{numeric} vector, where terminal genes are named same as +\format{ +A named \code{numeric} vector, where terminal genes are named same as in the interaction network and numeric values correspond to the importance of -the gene within the study.} +the gene within the study. +} \source{ Tgfb_phos.txt \url{https://github.com/fraenkel-lab/OmicsIntegrator/tree/master/example/a549} } diff --git a/man/enrichment_analysis.Rd b/man/enrichment_analysis.Rd index cee6150..f485cdf 100644 --- a/man/enrichment_analysis.Rd +++ b/man/enrichment_analysis.Rd @@ -7,9 +7,9 @@ enrichment_analysis(subnet, mode = NULL, gene_universe) } \arguments{ -\item{subnet}{A subnetwork provided by \code{\link{PCSF_rand}}, which is obtained by merging -a multiple outputs of the PCSF with random noise added edge costs. An \pkg{igraph} object -with edge cost and vertex prize attributes representing the total number of +\item{subnet}{A subnetwork provided by \code{\link{PCSF_rand}}, which is obtained by merging +a multiple outputs of the PCSF with random noise added edge costs. An \pkg{igraph} object +with edge cost and vertex prize attributes representing the total number of show ups throughout all runs.} \item{mode}{A binary variable to choose the method for enrichment analysis, where 0 is for EnrichR API and 1 is for \pkg{topGO} package.} @@ -17,33 +17,33 @@ show ups throughout all runs.} \item{gene_universe}{A complete list of genes (vector of gene symbols) used as background in enrichment analysis by \pkg{topGO} package.} } \value{ -A list composed of an interactive subnetwork and a table with enrichment -analysis results. An interactive subnetwork annotated with enrichment analysis -can be reached by $subnet. A full list of enrichment analysis for each cluster +A list composed of an interactive subnetwork and a table with enrichment +analysis results. An interactive subnetwork annotated with enrichment analysis +can be reached by $subnet. A full list of enrichment analysis for each cluster can be reached by $enrichment. } \description{ -\code{enrichment_analysis} performs functional enrichment analysis on the subnetwork -obtained by the \code{\link{PCSF_rand}}, and returns an annotated subnetwork with top 15 -functional enrichments and a list of tables with a complete enrichment analysis for +\code{enrichment_analysis} performs functional enrichment analysis on the subnetwork +obtained by the \code{\link{PCSF_rand}}, and returns an annotated subnetwork with top 15 +functional enrichments and a list of tables with a complete enrichment analysis for each cluster. } \details{ -An enrichment analysis of the final subnetwork obtained by multiple runs of the PCSF -(with rando noise added edge costs) is performed for functional interpretation. -The subnetwork is clustered using an edge betweenness clustering algorithm from -the \pkg{igraph} package, and for each cluster functional enrichment is done by -employing either EnrichR API (Chen \emph{et al.}, 2013) or +An enrichment analysis of the final subnetwork obtained by multiple runs of the PCSF +(with rando noise added edge costs) is performed for functional interpretation. +The subnetwork is clustered using an edge betweenness clustering algorithm from +the \pkg{igraph} package, and for each cluster functional enrichment is done by +employing either EnrichR API (Chen \emph{et al.}, 2013) or \pkg{topGO} (Alexa and Rahnenfuhrer, 2009) -package that is specified by the user. Important to note that EnrichR API requires -a working Internet connection to perform the enrichment. If the user does not -specify which tool to use for enrichment analysis, the package employs EnrichR -as a default if there is Internet connection, otherwise it uses \pkg{topGO}. +package that is specified by the user. Important to note that EnrichR API requires +a working Internet connection to perform the enrichment. If the user does not +specify which tool to use for enrichment analysis, the package employs EnrichR +as a default if there is Internet connection, otherwise it uses \pkg{topGO}. -An interactive visualization of -the final subnetwork is plotted, where the node sizes and edge widths are proportional -to the frequency of show ups throughout total runs. Nodes are colored according to the -cluster membership, and the top 15 functional enrichment terms are displayed in tabular +An interactive visualization of +the final subnetwork is plotted, where the node sizes and edge widths are proportional +to the frequency of show ups throughout total runs. Nodes are colored according to the +cluster membership, and the top 15 functional enrichment terms are displayed in tabular format during the hover-over of the node in that cluster. } \examples{ @@ -62,13 +62,13 @@ gene_universe <- V(ppi)$name res <- enrichment_analysis(subnet, mode=1, gene_universe)} \dontrun{ plot(res$subnet) -write.table(res$enrichment[[1]],file="cluster1_complete_enrichment.txt", - append = FALSE, quote = FALSE, sep ="\\t", row.names=FALSE)} - +write.table(res$enrichment[[1]],file="cluster1_complete_enrichment.txt", + append = FALSE, quote = FALSE, sep ="\t", row.names=FALSE)} + } \references{ -Chen E.Y., Christopher M.T., Yan K., Qiaonan D., Zichen W., Gabriela V.M., Neil R.C., -and Avi M. (2013) Enrichr: Interactive and Collaborative Html5 Gene List Enrichment +Chen E.Y., Christopher M.T., Yan K., Qiaonan D., Zichen W., Gabriela V.M., Neil R.C., +and Avi M. (2013) Enrichr: Interactive and Collaborative Html5 Gene List Enrichment Analysis Tool. \emph{BMC Bioinformatics} 14 (1). BioMed Central: 1. Alexa A. and Rahnenfuhrer J. (2009). topGO: Enrichment Analysis for Gene Ontology. diff --git a/man/plot.PCSF.Rd b/man/plot.PCSF.Rd index 93db5c8..1121b38 100644 --- a/man/plot.PCSF.Rd +++ b/man/plot.PCSF.Rd @@ -4,49 +4,60 @@ \alias{plot.PCSF} \title{Plot an interactive subnetwork} \usage{ -\method{plot}{PCSF}(x, style = 0, edge_width = 5, node_size = 40, - node_label_cex = 30, Steiner_node_color = "lightblue", - Terminal_node_color = "lightgreen", Terminal_node_legend = "Terminal", - Steiner_node_legend = "Steiner", ...) +\method{plot}{PCSF}( + x, + style = 0, + edge_width = 5, + node_size = 40, + node_label_cex = 30, + Steiner_node_color = "lightblue", + Terminal_node_color = "lightgreen", + Terminal_node_legend = "Terminal", + Steiner_node_legend = "Steiner", + extra_node_colors = list(), + ... +) } \arguments{ -\item{x}{A subnetwork obtained by the PCSF method. It is a "PCSF" object derived +\item{x}{A subnetwork obtained by the PCSF method. It is a "PCSF" object derived from \pkg{igraph} class and it has the edge cost and vertex prize attributes.} -\item{style}{A \code{boolean} value to determine the visualization style of the network, -where \code{0} plots the \code{static} network and \code{1} plots the \code{dynamic} +\item{style}{A \code{boolean} value to determine the visualization style of the network, +where \code{0} plots the \code{static} network and \code{1} plots the \code{dynamic} network. The default valu is 0.} -\item{edge_width}{A \code{numeric} value to emphasize a maximum edge width. A default value is 5. +\item{edge_width}{A \code{numeric} value to emphasize a maximum edge width. A default value is 5. This value must be greater than 1.} -\item{node_size}{A \code{numeric} value to emphasize a maximum node size. A default value is 40. +\item{node_size}{A \code{numeric} value to emphasize a maximum node size. A default value is 40. This value must be greater than 10.} \item{node_label_cex}{A \code{numeric} value to set a node label size. A default value is 30.} -\item{Steiner_node_color}{A \code{string} to set a color for \code{Steiner} nodes. +\item{Steiner_node_color}{A \code{string} to set a color for \code{Steiner} nodes. A default value is "lightblue".} \item{Terminal_node_color}{A \code{string} to set a color for \code{terminal} nodes.} -\item{Terminal_node_legend}{A \code{string} to set a legend for \code{terminal} nodes. +\item{Terminal_node_legend}{A \code{string} to set a legend for \code{terminal} nodes. A default legend is "Terminal".} -\item{Steiner_node_legend}{A \code{string} to set a legend for \code{Steiner} nodes. +\item{Steiner_node_legend}{A \code{string} to set a legend for \code{Steiner} nodes. A default legend is "Steiner".} +\item{extra_node_colors}{A \code{list} with colors of extra types of nodes added to the PCSF result, with the names of the list being the node type} + \item{...}{Ignored.} } \description{ -\code{plot.PCSF} plots an interactive figure of the subnetwork obrained by +\code{plot.PCSF} plots an interactive figure of the subnetwork obrained by the PCSF method. } \details{ -This function plots an interactive subnetwork obtained by the \code{\link{PCSF}} and \code{\link{PCSF_rand}}. -The node sizes and edge widths are respectively proportional to the node prizes and edge costs -while plotting the subnetwork from \code{\link{PCSF}}. In contrast, the node sizes and edge widths are -proportional to the total number of abondance in randomized runs while plotting the subnetwork +This function plots an interactive subnetwork obtained by the \code{\link{PCSF}} and \code{\link{PCSF_rand}}. +The node sizes and edge widths are respectively proportional to the node prizes and edge costs +while plotting the subnetwork from \code{\link{PCSF}}. In contrast, the node sizes and edge widths are +proportional to the total number of abondance in randomized runs while plotting the subnetwork from \code{\link{PCSF_rand}}. The node names are displayed during the hover-over. } \examples{ diff --git a/man/plot.PCSFe.Rd b/man/plot.PCSFe.Rd index 791f418..b5845d9 100644 --- a/man/plot.PCSFe.Rd +++ b/man/plot.PCSFe.Rd @@ -4,9 +4,16 @@ \alias{plot.PCSFe} \title{Plot an interactive subnetwork with functional enrichment analysis} \usage{ -\method{plot}{PCSFe}(x, edge_width = 5, node_size = 30, - node_label_cex = 1, Terminal_node_legend = "Terminal", - Steiner_node_legend = "Steiner", ...) +\method{plot}{PCSFe}( + x, + edge_width = 5, + node_size = 30, + node_label_cex = 1, + Terminal_node_legend = "Terminal", + Steiner_node_legend = "Steiner", + extra_node_colors = list(), + ... +) } \arguments{ \item{x}{An output subnetwork provided by the \code{enrichment_analysis}. @@ -22,12 +29,14 @@ A default value is 30. This value must be greater than 10.} \item{node_label_cex}{A \code{numeric} value to set a node label size. A default value is 1.} -\item{Terminal_node_legend}{A \code{string} to set a legend for \code{terminal} nodes. -A default legend is "Terminal".} +\item{Terminal_node_legend}{A \code{string} to set a legend for \code{terminal} nodes.} \item{Steiner_node_legend}{A \code{string} to set a legend for \code{Steiner} nodes. A default legend is "Steiner".} +\item{extra_node_colors}{A \code{list} with colors of extra types of nodes added to the PCSF result, with the names of the list being the node type +A default legend is "Terminal".} + \item{...}{Ignored.} } \description{ diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index ec84c3a..20cf3f5 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -5,6 +5,11 @@ using namespace Rcpp; +#ifdef RCPP_USE_GLOBAL_ROSTREAM +Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); +Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); +#endif + // call_sr List call_sr(CharacterVector from, CharacterVector to, NumericVector cost, CharacterVector node_names, NumericVector node_prizes); RcppExport SEXP _PCSF_call_sr(SEXP fromSEXP, SEXP toSEXP, SEXP costSEXP, SEXP node_namesSEXP, SEXP node_prizesSEXP) { From 45d8486df2b071695bc72c234d98bf8cb18febed Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 18:59:15 -0400 Subject: [PATCH 03/13] build: add a `.pre-commit-config.yaml` Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- .Rbuildignore | 8 +- .pre-commit-config.yaml | 140 ++++++++++++++++ DESCRIPTION | 42 +++-- LICENSE | 27 +--- LICENSE.md | 21 +++ R/PCSF.R | 157 +++++++++--------- R/PCSF_rand.R | 300 +++++++++++++++++------------------ R/call_enr.R | 257 +++++++++++++++--------------- R/construct_interactome.R | 57 +++---- R/data_interactome.R | 22 +-- R/data_phosphoproteomics.R | 26 +-- R/enrichment_analysis.R | 171 ++++++++++---------- R/plot.PCSF.R | 251 +++++++++++++++-------------- R/plot.PCSFe.R | 180 +++++++++++---------- codemeta.json | 187 ++++++++++++++++++++++ inst/WORDLIST | 100 ++++++++++++ man/PCSF.Rd | 3 +- man/PCSF_rand.Rd | 23 +-- man/STRING.Rd | 4 +- man/Tgfb_phospho.Rd | 6 +- man/construct_interactome.Rd | 7 +- man/enrichment_analysis.Rd | 13 +- man/plot.PCSF.Rd | 3 +- man/plot.PCSFe.Rd | 41 ++--- renv.lock | 120 ++++++++++++++ vignettes/PCSF-manual.Rmd | 62 ++++---- 26 files changed, 1410 insertions(+), 818 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 LICENSE.md create mode 100644 codemeta.json create mode 100644 inst/WORDLIST diff --git a/.Rbuildignore b/.Rbuildignore index d821302..ff875cb 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,4 +1,8 @@ -^renv$ -^renv\.lock$ ^.*\.Rproj$ +^HISTORY\.rst$ +^LICENSE\.md$ ^\.Rproj\.user$ +^\.pre-commit-config\.yaml$ +^codemeta\.json$ +^renv$ +^renv\.lock$ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..db6d09b --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,140 @@ +# All available hooks: https://pre-commit.com/hooks.html +# R specific hooks: https://github.com/lorenzwalthert/precommit +exclude: '.*\.(csv|tsv|xls)$' +repos: +- repo: https://github.com/lorenzwalthert/precommit + rev: v0.4.3 + hooks: + - id: use-tidy-description + - id: codemeta-description-updated + - id: spell-check + exclude: > + (?x)^( + .*\.[rR]| + .*\.feather| + .*\.jpeg| + .*\.pdf| + .*\.png| + .*\.py| + .*\.RData| + .*\.rd(s|a)| + .*\.Rd(s|a)| + .*\.RD(S|A)| + .*\.Rproj| + .*\.sh| + (.*/|)\.gitignore| + (.*/|)\.gitlab-ci\.yml| + (.*/|)\.lintr| + (.*/|)\.pre-commit-.*| + (.*/|)\.Rbuildignore| + (.*/|)\.Renviron| + (.*/|)\.Rprofile| + (.*/|)\.travis\.yml| + (.*/|)appveyor\.yml| + (.*/|)NAMESPACE| + (.*/|)renv/settings\.dcf| + (.*/|)renv\.lock| + (.*/|)WORDLIST| + \.github/workflows/.*| + data/.*| + .*\.(gz|xz|bz2)| + (.*/|)codemeta.json| + COMMIT_EDITMSG + )$ + - id: readme-rmd-rendered + - id: parsable-R + - id: no-browser-statement + - id: no-debug-statement + - id: deps-in-desc +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-added-large-files + args: ['--maxkb=500'] + - id: file-contents-sorter + files: '^\.Rbuildignore$' + - id: end-of-file-fixer + exclude: '\.Rd' + - id: check-json + - id: check-merge-conflict + - id: mixed-line-ending + args: + - --fix=no + - id: trailing-whitespace + - id: no-commit-to-branch + args: + - --branch + - devel + - --branch + - RELEASE.* +- repo: https://github.com/compilerla/conventional-pre-commit + rev: v3.6.0 + hooks: + - args: + - build + - chore + - ci + - docs + - feat + - fix + - perf + - refactor + - revert + - style + - test + - bump + id: conventional-pre-commit + stages: + - commit-msg +- repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.5.5 + hooks: + - id: forbid-crlf + - id: remove-crlf + - id: forbid-tabs + exclude: '.*\.[xls|tsv]$' + - id: remove-tabs + exclude: '.*\.[xls|tsv]$' +- repo: local + hooks: + - id: style_files + name: Apply bioconductor style + entry: > + Rscript --vanilla -e "styler::style_pkg(transformers = styler::tidyverse_style(indent_by = 4))" + language: system + - id: lint_files + name: Apply lintr + entry: > + Rscript --vanilla -e "lintr::lint_package()" + language: system + - id: forbid-to-commit + name: Don't commit common R artifacts + entry: Cannot commit .Rhistory, .RData, .Rds or .rds. + language: fail + files: '\.(Rhistory|RData|Rds|rds)$' + - id: bump-version + name: Bump version + entry: > + ./utilities/bump-version.sh + language: system + always_run: true + pass_filenames: false + stages: + - pre-commit + - id: codemeta-json-updated + name: Update codemeta.json + entry: > + Rscript --vanilla -e "codemetar::write_codemeta()" + language: system + files: DESCRIPTION + stages: + - pre-commit + - id: create-version-tag + name: Create Version Tag + entry: > + ./utilities/create_tag.sh + language: system + pass_filenames: false + always_run: true + stages: + - post-commit diff --git a/DESCRIPTION b/DESCRIPTION index 0999724..b8d42e8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,25 +1,35 @@ -Package: PCSF Type: Package +Package: PCSF Title: Network-based interpretation of highthroughput data Version: 0.99.1 Date: 2017-02-01 -Author: Murodzhon Akhmedov, Amanda Kedaigle, Renan Escalante, Roberto Montemanni, Francesco Bertoni, Ernest Fraenkel, Ivo Kwee +Author: Murodzhon Akhmedov, Amanda Kedaigle, Renan Escalante, Roberto + Montemanni, Francesco Bertoni, Ernest Fraenkel, Ivo Kwee Maintainer: Murodzhon Akhmedov -Description: The PCSF package performs an integrated analysis of highthroughput data using the interaction networks as a template, and interprets the biological landscape of interaction networks with respect to the data, which potentially leads to predictions of functional units. It also interactively visualize the resulting subnetwork with functional enrichment analysis. +Description: The PCSF package performs an integrated analysis of + highthroughput data using the interaction networks as a template, and + interprets the biological landscape of interaction networks with + respect to the data, which potentially leads to predictions of + functional units. It also interactively visualize the resulting + subnetwork with functional enrichment analysis. License: MIT + file LICENSE -Suggests: - knitr, - rmarkdown Depends: - R (>= 3.1.0), - igraph, - visNetwork, + igraph, + R (>= 3.1.0), + visNetwork Imports: - BH, - httr, - methods, - org.Hs.eg.db, - Rcpp, - topGO -LinkingTo: Rcpp, BH + BH, + dplyr, + httr, + methods, + org.Hs.eg.db, + Rcpp, + topGO +Suggests: + knitr, + rmarkdown +LinkingTo: + BH, + Rcpp +Encoding: UTF-8 RoxygenNote: 7.3.2 diff --git a/LICENSE b/LICENSE index 6740318..183cf66 100644 --- a/LICENSE +++ b/LICENSE @@ -1,25 +1,2 @@ - -Copyright (c) <2017>, - -************************************************************************ - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -************************************************************************ \ No newline at end of file +YEAR: 2024 +COPYRIGHT HOLDER: PCSF authors diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..6fe3a46 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 PCSF authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/R/PCSF.R b/R/PCSF.R index 62265a7..0a40634 100644 --- a/R/PCSF.R +++ b/R/PCSF.R @@ -66,7 +66,8 @@ #' data("Tgfb_phospho") #' terminals <- Tgfb_phospho #' ppi <- construct_interactome(STRING) -#' subnet <- PCSF(ppi, terminals, w = 2, b = 1, mu = 0.0005)} +#' subnet <- PCSF(ppi, terminals, w = 2, b = 1, mu = 0.0005) +#' } #' #' @author Murodzhon Akhmedov #' @@ -79,107 +80,107 @@ PCSF <- -function(ppi, terminals, w = 2, b = 1, mu = 0.0005, dummies){ - - # Checking function arguments - if (missing(ppi)) - stop("Need to specify an interaction network \"ppi\".") - if (class(ppi) != "igraph") - stop("The interaction network \"ppi\" must be an igraph object.") - if (missing(terminals)) - stop(" Need to provide terminal nodes as a named numeric vector, + function(ppi, terminals, w = 2, b = 1, mu = 0.0005, dummies) { + # Checking function arguments + if (missing(ppi)) { + stop("Need to specify an interaction network \"ppi\".") + } + if (class(ppi) != "igraph") { + stop("The interaction network \"ppi\" must be an igraph object.") + } + if (missing(terminals)) { + stop(" Need to provide terminal nodes as a named numeric vector, where node names must be same as in the interaction network.") - if(is.null(names(terminals))) - stop(" The terminal nodes must be provided as a named numeric vector, + } + if (is.null(names(terminals))) { + stop(" The terminal nodes must be provided as a named numeric vector, where node names must be same as in the interaction network.") + } - # Gather the terminal genes to be analyzed, and their scores - terminal_names = names(terminals) - terminal_values = as.numeric(terminals) + # Gather the terminal genes to be analyzed, and their scores + terminal_names <- names(terminals) + terminal_values <- as.numeric(terminals) - # Incorporate the node prizes - node_names = V(ppi)$name - node_prz = vector(mode = "numeric", length = length(node_names)) - index = match(terminal_names, node_names) - percent = signif((length(index) - sum(is.na(index)))/length(index)*100, 4) - if (percent < 5) - stop(" Less than 1% of your terminal nodes are matched in the interactome, check your terminals!") - cat(paste0(" ", percent, "% of your terminal nodes are included in the interactome\n")) - terminal_names = terminal_names[!is.na(index)] - terminal_values = terminal_values[!is.na(index)] - index = index[!is.na(index)] - node_prz[index] = terminal_values + # Incorporate the node prizes + node_names <- V(ppi)$name + node_prz <- vector(mode = "numeric", length = length(node_names)) + index <- match(terminal_names, node_names) + percent <- signif((length(index) - sum(is.na(index))) / length(index) * 100, 4) + if (percent < 5) { + stop(" Less than 1% of your terminal nodes are matched in the interactome, check your terminals!") + } + cat(paste0(" ", percent, "% of your terminal nodes are included in the interactome\n")) + terminal_names <- terminal_names[!is.na(index)] + terminal_values <- terminal_values[!is.na(index)] + index <- index[!is.na(index)] + node_prz[index] <- terminal_values - if(missing(dummies)||is.null(dummies)||is.na(dummies)) - dummies = terminal_names #re-assign this to allow for input + if (missing(dummies) || is.null(dummies) || is.na(dummies)) { + dummies <- terminal_names + } # re-assign this to allow for input - ## Prepare input file for MST-PCSF implementation in C++ + ## Prepare input file for MST-PCSF implementation in C++ - cat(" Solving the PCSF...\n") + cat(" Solving the PCSF...\n") - # Calculate the hub penalization scores - node_degrees = igraph::degree(ppi) - hub_penalization = - mu*node_degrees + # Calculate the hub penalization scores + node_degrees <- igraph::degree(ppi) + hub_penalization <- -mu * node_degrees - # Update the node prizes - node_prizes = b*node_prz - index = which(node_prizes==0) - node_prizes[index] = hub_penalization[index] + # Update the node prizes + node_prizes <- b * node_prz + index <- which(node_prizes == 0) + node_prizes[index] <- hub_penalization[index] - # Construct the list of edges - edges = ends(ppi,es = E(ppi)) - from = c(rep("DUMMY", length(dummies)), edges[,1]) - to = c(dummies, edges[,2]) + # Construct the list of edges + edges <- ends(ppi, es = E(ppi)) + from <- c(rep("DUMMY", length(dummies)), edges[, 1]) + to <- c(dummies, edges[, 2]) - cost = c(rep(w, length(dummies)), E(ppi)$weight) + cost <- c(rep(w, length(dummies)), E(ppi)$weight) - #PCSF will faill if there are NAs in weights, this will check and fail gracefully - if(any(is.na(E(ppi)$weight))){ + # PCSF will faill if there are NAs in weights, this will check and fail gracefully + if (any(is.na(E(ppi)$weight))) { - } + } - ## Feed the input into the PCSF algorithm - output = call_sr(from,to,cost,node_names,node_prizes) + ## Feed the input into the PCSF algorithm + output <- call_sr(from, to, cost, node_names, node_prizes) - # Check the size of output subnetwork and print a warning if it is 0 - if(length(output[[1]]) != 0){ + # Check the size of output subnetwork and print a warning if it is 0 + if (length(output[[1]]) != 0) { + # names(output) = c("from", "to", "cost", "terminal_names", "terminal_prizes") - #names(output) = c("from", "to", "cost", "terminal_names", "terminal_prizes") + # Contruct an igraph object from the MST-PCSF output + e <- data.frame(output[[1]], output[[2]], output[[3]]) + # e = e[which(e[,1]!="DUMMY"), ] + Ee <- e[which(e[, 2] != "DUMMY"), ] + names(e) <- c("from", "to", "weight") - # Contruct an igraph object from the MST-PCSF output - e = data.frame(output[[1]], output[[2]], output[[3]]) - #e = e[which(e[,1]!="DUMMY"), ] - Ee = e[which(e[,2]!="DUMMY"), ] - names(e) = c("from", "to", "weight") + # Differentiate the type of nodes + type <- rep("Steiner", length(output[[4]])) + index <- match(terminal_names, output[[4]]) + index <- index[!is.na(index)] + type[index] <- "Terminal" - # Differentiate the type of nodes - type = rep("Steiner", length(output[[4]])) - index = match(terminal_names, output[[4]]) - index = index[!is.na(index)] - type[index] = "Terminal" + v <- data.frame(output[[4]], output[[5]], type) + names(v) <- c("terminals", "prize", "type") + subnet <- graph.data.frame(e, vertices = v, directed = F) + E(subnet)$weight <- as.numeric(output[[3]]) + subnet <- delete_vertices(subnet, "DUMMY") + subnet <- delete_vertices(subnet, names(which(degree(subnet) == 0))) - v = data.frame(output[[4]], output[[5]], type) - names(v) = c("terminals", "prize", "type") - subnet = graph.data.frame(e,vertices=v,directed=F) - E(subnet)$weight=as.numeric(output[[3]]) - subnet = delete_vertices(subnet, "DUMMY") - subnet = delete_vertices(subnet, names(which(degree(subnet)==0))) + class(subnet) <- c("PCSF", "igraph") - class(subnet) <- c("PCSF", "igraph") - - return (subnet) - - } else{ - - stop(" Subnetwork can not be identified for a given parameter set. + return(subnet) + } else { + stop(" Subnetwork can not be identified for a given parameter set. Provide a compatible b or mu value with your terminal prize list...\n\n") - - } - -} + } + } diff --git a/R/PCSF_rand.R b/R/PCSF_rand.R index 3b58f42..8b8f8d5 100644 --- a/R/PCSF_rand.R +++ b/R/PCSF_rand.R @@ -1,34 +1,34 @@ #' Prize-collecting Steiner Forest (PCSF) with randomized edge costs #' -#' \code{PCSF_rand} returns a union of subnetworks obtained by solving the PCSF on the +#' \code{PCSF_rand} returns a union of subnetworks obtained by solving the PCSF on the #' given interaction network by adding a random noise to edge costs each time. #' @param ppi An interaction network as an \pkg{igraph} object. -#' @param terminals A list of terminal genes with prizes to be analyzed in the PCSF context. -#' A named \code{numeric} vector, where terminal genes are named same as in the interaction network +#' @param terminals A list of terminal genes with prizes to be analyzed in the PCSF context. +#' A named \code{numeric} vector, where terminal genes are named same as in the interaction network #' and numeric values correspond to the importance of the gene within the study. -#' @param n An \code{integer} value to determine the number of runs with random noise added edge costs. +#' @param n An \code{integer} value to determine the number of runs with random noise added edge costs. #' A default value is 10. -#' @param r A \code{numeric} value to determine additional random noise to edge costs. +#' @param r A \code{numeric} value to determine additional random noise to edge costs. #' A random noise upto r percent of the edge cost is added to each edge. A default value is 0.1 #' @param w A \code{numeric} value for tuning the number of trees in the output. A default value is 2. #' @param b A \code{numeric} value for tuning the node prizes. A default value is 1. #' @param mu A \code{numeric} value for a hub penalization. A default value is 0.0005. #' @param dummies A list of nodes that are to connected to the root of the tree. If missing the root will be connected to all terminals. -#' @return The final subnetwork obtained by taking the union of the PCSF outputs generated by -#' adding a random noise to edge costs each time. It returns an \pkg{igraph} object with the node prize +#' @return The final subnetwork obtained by taking the union of the PCSF outputs generated by +#' adding a random noise to edge costs each time. It returns an \pkg{igraph} object with the node prize #' and edge cost attributes representing the total number of show ups throughout all runs. #' @import igraph #' @export -#' -#' -#' @details -#' -#' In order to increase the robustness of the resulting structure, +#' +#' +#' @details +#' +#' In order to increase the robustness of the resulting structure, #' it is recommended to solve the PCSF several times on the same network -#' while adding some noise to the edge costs each time, and combine all results -#' in a final subnetwork. The union of all outputs may explain -#' the underlying biology better. -#' +#' while adding some noise to the edge costs each time, and combine all results +#' in a final subnetwork. The union of all outputs may explain +#' the underlying biology better. +#' #' @examples #' \dontrun{ #' library("PCSF") @@ -36,151 +36,151 @@ #' data("Tgfb_phospho") #' terminals <- Tgfb_phospho #' ppi <- construct_interactome(STRING) -#' subnet <- PCSF_rand(ppi, terminals, n = 10, r =0.1, w = 2, b = 2, mu = 0.0005)} -#' +#' subnet <- PCSF_rand(ppi, terminals, n = 10, r = 0.1, w = 2, b = 2, mu = 0.0005) +#' } +#' #' @author Murodzhon Akhmedov -#' +#' #' @seealso \code{\link{PCSF}}, \code{\link{plot.PCSFe}} -#' -#' @references +#' +#' @references #' Akhmedov M., LeNail A., Bertoni F., Kwee I., Fraenkel E., and Montemanni R. (2017) #' A Fast Prize-Collecting Steiner Forest Algorithm for Functional Analyses in Biological Networks. #' \emph{Lecture Notes in Computer Science}, to appear. PCSF_rand <- -function(ppi, terminals, n = 10, r = 0.1, w = 2, b = 1, mu = 0.0005,dummies){ - - # Checking function arguments - if (missing(ppi)) - stop("Need to specify an interaction network \"ppi\".") - if (class(ppi) != "igraph") - stop("The interaction network \"ppi\" must be an igraph object.") - if (missing(terminals)) - stop(" Need to provide terminal nodes as a named numeric vector, + function(ppi, terminals, n = 10, r = 0.1, w = 2, b = 1, mu = 0.0005, dummies) { + # Checking function arguments + if (missing(ppi)) { + stop("Need to specify an interaction network \"ppi\".") + } + if (class(ppi) != "igraph") { + stop("The interaction network \"ppi\" must be an igraph object.") + } + if (missing(terminals)) { + stop(" Need to provide terminal nodes as a named numeric vector, where node names must be same as in the interaction network.") - if(is.null(names(terminals))) - stop(" The terminal nodes must be provided as a named numeric vector, + } + if (is.null(names(terminals))) { + stop(" The terminal nodes must be provided as a named numeric vector, where node names must be same as in the interaction network.") + } + - - # Gather the terminal genes to be analyzed, and their scores - terminal_names = names(terminals) - terminal_values = as.numeric(terminals) - - # Incorporate the node prizes - node_names = V(ppi)$name - node_prz = vector(mode = "numeric", length = length(node_names)) - index = match(terminal_names, node_names) - percent = signif((length(index) - sum(is.na(index)))/length(index)*100, 4) - if (percent < 5) - stop(" Less than 1% of your terminal nodes are matched in the interactome, check your terminals!") - cat(paste0(" ", percent, "% of your terminal nodes are included in the interactome\n")) - terminal_names = terminal_names[!is.na(index)] - terminal_values = terminal_values[!is.na(index)] - index = index[!is.na(index)] - node_prz[index] = terminal_values - - ## Prepare input file for MST-PCSF implementation in C++ - if(missing(dummies)||is.null(dummies)||is.na(dummies)) - dummies = terminal_names #re-assign this to allow for input - - cat(" Solving the PCSF by adding random noise to the edge costs...\n") - - # Calculate the hub penalization scores - node_degrees = igraph::degree(ppi) - hub_penalization = - mu*node_degrees - - - # Update the node prizes - node_prizes = b*node_prz - index = which(node_prizes==0) - node_prizes[index] = hub_penalization[index] - - # Construct the list of edges - edges = ends(ppi,es = E(ppi)) - from = c(rep("DUMMY", length(dummies)), edges[,1]) - to = c(dummies, edges[,2]) - - all_nodes=NULL - - # Run the MST-PCSF algorithm for n times with random noise added to edge costs at each time - for(i in 1:n){ - - # Randomize the edge costs - cost = c(rep(w, length(dummies)), E(ppi)$weight + E(ppi)$weight*stats::runif(length(E(ppi)), 0, r)) - - # Feed in the input files into MSt-PCSF algorithm - output = call_sr(from,to,cost,node_names,node_prizes) - - # Construct an igraph object for current parameter set, and save it - edge = data.frame(as.character(output[[1]]),as.character(output[[2]])) - colnames(edge)= c("source", "target") - edge = edge[which(edge[,1]!="DUMMY"), ] - edge = edge[which(edge[,2]!="DUMMY"), ] - graph = graph.data.frame(edge,directed=F) - assign(paste0("graph_",i), get("graph")) - all_nodes = c(all_nodes, V(graph)$name) - } - - # Calculate graph statistics - node_frequency = table(all_nodes) - node_names = names(node_frequency) - node_prizes = as.numeric(node_frequency) - - # Combine the graphs in order to get unionized graph - adj_matrix = matrix(0, length(node_names), length(node_names)) - colnames(adj_matrix) = node_names - rownames(adj_matrix) = node_names - for(i in 1:n){ - assign("graph", get(paste0("graph_",i))) - edges = ends(graph,es = E(graph)) - x = match(edges[,1],node_names) - y = match(edges[,2],node_names) - if(length(x)>0 & length(y)>0){ - for( j in 1:length(x)){ - if(x[j]>=y[j]){ - k = x[j] - l = y[j] - }else{ - k = y[j] - l = x[j] + # Gather the terminal genes to be analyzed, and their scores + terminal_names <- names(terminals) + terminal_values <- as.numeric(terminals) + + # Incorporate the node prizes + node_names <- V(ppi)$name + node_prz <- vector(mode = "numeric", length = length(node_names)) + index <- match(terminal_names, node_names) + percent <- signif((length(index) - sum(is.na(index))) / length(index) * 100, 4) + if (percent < 5) { + stop(" Less than 1% of your terminal nodes are matched in the interactome, check your terminals!") } - adj_matrix[k,l] = adj_matrix[k,l]+1 - } - } - } - - # Check the size of output subnetwork and print a warning if it is 0 - if(sum(adj_matrix) != 0){ - - # Construct the igraph object from the union graph - subnet = graph_from_adjacency_matrix(adj_matrix, weighted=TRUE, mode="undirected") - index = match(V(subnet)$name, node_names) - V(subnet)$prize = node_prizes[index] - - # # Associate the type of nodes to shape - # V(subnet)$shape = "triangle" - # index = match(terminal_names, V(subnet)$name) - # index = index[!is.na(index)] - # V(subnet)$shape[index] = "circle" - - # Associate the type of nodes - V(subnet)$type = "Steiner" - index = match(terminal_names, V(subnet)$name) - index = index[!is.na(index)] - V(subnet)$type[index] = "Terminal" - - - class(subnet) <- c("PCSF", "igraph") - - return (subnet) - - } else { - - stop(" Subnetwork can not be identified for a given parameter set. - Provide a compatible b or mu value with your terminal prize list...\n\n") - } + cat(paste0(" ", percent, "% of your terminal nodes are included in the interactome\n")) + terminal_names <- terminal_names[!is.na(index)] + terminal_values <- terminal_values[!is.na(index)] + index <- index[!is.na(index)] + node_prz[index] <- terminal_values + + ## Prepare input file for MST-PCSF implementation in C++ + if (missing(dummies) || is.null(dummies) || is.na(dummies)) { + dummies <- terminal_names + } # re-assign this to allow for input + + cat(" Solving the PCSF by adding random noise to the edge costs...\n") + + # Calculate the hub penalization scores + node_degrees <- igraph::degree(ppi) + hub_penalization <- -mu * node_degrees -} + # Update the node prizes + node_prizes <- b * node_prz + index <- which(node_prizes == 0) + node_prizes[index] <- hub_penalization[index] + + # Construct the list of edges + edges <- ends(ppi, es = E(ppi)) + from <- c(rep("DUMMY", length(dummies)), edges[, 1]) + to <- c(dummies, edges[, 2]) + + all_nodes <- NULL + + # Run the MST-PCSF algorithm for n times with random noise added to edge costs at each time + for (i in 1:n) { + # Randomize the edge costs + cost <- c(rep(w, length(dummies)), E(ppi)$weight + E(ppi)$weight * stats::runif(length(E(ppi)), 0, r)) + + # Feed in the input files into MSt-PCSF algorithm + output <- call_sr(from, to, cost, node_names, node_prizes) + + # Construct an igraph object for current parameter set, and save it + edge <- data.frame(as.character(output[[1]]), as.character(output[[2]])) + colnames(edge) <- c("source", "target") + edge <- edge[which(edge[, 1] != "DUMMY"), ] + edge <- edge[which(edge[, 2] != "DUMMY"), ] + graph <- graph.data.frame(edge, directed = F) + assign(paste0("graph_", i), get("graph")) + all_nodes <- c(all_nodes, V(graph)$name) + } + + # Calculate graph statistics + node_frequency <- table(all_nodes) + node_names <- names(node_frequency) + node_prizes <- as.numeric(node_frequency) + + # Combine the graphs in order to get unionized graph + adj_matrix <- matrix(0, length(node_names), length(node_names)) + colnames(adj_matrix) <- node_names + rownames(adj_matrix) <- node_names + for (i in 1:n) { + assign("graph", get(paste0("graph_", i))) + edges <- ends(graph, es = E(graph)) + x <- match(edges[, 1], node_names) + y <- match(edges[, 2], node_names) + if (length(x) > 0 & length(y) > 0) { + for (j in 1:length(x)) { + if (x[j] >= y[j]) { + k <- x[j] + l <- y[j] + } else { + k <- y[j] + l <- x[j] + } + adj_matrix[k, l] <- adj_matrix[k, l] + 1 + } + } + } + + # Check the size of output subnetwork and print a warning if it is 0 + if (sum(adj_matrix) != 0) { + # Construct the igraph object from the union graph + subnet <- graph_from_adjacency_matrix(adj_matrix, weighted = TRUE, mode = "undirected") + index <- match(V(subnet)$name, node_names) + V(subnet)$prize <- node_prizes[index] + + # # Associate the type of nodes to shape + # V(subnet)$shape = "triangle" + # index = match(terminal_names, V(subnet)$name) + # index = index[!is.na(index)] + # V(subnet)$shape[index] = "circle" + + # Associate the type of nodes + V(subnet)$type <- "Steiner" + index <- match(terminal_names, V(subnet)$name) + index <- index[!is.na(index)] + V(subnet)$type[index] <- "Terminal" + + + class(subnet) <- c("PCSF", "igraph") + + return(subnet) + } else { + stop(" Subnetwork can not be identified for a given parameter set. + Provide a compatible b or mu value with your terminal prize list...\n\n") + } + } diff --git a/R/call_enr.R b/R/call_enr.R index 4762c1f..b8deb49 100644 --- a/R/call_enr.R +++ b/R/call_enr.R @@ -10,144 +10,145 @@ #' @param mode A binary variable to choose the method for enrichment analysis, where 0 is for EnrichR API and 1 is for \pkg{topGO} package. #' @param gene_universe A complete list of genes (vector of gene symbols) used as background in enrichment analysis by \pkg{topGO} package. -call_enr <- function(clusters, mode=0, gene_universe){ - - if( mode == 0){ - - # Enrichment analysis is performed with ENRICHR - ENRICHR_ADDLIST = 'http://amp.pharm.mssm.edu/Enrichr/addList' - ENRICHR_EXPORT = 'http://amp.pharm.mssm.edu/Enrichr/export' - - # The list of databases to be checked in Enrichment Analysis - database = c("GO_Biological_Process_2015","KEGG_2016", "Reactome_2016", "BioCarta_2016") - - # Enrichment results - enrichment_result = as.list(1:length(clusters)) - enrichment_result_complete = as.list(1:length(clusters)) - - # Perform Enrichment Analysis for each cluster in the forest - for( a in 1:length(clusters)){ - - # List of genes to be regusted for enrichment via ENRICHR API - genes = clusters[[a]] - request = list(list = paste(genes, collapse = "\n")) - complete_request = POST(ENRICHR_ADDLIST, body = request) - output =content(complete_request, "text", encoding = "ISO-8859-1") - userListID = strsplit(strsplit(output, "\n")[[1]][3], ": ")[[1]][2] - - response_collection=NULL - - # Request enrichment for each database and comnine them all - for( b in 1:length(database)){ - - # Gather an EXPORT URL and the Response - url = paste0(ENRICHR_EXPORT, "?userListId=",userListID, "&backgroundType=", database[b]) - response = GET(url) - response = content(response, "text", encoding = "ISO-8859-1") - response = strsplit(response, "\n")[[1]] - # if(length(unlist(response ))==1) - # next - response = lapply(response, function(x){sp = strsplit(x, "\t")[[1]]; return (sp)}) - - # If the response contains some elements then combine it - if(length(response)>1){ - x = length(response)-1 - m_resp = as.data.frame(matrix(0, nrow = x, ncol = length(response[[1]]))) - colnames(m_resp) = response[[1]] - for(i in 1:x){ - m_resp[i,] = response[[i+1]] - } - response_collection = rbind(response_collection,m_resp) - } - } - - - if(is.null(response_collection)) - next - # Reorder the enrichment according to the "Adjusted P-value" and select the top 15 enrichments - ordered_resp = data.frame(response_collection$`Term`, response_collection$`Adjusted P-value`, response_collection$`Combined Score`) - ordered_resp = ordered_resp[order(ordered_resp[,2]),][1:15,] - ordered_resp[,2] = signif(as.numeric(as.character(ordered_resp[,2])), 3) - ordered_resp[,3] = signif(as.numeric(as.character(ordered_resp[,3])), 3) - - # Convert the enrichment table into HTML format in order to display it - enrich = " - "; - for(i in 1:nrow(ordered_resp)){ - enrich = paste0(enrich, " ") - for(j in 1:ncol(ordered_resp)){ - enrich = paste0(enrich, "") +
Term Adjusted P-value Combined Score
",ordered_resp[i,j], "
" + for (i in 1:nrow(ordered_resp)) { + enrich <- paste0(enrich, " ") + for (j in 1:ncol(ordered_resp)) { + enrich <- paste0(enrich, "") + } + enrich <- paste0(enrich, " ") + } + enrich <- paste0(enrich, "
Term Adjusted P-value Combined Score
", ordered_resp[i, j], "
") + + # Attach the Enrichment Analysis for the current cluster + enrichment_result[[a]] <- enrich + enrichment_result_complete[[a]] <- response_collection } - enrich = paste0(enrich, " ") - } - enrich = paste0(enrich, " ") - - # Attach the Enrichment Analysis for the current cluster - enrichment_result[[a]] = enrich - enrichment_result_complete[[a]] = response_collection - } - - } else{ - - # Enrichment analysis is performed by topGO - - # Enrichment results - enrichment_result = as.list(1:length(clusters)) - enrichment_result_complete = as.list(1:length(clusters)) - - # Perform Enrichment Analysis for each cluster in the forest - for( a in 1:length(clusters)){ - - # List of genes to be regusted for enrichment by topGO - genes = clusters[[a]] - fg <- factor(as.integer(gene_universe %in% genes)) - names(fg) <- gene_universe - tgData <- new("topGOdata", description = "simple_session", ontology = "BP", - allGenes=fg, nodeSize=15, annot=annFUN.org, mapping = "org.Hs.eg.db", ID = "symbol") - - resultFisher <- runTest(tgData, algorithm = "classic", statistic = "fisher") - resultKS <- runTest(tgData, algorithm = "classic", statistic = "ks") - - res_table_top15 <- GenTable(tgData, classicFisher = resultFisher, - classicKS = resultKS, - orderBy = "classicFisher", ranksOf = "classicFisher", topNodes = 15) - res_table_top1000 <- GenTable(tgData, classicFisher = resultFisher, - classicKS = resultKS, - orderBy = "classicFisher", ranksOf = "classicFisher", topNodes = 1000) - - - # Reorder the enrichment according to the "Adjusted P-value" and select the top 15 enrichments - #ordered_resp[,2] = signif(as.numeric(as.character(ordered_resp[,2])), 3) - #ordered_resp[,3] = signif(as.numeric(as.character(ordered_resp[,3])), 3) - - # Convert the enrichment table into HTML format in order to display it - enrich = " - "; - for(i in 1:nrow(res_table_top15)){ - enrich = paste0(enrich, " ") - for(j in 1:ncol(res_table_top15)){ - enrich = paste0(enrich, "") +
GO.ID Term Annotated Significant Expected classicFisher classicKS
",res_table_top15[i,j], "
" + for (i in 1:nrow(res_table_top15)) { + enrich <- paste0(enrich, " ") + for (j in 1:ncol(res_table_top15)) { + enrich <- paste0(enrich, "") + } + enrich <- paste0(enrich, " ") + } + enrich <- paste0(enrich, "
GO.ID Term Annotated Significant Expected classicFisher classicKS
", res_table_top15[i, j], "
") + + # Attach the Enrichment Analysis for the current cluster + enrichment_result[[a]] <- enrich + enrichment_result_complete[[a]] <- res_table_top1000 } - enrich = paste0(enrich, " ") - } - enrich = paste0(enrich, " ") - - # Attach the Enrichment Analysis for the current cluster - enrichment_result[[a]] = enrich - enrichment_result_complete[[a]] = res_table_top1000 - } - - } - + } - return (list(enrichment_result, enrichment_result_complete)) + return(list(enrichment_result, enrichment_result_complete)) } diff --git a/R/construct_interactome.R b/R/construct_interactome.R index b55f3b0..65e0ec6 100644 --- a/R/construct_interactome.R +++ b/R/construct_interactome.R @@ -1,47 +1,48 @@ #' Construct an interaction network #' -#' Given a list of edges, \code{construct_interactome} generates +#' Given a list of edges, \code{construct_interactome} generates #' an interaction network which is used as a template network to interpret the highthrougput data. -#' +#' #' @param ppi A list of edges. A \code{data.frame} composed of three columns, where each -#' row corresponds to an edge in which the first element is a \code{head}, the second +#' row corresponds to an edge in which the first element is a \code{head}, the second #' element is a \code{tail}, and the last element represents the \code{cost} of the edge. -#' +#' #' @return An interaction network as \pkg{igraph} object. #' @import igraph #' @export -#' -#' @examples +#' +#' @examples #' \dontrun{ #' library("PCSF") #' data("STRING") -#' ppi <- construct_interactome(STRING)} -#' +#' ppi <- construct_interactome(STRING) +#' } +#' #' @author Murodzhon Akhmedov -#' +#' construct_interactome <- -function(ppi){ - - # Checking function arguments - if (missing(ppi)) - stop(" Need to specify a list of edges to construct an interaction network. - Provide a data.frame composed of three columns, where each row corresponds - to an edge in which the first element is a head node, the second element + function(ppi) { + # Checking function arguments + if (missing(ppi)) { + stop(" Need to specify a list of edges to construct an interaction network. + Provide a data.frame composed of three columns, where each row corresponds + to an edge in which the first element is a head node, the second element is a tail node, and the last element represents the cost of the edge.") - if (nrow(ppi)<1 || ncol(ppi) != 3 || class(ppi) != "data.frame") - stop(" Need to provide a data.frame composed of three columns, where each row corresponds - to an edge in which the first element is a head node, the second element + } + if (nrow(ppi) < 1 || ncol(ppi) != 3 || class(ppi) != "data.frame") { + stop(" Need to provide a data.frame composed of three columns, where each row corresponds + to an edge in which the first element is a head node, the second element is a tail node, and the last element represents the cost of the edge.") + } - # Interpolate the node prizes - node_names = unique(c(as.character(ppi[,1]),as.character(ppi[,2]))) - - # Contruct an interaction network as igraph object - ppi.graph = graph.data.frame(ppi[,1:2],vertices=node_names,directed=F) - E(ppi.graph)$weight=as.numeric(ppi[,3]) - ppi.graph = simplify(ppi.graph) + # Interpolate the node prizes + node_names <- unique(c(as.character(ppi[, 1]), as.character(ppi[, 2]))) - return (ppi.graph) + # Contruct an interaction network as igraph object + ppi.graph <- graph.data.frame(ppi[, 1:2], vertices = node_names, directed = F) + E(ppi.graph)$weight <- as.numeric(ppi[, 3]) + ppi.graph <- simplify(ppi.graph) -} + return(ppi.graph) + } diff --git a/R/data_interactome.R b/R/data_interactome.R index 43bf793..ad24a5b 100644 --- a/R/data_interactome.R +++ b/R/data_interactome.R @@ -1,18 +1,18 @@ -#' Protein-protein interaction network data -#' +#' Protein-protein interaction network data +#' #' An interactome data set in which the nodes are named with gene symbols -#' +#' #' @name STRING -#' -#' @format A data frame with three variables, where each row corresponds to -#' an edge in which the first element is a \code{head}, the second +#' +#' @format A data frame with three variables, where each row corresponds to +#' an edge in which the first element is a \code{head}, the second #' element is a \code{tail}, and the last element represents the \code{cost} of the edge. -#' +#' #' @docType data #' @usage STRING -#' +#' #' @source iref_mitab_miscore_2013_08_12_interactome.txt \url{https://github.com/fraenkel-lab/OmicsIntegrator/tree/master/data} -#' +#' #' @keywords data -#' -NULL \ No newline at end of file +#' +NULL diff --git a/R/data_phosphoproteomics.R b/R/data_phosphoproteomics.R index 3bdb49a..5863da0 100644 --- a/R/data_phosphoproteomics.R +++ b/R/data_phosphoproteomics.R @@ -1,20 +1,20 @@ -#' Phosphoproteomic data -#' -#' This dataset contains differential phosphoproteomic data derived from H358 cells, +#' Phosphoproteomic data +#' +#' This dataset contains differential phosphoproteomic data derived from H358 cells, #' a model of lung cancer, that were stimulated with TGF-b. -#' +#' #' @name Tgfb_phospho -#' -#' @format A named \code{numeric} vector, where terminal genes are named same as -#' in the interaction network and numeric values correspond to the importance of +#' +#' @format A named \code{numeric} vector, where terminal genes are named same as +#' in the interaction network and numeric values correspond to the importance of #' the gene within the study. -#' +#' #' @docType data #' @usage Tgfb_phospho -#' +#' #' @source Tgfb_phos.txt \url{https://github.com/fraenkel-lab/OmicsIntegrator/tree/master/example/a549} -#' +#' #' @keywords data -#' -#' -NULL \ No newline at end of file +#' +#' +NULL diff --git a/R/enrichment_analysis.R b/R/enrichment_analysis.R index 87a7162..c6746ba 100644 --- a/R/enrichment_analysis.R +++ b/R/enrichment_analysis.R @@ -47,15 +47,20 @@ #' ppi <- construct_interactome(STRING) #' subnet <- PCSF_rand(ppi, terminals, n = 10, r = 0.1, w = 2, b = 1, mu = 0.0005) #' res <- enrichment_analysis(subnet) -#' res <- enrichment_analysis(subnet, mode=0)} +#' res <- enrichment_analysis(subnet, mode = 0) +#' } #' \dontrun{ #' library(topGO) #' gene_universe <- V(ppi)$name -#' res <- enrichment_analysis(subnet, mode=1, gene_universe)} +#' res <- enrichment_analysis(subnet, mode = 1, gene_universe) +#' } #' \dontrun{ #' plot(res$subnet) -#' write.table(res$enrichment[[1]],file="cluster1_complete_enrichment.txt", -#' append = FALSE, quote = FALSE, sep ="\t", row.names=FALSE)} +#' write.table(res$enrichment[[1]], +#' file = "cluster1_complete_enrichment.txt", +#' append = FALSE, quote = FALSE, sep = "\t", row.names = FALSE +#' ) +#' } #' #' @author Murodzhon Akhmedov #' @@ -71,100 +76,100 @@ #' Alexa A. and Rahnenfuhrer J. (2009). topGO: Enrichment Analysis for Gene Ontology. #' R package version 2.28.0. -enrichment_analysis <-function(subnet, mode=NULL, gene_universe){ - - # Checking function arguments - if (missing(subnet)) - stop("Need to specify the subnetwork obtained from the PCSF algorithm.") - if (class(subnet)[1] != "PCSF" || class(subnet)[2] != "igraph") - stop("The subnetwork must be a \"PCSF\" object derived from an \"igraph\" class.") - if (!is.null(mode)){ - if(mode==1 && missing(gene_universe)) - stop("Need to specify a list of genes (vector of gene symbols) used as background in enrichment analysis by topGO package") - } +enrichment_analysis <- function(subnet, mode = NULL, gene_universe) { + # Checking function arguments + if (missing(subnet)) { + stop("Need to specify the subnetwork obtained from the PCSF algorithm.") + } + if (class(subnet)[1] != "PCSF" || class(subnet)[2] != "igraph") { + stop("The subnetwork must be a \"PCSF\" object derived from an \"igraph\" class.") + } + if (!is.null(mode)) { + if (mode == 1 && missing(gene_universe)) { + stop("Need to specify a list of genes (vector of gene symbols) used as background in enrichment analysis by topGO package") + } + } - cat(" Performing enrichment analysis...\n\n") + cat(" Performing enrichment analysis...\n\n") - # Obtain clusters in the subnet using edge betweenness clustering algorithm from igraph package. - clusters = cluster_edge_betweenness(subnet) + # Obtain clusters in the subnet using edge betweenness clustering algorithm from igraph package. + clusters <- cluster_edge_betweenness(subnet) - # Perform ebrichment analysis for each cluster using EnrichR through its API or topGO. + # Perform ebrichment analysis for each cluster using EnrichR through its API or topGO. - havingInternet <- function() { - if (.Platform$OS.type == "windows") { - ipmessage <- system("ipconfig", intern = TRUE) - } else { - ipmessage <- system("ifconfig", intern = TRUE) + havingInternet <- function() { + if (.Platform$OS.type == "windows") { + ipmessage <- system("ipconfig", intern = TRUE) + } else { + ipmessage <- system("ifconfig", intern = TRUE) + } + validIP <- "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.]){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" + any(grep(validIP, ipmessage)) } - validIP <- "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.]){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" - any(grep(validIP, ipmessage)) - } - internet_connection <- havingInternet() + internet_connection <- havingInternet() - if(!is.null(mode)){ - if(mode==0){ - if(internet_connection){ - cat(" Enrichment is being performed by EnrichR (http://amp.pharm.mssm.edu/Enrichr) API ...\n") - enrich = call_enr(clusters, mode = 0, gene_universe) - } - else{ - stop("There is no working Internet connection, perform your enrichment with topGO package with mode=1 by providing background gene list ...\n") - } - } - else{ - cat(" Enrichment is being performed by topGO package ...\n") - enrich = call_enr(clusters, mode = mode, gene_universe) - } - } - else - { - if(internet_connection){ - cat(" Enrichment is being performed by EnrichR (http://amp.pharm.mssm.edu/Enrichr) API ...\n") - enrich = call_enr(clusters, mode = 0, gene_universe) - } - else{ - stop("There is no working Internet connection, perform your enrichment with topGO package with mode=1 by providing background gene list ...\n") + if (!is.null(mode)) { + if (mode == 0) { + if (internet_connection) { + cat(" Enrichment is being performed by EnrichR (http://amp.pharm.mssm.edu/Enrichr) API ...\n") + enrich <- call_enr(clusters, mode = 0, gene_universe) + } else { + stop("There is no working Internet connection, perform your enrichment with topGO package with mode=1 by providing background gene list ...\n") + } + } else { + cat(" Enrichment is being performed by topGO package ...\n") + enrich <- call_enr(clusters, mode = mode, gene_universe) + } + } else { + if (internet_connection) { + cat(" Enrichment is being performed by EnrichR (http://amp.pharm.mssm.edu/Enrichr) API ...\n") + enrich <- call_enr(clusters, mode = 0, gene_universe) + } else { + stop("There is no working Internet connection, perform your enrichment with topGO package with mode=1 by providing background gene list ...\n") + } } - } - if('Compound'%in% V(subnet)$type){##then we have drugs! + if ("Compound" %in% V(subnet)$type) { ## then we have drugs! require(dplyr) - comps=data.frame(Drug=V(subnet)$name[which(V(subnet)$type=='Compound')], - Cluster=clusters$membership[which(V(subnet)$type=='Compound')])%>% - dplyr::group_by(Cluster)%>% - dplyr::summarise(DrugsByBetweenness=paste(Drug,collapse=';')) - + comps <- data.frame( + Drug = V(subnet)$name[which(V(subnet)$type == "Compound")], + Cluster = clusters$membership[which(V(subnet)$type == "Compound")] + ) %>% + dplyr::group_by(Cluster) %>% + dplyr::summarise(DrugsByBetweenness = paste(Drug, collapse = ";")) + } else { + comps <- NULL } - else{ - comps <-NULL - } - enrichment = enrich[[1]] - enrichment_complete = enrich[[2]] + enrichment <- enrich[[1]] + enrichment_complete <- enrich[[2]] - novals<-which(unlist(sapply(enrich[[2]],function(x) is.null(dim(x))))) - if(length(novals)>0) + novals <- which(unlist(sapply(enrich[[2]], function(x) is.null(dim(x))))) + if (length(novals) > 0) { enrichment_complete <- enrichment_complete[-novals] - enrichment_tab = do.call(rbind,lapply(c(1:length(enrichment_complete)),function(x) data.frame(Cluster=x,enrichment_complete[[x]]))) - more.than.two=which(sapply(enrichment_tab$Genes,function(x) length(unlist(strsplit(x,split=';')))>2)) - if(length(more.than.two)>0) - enrichment_tab=enrichment_tab[more.than.two,] - if(!is.null(comps)) - enrichment_tab = enrichment_tab%>%dplyr::left_join(comps,by='Cluster') + } + enrichment_tab <- do.call(rbind, lapply(c(1:length(enrichment_complete)), function(x) data.frame(Cluster = x, enrichment_complete[[x]]))) + more.than.two <- which(sapply(enrichment_tab$Genes, function(x) length(unlist(strsplit(x, split = ";"))) > 2)) + if (length(more.than.two) > 0) { + enrichment_tab <- enrichment_tab[more.than.two, ] + } + if (!is.null(comps)) { + enrichment_tab <- enrichment_tab %>% dplyr::left_join(comps, by = "Cluster") + } - # Add 'group" and 'title' attributes to subnet - V(subnet)$group = clusters$membership - V(subnet)$title = paste0("Cluster ",clusters$membership,": Enrichment analysis") - for( i in 1:length(V(subnet))){ - V(subnet)$title[i] = paste0( V(subnet)$title[i], enrichment[[V(subnet)$group[i]]]) - } + # Add 'group" and 'title' attributes to subnet + V(subnet)$group <- clusters$membership + V(subnet)$title <- paste0("Cluster ", clusters$membership, ": Enrichment analysis") + for (i in 1:length(V(subnet))) { + V(subnet)$title[i] <- paste0(V(subnet)$title[i], enrichment[[V(subnet)$group[i]]]) + } - # Derive a "PCSFe" object from an "igraph" class. - class(subnet) <- c("PCSFe", "igraph") - # Combine the subnetwork and colplete enrichment analysis tables. - output = list(subnet, enrichment_tab) - names(output) = c("subnet", "enrichment") + # Derive a "PCSFe" object from an "igraph" class. + class(subnet) <- c("PCSFe", "igraph") + # Combine the subnetwork and colplete enrichment analysis tables. + output <- list(subnet, enrichment_tab) + names(output) <- c("subnet", "enrichment") - return (output) + return(output) } diff --git a/R/plot.PCSF.R b/R/plot.PCSF.R index fbfa47d..e61589c 100644 --- a/R/plot.PCSF.R +++ b/R/plot.PCSF.R @@ -42,136 +42,141 @@ #' terminals <- Tgfb_phospho #' ppi <- construct_interactome(STRING) #' subnet <- PCSF(ppi, terminals, w = 2, b = 1, mu = 0.0005) -#' plot(subnet)} +#' plot(subnet) +#' } #' #' @author Murodzhon Akhmedov #' #' @seealso \code{\link{PCSF}}, \code{\link{plot.PCSFe}} plot.PCSF <- -function(x, style = 0, edge_width=5, node_size=40, node_label_cex = 30, Steiner_node_color = "lightblue", - Terminal_node_color = "lightgreen", Terminal_node_legend = "Terminal", - Steiner_node_legend = "Steiner",extra_node_colors = list(),...){ - - subnet = x - # Checking function arguments - if (missing(subnet)) - stop("Need to specify the subnetwork obtained from the PCSF algorithm.") - if (class(subnet)[1] != "PCSF" || class(subnet)[2] != "igraph") - stop("The subnetwork must be a \"PCSF\" object derived from an \"igraph\" class.") - if (edge_width < 1) - stop("The edge_width must be greater than 1.") - if (node_size < 10) - stop("The node_size must be greater than 10.") - - # Calculate the adjusted node prizes - prize = abs(V(subnet)$prize) - min1 = 10 - max1 = node_size - r1 = max1 - min1 - min2 = min(prize) - max2 = max(prize) - r2 = max2 - min2 - adjusted_prize = r1*(prize - min2)/r2 + min1 - - # Calculate the adjusted edge weights - weight = E(subnet)$weight - min1 = 1 - max1 = edge_width - r1 = max1 - min1 - min2 = min(weight) - max2 = max(weight) - r2 = max2 - min2 - adjusted_weight = r1*(weight - min2)/r2 + min1 - - - if(style){ - - # List of nodes in the subnet - nodes = data.frame(1:length(V(subnet)), V(subnet)$name) - names(nodes) = c("id", "name") - - # Differentiate the type of nodes - nodes$group = V(subnet)$type - - # Attach the node attributes - nodes$size = adjusted_prize - nodes$title = nodes$name - nodes$label = nodes$name - nodes$label.cex = node_label_cex - nodes$font.size = node_label_cex - - # List of edges in the subnet - edges = data.frame(ends(subnet,es = E(subnet)), adjusted_weight) - names(edges) = c("from", "to", "width") - edges$from = match(edges$from, nodes$name) - edges$to = match(edges$to, nodes$name) - - # Visualize the subnet - visNet <-visNetwork(nodes,edges) %>% - visNodes( shadow = list(enabled = TRUE, size = 12)) %>% - visGroups(groupname = "Steiner", color = list(background = Steiner_node_color, border = "blue"), shape = "triangle") %>% - visGroups(groupname = "Terminal", color = list(background = Terminal_node_color, border = "green"), shape = "dot") - - #broke this out to accomodate extra node names - leg.groups<- list( - list(label = Terminal_node_legend, shape = "dot", size = 15, color = list(background = Terminal_node_color, border = "green"), label.cex = 0.8), - list(label = Steiner_node_legend, shape = "triangle",size = 10, color = list(background = Steiner_node_color, border = "blue"), label.cex = 0.8 )) - - if(length(extra_node_colors)>0){ - for(i in 1:length(extra_node_colors)){ - en=names(extra_node_colors)[i] - visNet <- visNet %>% visGroups(groupname=en,color=list(background = extra_node_colors[[en]],border='grey'),shape='triangle') - leg.groups[[i+2]]<-list(label=en,shape='triangle',size=13,color=list(background=extra_node_colors[[en]],border='grey'),label.cex=0.8) + function(x, style = 0, edge_width = 5, node_size = 40, node_label_cex = 30, Steiner_node_color = "lightblue", + Terminal_node_color = "lightgreen", Terminal_node_legend = "Terminal", + Steiner_node_legend = "Steiner", extra_node_colors = list(), ...) { + subnet <- x + # Checking function arguments + if (missing(subnet)) { + stop("Need to specify the subnetwork obtained from the PCSF algorithm.") + } + if (class(subnet)[1] != "PCSF" || class(subnet)[2] != "igraph") { + stop("The subnetwork must be a \"PCSF\" object derived from an \"igraph\" class.") + } + if (edge_width < 1) { + stop("The edge_width must be greater than 1.") + } + if (node_size < 10) { + stop("The node_size must be greater than 10.") } - } - - visNet<-visNet %>% visOptions(highlightNearest = list(enabled = T)) %>% - visLegend(addNodes =leg.groups, width = 0.15, - useGroups = FALSE) - - - } else{ - - # Attach the node type attribute - V(subnet)$group = V(subnet)$type - - # Attach the node attributes: size, title, label, label.cex, font size - V(subnet)$size = adjusted_prize - V(subnet)$title = V(subnet)$name - V(subnet)$label = V(subnet)$name - V(subnet)$label.cex = node_label_cex/30 - V(subnet)$font.size = node_label_cex/30 - - # Attach the edge width attribute - E(subnet)$width = adjusted_weight - - - # Visualize the subnet - visNet <- visIgraph(subnet) %>% - visIgraphLayout(layout = "layout_with_fr") %>% - visNodes( shadow = list(enabled = TRUE, size = 12)) %>% - visGroups(groupname = "Steiner", color = list(background = Steiner_node_color, border = "blue"), shape = "triangle") %>% - visGroups(groupname = "Terminal", color = list(background = Terminal_node_color, border = "green"), shape = "dot") - - leg.groups<- list( - list(label = Terminal_node_legend, shape = "dot", size = 15, color = list(background = Terminal_node_color, border = "green"), label.cex = 0.8), - list(label = Steiner_node_legend, shape = "triangle",size = 10, color = list(background = Steiner_node_color, border = "blue"), label.cex = 0.8 )) - - if(length(extra_node_colors)>0){ - for(i in 1:length(extra_node_colors)){ - en=names(extra_node_colors)[i] - visNet <- visNet %>% visGroups(groupname=en,color=list(background = extra_node_colors[[en]],border='grey'),shape='triangle') - leg.groups[[i+2]]<-list(label=en,shape='triangle',size=13,color=list(background=extra_node_colors[[en]],border='grey'),label.cex=0.8) + # Calculate the adjusted node prizes + prize <- abs(V(subnet)$prize) + min1 <- 10 + max1 <- node_size + r1 <- max1 - min1 + min2 <- min(prize) + max2 <- max(prize) + r2 <- max2 - min2 + adjusted_prize <- r1 * (prize - min2) / r2 + min1 + + # Calculate the adjusted edge weights + weight <- E(subnet)$weight + min1 <- 1 + max1 <- edge_width + r1 <- max1 - min1 + min2 <- min(weight) + max2 <- max(weight) + r2 <- max2 - min2 + adjusted_weight <- r1 * (weight - min2) / r2 + min1 + + + if (style) { + # List of nodes in the subnet + nodes <- data.frame(1:length(V(subnet)), V(subnet)$name) + names(nodes) <- c("id", "name") + + # Differentiate the type of nodes + nodes$group <- V(subnet)$type + + # Attach the node attributes + nodes$size <- adjusted_prize + nodes$title <- nodes$name + nodes$label <- nodes$name + nodes$label.cex <- node_label_cex + nodes$font.size <- node_label_cex + + # List of edges in the subnet + edges <- data.frame(ends(subnet, es = E(subnet)), adjusted_weight) + names(edges) <- c("from", "to", "width") + edges$from <- match(edges$from, nodes$name) + edges$to <- match(edges$to, nodes$name) + + # Visualize the subnet + visNet <- visNetwork(nodes, edges) %>% + visNodes(shadow = list(enabled = TRUE, size = 12)) %>% + visGroups(groupname = "Steiner", color = list(background = Steiner_node_color, border = "blue"), shape = "triangle") %>% + visGroups(groupname = "Terminal", color = list(background = Terminal_node_color, border = "green"), shape = "dot") + + # broke this out to accomodate extra node names + leg.groups <- list( + list(label = Terminal_node_legend, shape = "dot", size = 15, color = list(background = Terminal_node_color, border = "green"), label.cex = 0.8), + list(label = Steiner_node_legend, shape = "triangle", size = 10, color = list(background = Steiner_node_color, border = "blue"), label.cex = 0.8) + ) + + if (length(extra_node_colors) > 0) { + for (i in 1:length(extra_node_colors)) { + en <- names(extra_node_colors)[i] + visNet <- visNet %>% visGroups(groupname = en, color = list(background = extra_node_colors[[en]], border = "grey"), shape = "triangle") + leg.groups[[i + 2]] <- list(label = en, shape = "triangle", size = 13, color = list(background = extra_node_colors[[en]], border = "grey"), label.cex = 0.8) + } + } + + visNet <- visNet %>% + visOptions(highlightNearest = list(enabled = T)) %>% + visLegend( + addNodes = leg.groups, width = 0.15, + useGroups = FALSE + ) + } else { + # Attach the node type attribute + V(subnet)$group <- V(subnet)$type + + # Attach the node attributes: size, title, label, label.cex, font size + V(subnet)$size <- adjusted_prize + V(subnet)$title <- V(subnet)$name + V(subnet)$label <- V(subnet)$name + V(subnet)$label.cex <- node_label_cex / 30 + V(subnet)$font.size <- node_label_cex / 30 + + # Attach the edge width attribute + E(subnet)$width <- adjusted_weight + + + # Visualize the subnet + visNet <- visIgraph(subnet) %>% + visIgraphLayout(layout = "layout_with_fr") %>% + visNodes(shadow = list(enabled = TRUE, size = 12)) %>% + visGroups(groupname = "Steiner", color = list(background = Steiner_node_color, border = "blue"), shape = "triangle") %>% + visGroups(groupname = "Terminal", color = list(background = Terminal_node_color, border = "green"), shape = "dot") + + leg.groups <- list( + list(label = Terminal_node_legend, shape = "dot", size = 15, color = list(background = Terminal_node_color, border = "green"), label.cex = 0.8), + list(label = Steiner_node_legend, shape = "triangle", size = 10, color = list(background = Steiner_node_color, border = "blue"), label.cex = 0.8) + ) + + if (length(extra_node_colors) > 0) { + for (i in 1:length(extra_node_colors)) { + en <- names(extra_node_colors)[i] + visNet <- visNet %>% visGroups(groupname = en, color = list(background = extra_node_colors[[en]], border = "grey"), shape = "triangle") + leg.groups[[i + 2]] <- list(label = en, shape = "triangle", size = 13, color = list(background = extra_node_colors[[en]], border = "grey"), label.cex = 0.8) + } + } + + visNet <- visNet %>% + visOptions(highlightNearest = list(enabled = T)) %>% + visLegend( + addNodes = leg.groups, width = 0.10, + useGroups = FALSE + ) } + visNet } - - visNet <- visNet %>% visOptions(highlightNearest = list(enabled = T)) %>% - visLegend(addNodes =leg.groups, width = 0.10, - useGroups = FALSE) - -} - visNet - -} diff --git a/R/plot.PCSFe.R b/R/plot.PCSFe.R index 91c813b..6e4fd15 100644 --- a/R/plot.PCSFe.R +++ b/R/plot.PCSFe.R @@ -1,43 +1,43 @@ #' Plot an interactive subnetwork with functional enrichment analysis #' -#' \code{plot.PCSFe} plots an interactive figure of the subnetwork -#' to display the functionla enrichment analysis, which is obtained by employing +#' \code{plot.PCSFe} plots an interactive figure of the subnetwork +#' to display the functionla enrichment analysis, which is obtained by employing #' \code{enrichment_analysis} on the subnetwork. -#' -#' @param x An output subnetwork provided by the \code{enrichment_analysis}. -#' It is "PCSFe" object derived from an \pkg{igraph} class, and it has the edge +#' +#' @param x An output subnetwork provided by the \code{enrichment_analysis}. +#' It is "PCSFe" object derived from an \pkg{igraph} class, and it has the edge #' cost and vertex prize attributes. -#' @param edge_width A \code{numeric} value to emphasize a maximum edge width. +#' @param edge_width A \code{numeric} value to emphasize a maximum edge width. #' A default value is 5. This value must be greater than 1. -#' @param node_size A \code{numeric} value to emphasize a maximum node size. +#' @param node_size A \code{numeric} value to emphasize a maximum node size. #' A default value is 30. This value must be greater than 10. -#' @param node_label_cex A \code{numeric} value to set a node label size. +#' @param node_label_cex A \code{numeric} value to set a node label size. #' A default value is 1. -#' @param Steiner_node_legend A \code{string} to set a legend for \code{Steiner} nodes. +#' @param Steiner_node_legend A \code{string} to set a legend for \code{Steiner} nodes. #' A default legend is "Steiner". -#' @param Terminal_node_legend A \code{string} to set a legend for \code{terminal} nodes. +#' @param Terminal_node_legend A \code{string} to set a legend for \code{terminal} nodes. #' @param extra_node_colors A \code{list} with colors of extra types of nodes added to the PCSF result, with the names of the list being the node type #' A default legend is "Terminal". #' @param ... Ignored. #' @import igraph visNetwork #' @method plot PCSFe #' @export -#' -#' @details -#' -#' An enrichment analysis of the final subnetwork obtained by multiple runs of the PCSF -#' (with random noise added edge costs) is performed by using \code{\link{enrichment_analysis}}. -#' The subnetwork is clustered using an edge betweenness clustering algorithm from the -#' \pkg{igraph} package, and for each cluster functional enrichment is done by employing the -#' ENRICHR API (Chen \emph{et al.}, 2013). An interactive visualization of the final subnetwork -#' is plotted, where the node sizes and edge widths are proportional to the frequency of show -#' ups in total randomised runs. Nodes are colored according to the cluster membership, and -#' the top 15 functional enrichment terms are displayed in tabular format during the hover-over -#' of the node in that cluster. A specific cluster can be displayed separately in the figure +#' +#' @details +#' +#' An enrichment analysis of the final subnetwork obtained by multiple runs of the PCSF +#' (with random noise added edge costs) is performed by using \code{\link{enrichment_analysis}}. +#' The subnetwork is clustered using an edge betweenness clustering algorithm from the +#' \pkg{igraph} package, and for each cluster functional enrichment is done by employing the +#' ENRICHR API (Chen \emph{et al.}, 2013). An interactive visualization of the final subnetwork +#' is plotted, where the node sizes and edge widths are proportional to the frequency of show +#' ups in total randomised runs. Nodes are colored according to the cluster membership, and +#' the top 15 functional enrichment terms are displayed in tabular format during the hover-over +#' of the node in that cluster. A specific cluster can be displayed separately in the figure #' by selecting from the icon list at the top left side of the figure. -#' #' -#' @examples +#' +#' @examples #' \dontrun{ #' library("PCSF") #' data("STRING") @@ -46,73 +46,79 @@ #' ppi <- construct_interactome(STRING) #' subnet <- PCSF_rand(ppi, terminals, n = 10, r = 0.1, w = 2, b = 1, mu = 0.0005) #' res <- enrichment_analysis(subnet) -#' plot(res$subnet)} -#' +#' plot(res$subnet) +#' } +#' #' @author Murodzhon Akhmedov -#' -#' @references -#' Chen E.Y., Christopher M.T., Yan K., Qiaonan D., Zichen W., Gabriela V.M., Neil R.C., and Avi M. (2013) -#' Enrichr: Interactive and Collaborative Html5 Gene List Enrichment Analysis Tool. \emph{BMC Bioinformatics} 14 (1). +#' +#' @references +#' Chen E.Y., Christopher M.T., Yan K., Qiaonan D., Zichen W., Gabriela V.M., Neil R.C., and Avi M. (2013) +#' Enrichr: Interactive and Collaborative Html5 Gene List Enrichment Analysis Tool. \emph{BMC Bioinformatics} 14 (1). #' BioMed Central: 1. -#' +#' #' @seealso \code{\link{enrichment_analysis}}, \code{\link{PCSF_rand}}, \code{\link{plot.PCSF}} -plot.PCSFe <-function(x, edge_width = 5, node_size = 30, node_label_cex = 1, - Terminal_node_legend = "Terminal", - Steiner_node_legend = "Steiner", +plot.PCSFe <- function(x, edge_width = 5, node_size = 30, node_label_cex = 1, + Terminal_node_legend = "Terminal", + Steiner_node_legend = "Steiner", extra_node_colors = list(), - ...){ - - - subnet = x - # Checking function arguments - if (missing(subnet)) - stop("Need to specify the subnetwork obtained from the PCSF algorithm.") - if (class(subnet)[1] != "PCSFe" || class(subnet)[2] != "igraph") - stop("The subnetwork must be a \"PCSFe\" object derived from an \"igraph\" class.") - if (edge_width < 2) - stop("The edge_width must be greater than 2.") - if (node_size < 10) - stop("The node_size must be greater than 10.") - - # Add 'label' and 'size' attributes - V(subnet)$label.cex = node_label_cex - prize = abs(V(subnet)$prize) - min1 = 10 - max1 = node_size - r1 = max1 - min1 - min2 = min(prize) - max2 = max(prize) - r2 = max2 - min2 - adjusted_prize = r1*(prize - min2)/r2 + min1 - V(subnet)$size = adjusted_prize - - # Add edge width' attributes - weight = E(subnet)$weight - min1 = 2 - max1 = edge_width - r1 = max1 - min1 - min2 = min(weight) - max2 = max(weight) - r2 = max2 - min2 - adjusted_weight = r1*(weight - min2)/r2 + min1 - E(subnet)$width = adjusted_weight - - - # Associate the type of nodes to shape - shape = V(subnet)$type - shape[which(shape=="Steiner")] = "triangle" - shape[which(shape=="Terminal")] = "circle" - V(subnet)$shape = shape - - # Visualize the subnet - visIgraph(subnet) %>% - visIgraphLayout(layout = "layout_with_fr") %>% - visOptions(highlightNearest = list(enabled = T), selectedBy = "group")%>% - visLegend(addNodes = list( - list(label = Terminal_node_legend, shape = "dot", size = 15, label.cex = 0.3), - list(label = Steiner_node_legend, shape = "triangle",size = 9, label.cex = 0.3)), width = 0.2, - useGroups = FALSE) -} \ No newline at end of file + ...) { + subnet <- x + # Checking function arguments + if (missing(subnet)) { + stop("Need to specify the subnetwork obtained from the PCSF algorithm.") + } + if (class(subnet)[1] != "PCSFe" || class(subnet)[2] != "igraph") { + stop("The subnetwork must be a \"PCSFe\" object derived from an \"igraph\" class.") + } + if (edge_width < 2) { + stop("The edge_width must be greater than 2.") + } + if (node_size < 10) { + stop("The node_size must be greater than 10.") + } + + # Add 'label' and 'size' attributes + V(subnet)$label.cex <- node_label_cex + prize <- abs(V(subnet)$prize) + min1 <- 10 + max1 <- node_size + r1 <- max1 - min1 + min2 <- min(prize) + max2 <- max(prize) + r2 <- max2 - min2 + adjusted_prize <- r1 * (prize - min2) / r2 + min1 + V(subnet)$size <- adjusted_prize + + # Add edge width' attributes + weight <- E(subnet)$weight + min1 <- 2 + max1 <- edge_width + r1 <- max1 - min1 + min2 <- min(weight) + max2 <- max(weight) + r2 <- max2 - min2 + adjusted_weight <- r1 * (weight - min2) / r2 + min1 + E(subnet)$width <- adjusted_weight + + + # Associate the type of nodes to shape + shape <- V(subnet)$type + shape[which(shape == "Steiner")] <- "triangle" + shape[which(shape == "Terminal")] <- "circle" + V(subnet)$shape <- shape + + # Visualize the subnet + visIgraph(subnet) %>% + visIgraphLayout(layout = "layout_with_fr") %>% + visOptions(highlightNearest = list(enabled = T), selectedBy = "group") %>% + visLegend( + addNodes = list( + list(label = Terminal_node_legend, shape = "dot", size = 15, label.cex = 0.3), + list(label = Steiner_node_legend, shape = "triangle", size = 9, label.cex = 0.3) + ), width = 0.2, + useGroups = FALSE + ) +} diff --git a/codemeta.json b/codemeta.json new file mode 100644 index 0000000..ef7b474 --- /dev/null +++ b/codemeta.json @@ -0,0 +1,187 @@ +{ + "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@type": "SoftwareSourceCode", + "identifier": "PCSF", + "description": "The PCSF package performs an integrated analysis of highthroughput data using the interaction networks as a template, and interprets the biological landscape of interaction networks with respect to the data, which potentially leads to predictions of functional units. It also interactively visualize the resulting subnetwork with functional enrichment analysis.", + "name": "PCSF: Network-based interpretation of highthroughput data", + "license": "https://spdx.org/licenses/MIT", + "version": "0.99.1", + "programmingLanguage": { + "@type": "ComputerLanguage", + "name": "R", + "url": "https://r-project.org" + }, + "runtimePlatform": "R version 4.4.1 (2024-06-14)", + "author": [ + { + "@type": "Person", + "givenName": "Amanda", + "familyName": "Kedaigle" + }, + { + "@type": "Person", + "givenName": "Renan", + "familyName": "Escalante" + }, + { + "@type": "Person", + "givenName": "Roberto", + "familyName": "Montemanni" + }, + { + "@type": "Person", + "givenName": "Francesco", + "familyName": "Bertoni" + }, + { + "@type": "Person", + "givenName": "Ernest", + "familyName": "Fraenkel" + }, + { + "@type": "Person", + "givenName": "Ivo", + "familyName": "Kwee" + } + ], + "maintainer": [ + { + "@type": "Person", + "givenName": "Murodzhon", + "familyName": "Akhmedov", + "email": "murodzhon@idsia.ch" + } + ], + "softwareSuggestions": [ + { + "@type": "SoftwareApplication", + "identifier": "knitr", + "name": "knitr", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=knitr" + }, + { + "@type": "SoftwareApplication", + "identifier": "rmarkdown", + "name": "rmarkdown", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=rmarkdown" + } + ], + "softwareRequirements": { + "1": { + "@type": "SoftwareApplication", + "identifier": "igraph", + "name": "igraph", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=igraph" + }, + "2": { + "@type": "SoftwareApplication", + "identifier": "R", + "name": "R", + "version": ">= 3.1.0" + }, + "3": { + "@type": "SoftwareApplication", + "identifier": "visNetwork", + "name": "visNetwork", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=visNetwork" + }, + "4": { + "@type": "SoftwareApplication", + "identifier": "BH", + "name": "BH", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=BH" + }, + "5": { + "@type": "SoftwareApplication", + "identifier": "dplyr", + "name": "dplyr", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=dplyr" + }, + "6": { + "@type": "SoftwareApplication", + "identifier": "httr", + "name": "httr", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=httr" + }, + "7": { + "@type": "SoftwareApplication", + "identifier": "methods", + "name": "methods" + }, + "8": { + "@type": "SoftwareApplication", + "identifier": "org.Hs.eg.db", + "name": "org.Hs.eg.db" + }, + "9": { + "@type": "SoftwareApplication", + "identifier": "Rcpp", + "name": "Rcpp", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=Rcpp" + }, + "10": { + "@type": "SoftwareApplication", + "identifier": "topGO", + "name": "topGO", + "provider": { + "@id": "https://www.bioconductor.org", + "@type": "Organization", + "name": "Bioconductor", + "url": "https://www.bioconductor.org" + }, + "sameAs": "https://bioconductor.org/packages/release/bioc/html/topGO.html" + }, + "SystemRequirements": null + }, + "fileSize": "7741.971KB", + "codeRepository": "https://github.com/CogDisResLab/PCSF", + "readme": "https://github.com/CogDisResLab/PCSF/blob/master/README.md" +} diff --git a/inst/WORDLIST b/inst/WORDLIST new file mode 100644 index 0000000..45a098b --- /dev/null +++ b/inst/WORDLIST @@ -0,0 +1,100 @@ +abondance +Akhmedov +al +Alexa +AliSajid +Avi +Bertoni +betweenness +BH +Bioinformatics +BioMed +biomolecule +biomolecules +BMC +CBL +CMake +config +downregulation +dplyr +dysregulated +eg +EGFR +enrichments +Enrichr +EnrichR +ENRICHR +Escalante +et +Fraenkel +Francesco +fuction +functionla +github +GW +highthroughput +highthrougput +Hs +httr +idsia +igraph +Imami +interactome +intra +iref +Ivo +Kedaigle +knitr +Kwee +LeNail +lightblue +LinkingTo +MERCHANTABILITY +mesenchymal +miscore +mitab +Montemanni +murodzhon +Murodzhon +NONINFRINGEMENT +noreply +obrained +Omics +pacakge +PCSF +PCSFe +phos +phosphoproteomic +Phosphoproteomic +phosphotyrosine +PPI +pre +PSCF +Qiaonan +Rahnenfuhrer +rando +randomised +Rcpp +Renan +rmarkdown +RoxygenNote +Sajid +Steiners +sublicense +subnet +subnetwork +subnetworks +subunits +TGF +Tgfb +topGO +UBC +ubiquitin +undirected +upto +valu +visNetwork +yaml +Yan +Zichen +β diff --git a/man/PCSF.Rd b/man/PCSF.Rd index eaab1ff..43c490d 100644 --- a/man/PCSF.Rd +++ b/man/PCSF.Rd @@ -77,7 +77,8 @@ data("STRING") data("Tgfb_phospho") terminals <- Tgfb_phospho ppi <- construct_interactome(STRING) -subnet <- PCSF(ppi, terminals, w = 2, b = 1, mu = 0.0005)} +subnet <- PCSF(ppi, terminals, w = 2, b = 1, mu = 0.0005) +} } \references{ diff --git a/man/PCSF_rand.Rd b/man/PCSF_rand.Rd index c1722a2..1374310 100644 --- a/man/PCSF_rand.Rd +++ b/man/PCSF_rand.Rd @@ -9,14 +9,14 @@ PCSF_rand(ppi, terminals, n = 10, r = 0.1, w = 2, b = 1, mu = 0.0005, dummies) \arguments{ \item{ppi}{An interaction network as an \pkg{igraph} object.} -\item{terminals}{A list of terminal genes with prizes to be analyzed in the PCSF context. -A named \code{numeric} vector, where terminal genes are named same as in the interaction network +\item{terminals}{A list of terminal genes with prizes to be analyzed in the PCSF context. +A named \code{numeric} vector, where terminal genes are named same as in the interaction network and numeric values correspond to the importance of the gene within the study.} -\item{n}{An \code{integer} value to determine the number of runs with random noise added edge costs. +\item{n}{An \code{integer} value to determine the number of runs with random noise added edge costs. A default value is 10.} -\item{r}{A \code{numeric} value to determine additional random noise to edge costs. +\item{r}{A \code{numeric} value to determine additional random noise to edge costs. A random noise upto r percent of the edge cost is added to each edge. A default value is 0.1} \item{w}{A \code{numeric} value for tuning the number of trees in the output. A default value is 2.} @@ -28,19 +28,19 @@ A random noise upto r percent of the edge cost is added to each edge. A default \item{dummies}{A list of nodes that are to connected to the root of the tree. If missing the root will be connected to all terminals.} } \value{ -The final subnetwork obtained by taking the union of the PCSF outputs generated by -adding a random noise to edge costs each time. It returns an \pkg{igraph} object with the node prize +The final subnetwork obtained by taking the union of the PCSF outputs generated by +adding a random noise to edge costs each time. It returns an \pkg{igraph} object with the node prize and edge cost attributes representing the total number of show ups throughout all runs. } \description{ -\code{PCSF_rand} returns a union of subnetworks obtained by solving the PCSF on the +\code{PCSF_rand} returns a union of subnetworks obtained by solving the PCSF on the given interaction network by adding a random noise to edge costs each time. } \details{ -In order to increase the robustness of the resulting structure, +In order to increase the robustness of the resulting structure, it is recommended to solve the PCSF several times on the same network -while adding some noise to the edge costs each time, and combine all results -in a final subnetwork. The union of all outputs may explain +while adding some noise to the edge costs each time, and combine all results +in a final subnetwork. The union of all outputs may explain the underlying biology better. } \examples{ @@ -50,7 +50,8 @@ data("STRING") data("Tgfb_phospho") terminals <- Tgfb_phospho ppi <- construct_interactome(STRING) -subnet <- PCSF_rand(ppi, terminals, n = 10, r =0.1, w = 2, b = 2, mu = 0.0005)} +subnet <- PCSF_rand(ppi, terminals, n = 10, r = 0.1, w = 2, b = 2, mu = 0.0005) +} } \references{ diff --git a/man/STRING.Rd b/man/STRING.Rd index 0d90336..0d25902 100644 --- a/man/STRING.Rd +++ b/man/STRING.Rd @@ -5,8 +5,8 @@ \alias{STRING} \title{Protein-protein interaction network data} \format{ -A data frame with three variables, where each row corresponds to -an edge in which the first element is a \code{head}, the second +A data frame with three variables, where each row corresponds to +an edge in which the first element is a \code{head}, the second element is a \code{tail}, and the last element represents the \code{cost} of the edge. } \source{ diff --git a/man/Tgfb_phospho.Rd b/man/Tgfb_phospho.Rd index 45de9e6..e40706a 100644 --- a/man/Tgfb_phospho.Rd +++ b/man/Tgfb_phospho.Rd @@ -5,8 +5,8 @@ \alias{Tgfb_phospho} \title{Phosphoproteomic data} \format{ -A named \code{numeric} vector, where terminal genes are named same as -in the interaction network and numeric values correspond to the importance of +A named \code{numeric} vector, where terminal genes are named same as +in the interaction network and numeric values correspond to the importance of the gene within the study. } \source{ @@ -16,7 +16,7 @@ Tgfb_phos.txt \url{https://github.com/fraenkel-lab/OmicsIntegrator/tree/master/e Tgfb_phospho } \description{ -This dataset contains differential phosphoproteomic data derived from H358 cells, +This dataset contains differential phosphoproteomic data derived from H358 cells, a model of lung cancer, that were stimulated with TGF-b. } \keyword{data} diff --git a/man/construct_interactome.Rd b/man/construct_interactome.Rd index 0f40827..31e9a83 100644 --- a/man/construct_interactome.Rd +++ b/man/construct_interactome.Rd @@ -8,21 +8,22 @@ construct_interactome(ppi) } \arguments{ \item{ppi}{A list of edges. A \code{data.frame} composed of three columns, where each -row corresponds to an edge in which the first element is a \code{head}, the second +row corresponds to an edge in which the first element is a \code{head}, the second element is a \code{tail}, and the last element represents the \code{cost} of the edge.} } \value{ An interaction network as \pkg{igraph} object. } \description{ -Given a list of edges, \code{construct_interactome} generates +Given a list of edges, \code{construct_interactome} generates an interaction network which is used as a template network to interpret the highthrougput data. } \examples{ \dontrun{ library("PCSF") data("STRING") -ppi <- construct_interactome(STRING)} +ppi <- construct_interactome(STRING) +} } \author{ diff --git a/man/enrichment_analysis.Rd b/man/enrichment_analysis.Rd index f485cdf..34d281f 100644 --- a/man/enrichment_analysis.Rd +++ b/man/enrichment_analysis.Rd @@ -55,15 +55,20 @@ terminals <- Tgfb_phospho ppi <- construct_interactome(STRING) subnet <- PCSF_rand(ppi, terminals, n = 10, r = 0.1, w = 2, b = 1, mu = 0.0005) res <- enrichment_analysis(subnet) -res <- enrichment_analysis(subnet, mode=0)} +res <- enrichment_analysis(subnet, mode = 0) +} \dontrun{ library(topGO) gene_universe <- V(ppi)$name -res <- enrichment_analysis(subnet, mode=1, gene_universe)} +res <- enrichment_analysis(subnet, mode = 1, gene_universe) +} \dontrun{ plot(res$subnet) -write.table(res$enrichment[[1]],file="cluster1_complete_enrichment.txt", - append = FALSE, quote = FALSE, sep ="\t", row.names=FALSE)} +write.table(res$enrichment[[1]], + file = "cluster1_complete_enrichment.txt", + append = FALSE, quote = FALSE, sep = "\t", row.names = FALSE +) +} } \references{ diff --git a/man/plot.PCSF.Rd b/man/plot.PCSF.Rd index 1121b38..025caa6 100644 --- a/man/plot.PCSF.Rd +++ b/man/plot.PCSF.Rd @@ -68,7 +68,8 @@ data("Tgfb_phospho") terminals <- Tgfb_phospho ppi <- construct_interactome(STRING) subnet <- PCSF(ppi, terminals, w = 2, b = 1, mu = 0.0005) -plot(subnet)} +plot(subnet) +} } \seealso{ diff --git a/man/plot.PCSFe.Rd b/man/plot.PCSFe.Rd index b5845d9..e912cb1 100644 --- a/man/plot.PCSFe.Rd +++ b/man/plot.PCSFe.Rd @@ -16,22 +16,22 @@ ) } \arguments{ -\item{x}{An output subnetwork provided by the \code{enrichment_analysis}. -It is "PCSFe" object derived from an \pkg{igraph} class, and it has the edge +\item{x}{An output subnetwork provided by the \code{enrichment_analysis}. +It is "PCSFe" object derived from an \pkg{igraph} class, and it has the edge cost and vertex prize attributes.} -\item{edge_width}{A \code{numeric} value to emphasize a maximum edge width. +\item{edge_width}{A \code{numeric} value to emphasize a maximum edge width. A default value is 5. This value must be greater than 1.} -\item{node_size}{A \code{numeric} value to emphasize a maximum node size. +\item{node_size}{A \code{numeric} value to emphasize a maximum node size. A default value is 30. This value must be greater than 10.} -\item{node_label_cex}{A \code{numeric} value to set a node label size. +\item{node_label_cex}{A \code{numeric} value to set a node label size. A default value is 1.} \item{Terminal_node_legend}{A \code{string} to set a legend for \code{terminal} nodes.} -\item{Steiner_node_legend}{A \code{string} to set a legend for \code{Steiner} nodes. +\item{Steiner_node_legend}{A \code{string} to set a legend for \code{Steiner} nodes. A default legend is "Steiner".} \item{extra_node_colors}{A \code{list} with colors of extra types of nodes added to the PCSF result, with the names of the list being the node type @@ -40,20 +40,20 @@ A default legend is "Terminal".} \item{...}{Ignored.} } \description{ -\code{plot.PCSFe} plots an interactive figure of the subnetwork -to display the functionla enrichment analysis, which is obtained by employing +\code{plot.PCSFe} plots an interactive figure of the subnetwork +to display the functionla enrichment analysis, which is obtained by employing \code{enrichment_analysis} on the subnetwork. } \details{ -An enrichment analysis of the final subnetwork obtained by multiple runs of the PCSF -(with random noise added edge costs) is performed by using \code{\link{enrichment_analysis}}. -The subnetwork is clustered using an edge betweenness clustering algorithm from the -\pkg{igraph} package, and for each cluster functional enrichment is done by employing the -ENRICHR API (Chen \emph{et al.}, 2013). An interactive visualization of the final subnetwork -is plotted, where the node sizes and edge widths are proportional to the frequency of show -ups in total randomised runs. Nodes are colored according to the cluster membership, and -the top 15 functional enrichment terms are displayed in tabular format during the hover-over -of the node in that cluster. A specific cluster can be displayed separately in the figure +An enrichment analysis of the final subnetwork obtained by multiple runs of the PCSF +(with random noise added edge costs) is performed by using \code{\link{enrichment_analysis}}. +The subnetwork is clustered using an edge betweenness clustering algorithm from the +\pkg{igraph} package, and for each cluster functional enrichment is done by employing the +ENRICHR API (Chen \emph{et al.}, 2013). An interactive visualization of the final subnetwork +is plotted, where the node sizes and edge widths are proportional to the frequency of show +ups in total randomised runs. Nodes are colored according to the cluster membership, and +the top 15 functional enrichment terms are displayed in tabular format during the hover-over +of the node in that cluster. A specific cluster can be displayed separately in the figure by selecting from the icon list at the top left side of the figure. } \examples{ @@ -65,12 +65,13 @@ terminals <- Tgfb_phospho ppi <- construct_interactome(STRING) subnet <- PCSF_rand(ppi, terminals, n = 10, r = 0.1, w = 2, b = 1, mu = 0.0005) res <- enrichment_analysis(subnet) -plot(res$subnet)} +plot(res$subnet) +} } \references{ -Chen E.Y., Christopher M.T., Yan K., Qiaonan D., Zichen W., Gabriela V.M., Neil R.C., and Avi M. (2013) -Enrichr: Interactive and Collaborative Html5 Gene List Enrichment Analysis Tool. \emph{BMC Bioinformatics} 14 (1). +Chen E.Y., Christopher M.T., Yan K., Qiaonan D., Zichen W., Gabriela V.M., Neil R.C., and Avi M. (2013) +Enrichr: Interactive and Collaborative Html5 Gene List Enrichment Analysis Tool. \emph{BMC Bioinformatics} 14 (1). BioMed Central: 1. } \seealso{ diff --git a/renv.lock b/renv.lock index 47d2b14..0fd5861 100644 --- a/renv.lock +++ b/renv.lock @@ -474,6 +474,29 @@ ], "Hash": "698ece7ba5a4fa4559e3d537e7ec3d31" }, + "dplyr": { + "Package": "dplyr", + "Version": "1.1.4", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "cli", + "generics", + "glue", + "lifecycle", + "magrittr", + "methods", + "pillar", + "rlang", + "tibble", + "tidyselect", + "utils", + "vctrs" + ], + "Hash": "fedd9d00c2944ff00a0e2696ccf048ec" + }, "evaluate": { "Package": "evaluate", "Version": "0.24.0", @@ -485,6 +508,18 @@ ], "Hash": "a1066cbc05caee9a4bf6d90f194ff4da" }, + "fansi": { + "Package": "fansi", + "Version": "1.0.6", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "grDevices", + "utils" + ], + "Hash": "962174cf2aeb5b9eea581522286a911f" + }, "fastmap": { "Package": "fastmap", "Version": "1.2.0", @@ -515,6 +550,17 @@ ], "Hash": "15aeb8c27f5ea5161f9f6a641fafd93a" }, + "generics": { + "Package": "generics", + "Version": "0.1.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "methods" + ], + "Hash": "15e9634c0fcd294799e9b2e929ed1b86" + }, "glue": { "Package": "glue", "Version": "1.7.0", @@ -747,6 +793,23 @@ ], "Hash": "1ac8a004ad2e4f6489dadf3a2ffeb638" }, + "pillar": { + "Package": "pillar", + "Version": "1.9.0", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "cli", + "fansi", + "glue", + "lifecycle", + "rlang", + "utf8", + "utils", + "vctrs" + ], + "Hash": "15da5a8412f317beeee6175fbc76f4bb" + }, "pkgconfig": { "Package": "pkgconfig", "Version": "2.0.3", @@ -849,6 +912,41 @@ "Repository": "RSPM", "Hash": "3a1be13d68d47a8cd0bfd74739ca1555" }, + "tibble": { + "Package": "tibble", + "Version": "3.2.1", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "fansi", + "lifecycle", + "magrittr", + "methods", + "pillar", + "pkgconfig", + "rlang", + "utils", + "vctrs" + ], + "Hash": "a84e2cc86d07289b3b6f5069df7a004c" + }, + "tidyselect": { + "Package": "tidyselect", + "Version": "1.2.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cli", + "glue", + "lifecycle", + "rlang", + "vctrs", + "withr" + ], + "Hash": "829f27b9c4919c16b593794a6344d6c0" + }, "tinytex": { "Package": "tinytex", "Version": "0.51", @@ -879,6 +977,16 @@ ], "Hash": "41e23d477c59be6a405f5239fe507213" }, + "utf8": { + "Package": "utf8", + "Version": "1.2.4", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R" + ], + "Hash": "62b65c52671e6665f803ff02954446e9" + }, "vctrs": { "Package": "vctrs", "Version": "0.6.5", @@ -911,6 +1019,18 @@ ], "Hash": "3e48b097e8d9a91ecced2ed4817a678d" }, + "withr": { + "Package": "withr", + "Version": "3.0.1", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "grDevices", + "graphics" + ], + "Hash": "07909200e8bbe90426fbfeb73e1e27aa" + }, "xfun": { "Package": "xfun", "Version": "0.44", diff --git a/vignettes/PCSF-manual.Rmd b/vignettes/PCSF-manual.Rmd index 0a03c5c..f290866 100644 --- a/vignettes/PCSF-manual.Rmd +++ b/vignettes/PCSF-manual.Rmd @@ -13,7 +13,7 @@ bibliography: ref.bib ####Introduction -A tremendous amount of high-throughput data at multiple layers of cellular systems has been profiled to study biological responses to perturbations and disease. The current challenge is to develop methods for effective analysis of these data to better interpret underlying biology and identify functional units. Network modeling approaches are some of the techniques lately used for analysis of biological networks [@Dittrich]. Recently, the Prize-collecting Steiner Forest (PCSF) algorithm has been applied to interaction networks to find a subnetwork enriched for input data, which corresponds to relevant subunits in the interactome of a cell [@Bechet, @Tuncbag]. +A tremendous amount of high-throughput data at multiple layers of cellular systems has been profiled to study biological responses to perturbations and disease. The current challenge is to develop methods for effective analysis of these data to better interpret underlying biology and identify functional units. Network modeling approaches are some of the techniques lately used for analysis of biological networks [@Dittrich]. Recently, the Prize-collecting Steiner Forest (PCSF) algorithm has been applied to interaction networks to find a subnetwork enriched for input data, which corresponds to relevant subunits in the interactome of a cell [@Bechet, @Tuncbag]. The PCSF problem has NP-hard characteristics, and requires a great deal of effort to find exact solutions on larger biological networks. Recently, we have developed a fast heuristic for the PCSF [@Akhmedov2016], and conducted a detailed performance comparison with existing methods [@Akhmedov]. As an extension to this, we present an R package that performs fast and user-friendly analysis of high-throughput data using the interaction networks as a template, and interprets the biological landscape of interactome with respect to the data. More specifically, the PCSF package allows the user to i) upload the interactome and patient data ii) compute the PCSF subnetwork solution iii) perform functional analysis on resulting subnetwork iv) and interactively visualize the final subnetwork with functional enrichment information. @@ -27,7 +27,7 @@ The PCSF is a well-known problem in graph theory. Given an undirected graph $G = $$F(G')= \text{Minimize} \sum_{e{\in}E'} c_{e} + \beta*\sum_{v{\not\in}V'} p_{v} + w*k \label{GW}$$ -where $k$ is the number of trees in the forest, and it is regulated by parameter $w$. The parameter $\beta$ is used to tune the prizes of nodes relative to edge costs. +where $k$ is the number of trees in the forest, and it is regulated by parameter $w$. The parameter $\beta$ is used to tune the prizes of nodes relative to edge costs. Recently, we have applied PCSF to biological networks in the Forest module of the Omics Integrator software [@Tuncbag]. In biological networks such as Protein-Protein Interaction (PPI) networks, every vertex represents a biomolecule, and every edge corresponds to the cellular interaction between two biomolecules. Edges of the network are given costs, which correspond to confidence or frequency of that interaction. The vertices of the network are given prizes according to the measurements of differential expression, copy number, or number of mutation for that gene/protein. The set of vertices that are assigned a prize are referred to as `terminal` nodes. Non-terminal nodes, which were not observed in the experimental data, may appear in the solution and are called `Steiner` nodes. After scoring the interactome, the PCSF is used to detect a relevant subnetwork (forest). The PCSF aims to identify neighborhoods in interaction networks potentially belonging to the key dysregulated pathways of a disease or experiment. @@ -42,9 +42,9 @@ The parameter $\mu$ also affects the total number of `Steiner` nodes in the solu #### Package Dependencies and Installation -The software was implemented in R environment, and easily can be installed within the R terminal. As input, the package requires a template network such as protein-protein interaction, protein-metabolite interaction or any other correlation-based interaction network, and it maps differentially expressed genes/proteins/metabolites from the high-throughput data as vertex prizes into the template network. Then, it computes and returns high-scoring neighborhoods to identify functional modules in the interactome. Required parameters are: $\beta$ - for tuning the vertex prizes, $\omega$ - for regulating the number of distinct components in the subnetwork, and $\mu$ - for hub penalization. +The software was implemented in R environment, and easily can be installed within the R terminal. As input, the package requires a template network such as protein-protein interaction, protein-metabolite interaction or any other correlation-based interaction network, and it maps differentially expressed genes/proteins/metabolites from the high-throughput data as vertex prizes into the template network. Then, it computes and returns high-scoring neighborhoods to identify functional modules in the interactome. Required parameters are: $\beta$ - for tuning the vertex prizes, $\omega$ - for regulating the number of distinct components in the subnetwork, and $\mu$ - for hub penalization. -The package has the following R-package dependencies that are automatically installed along with the package: +The package has the following R-package dependencies that are automatically installed along with the package: * `BH` and `igraph` - for efficient graph handling and calculations, * `httr`, `methods`, `org.Hs.eg.db`, and `topGO` - to perform enrichment analysis, @@ -59,9 +59,11 @@ The PCSF package and its dependencies can be installed on Mac OS, Linux and Wind ```{r, eval=FALSE} source("http://bioconductor.org/biocLite.R") biocLite("topGO") -install.packages("devtools", dependencies=TRUE) -devtools::install_github("IOR-Bioinformatics/PCSF", repos=BiocInstaller::biocinstallRepos(), - dependencies=TRUE, type="source", force=TRUE) +install.packages("devtools", dependencies = TRUE) +devtools::install_github("IOR-Bioinformatics/PCSF", + repos = BiocInstaller::biocinstallRepos(), + dependencies = TRUE, type = "source", force = TRUE +) ```
@@ -80,8 +82,8 @@ library(PCSF) data("STRING") data("Tgfb_phospho") ``` -
-Next, we construct a PPI network using the STRING data employing the `construct_interactome()` function. The resulting PPI network consists of 17581 edges and 15405 nodes. +
+Next, we construct a PPI network using the STRING data employing the `construct_interactome()` function. The resulting PPI network consists of 17581 edges and 15405 nodes. Users can construct a PPI network by providing their own interactome. An interactome data for `construct_interactome()` must be a `data.frame` composed of three columns, where each row corresponds to an edge, in which the first element is a `head`, the second element is a `tail`, and the last element represents the `cost` of the edge. @@ -89,7 +91,7 @@ Users can construct a PPI network by providing their own interactome. An interac ppi <- construct_interactome(STRING) ppi ``` -
+
We then generate a vector named `terminals` that is composed of genes with prizes to be analyzed in the PCSF context. Here, our prizes come from the phosphoproteomic data derived from H358 cells. There are 58 proteins which were determined to be significantly modulated in phosphorylation after TGF-β stimulation, and the prize for each protein is the absolute value of the log fold change in phosphotyrosine abundance. @@ -99,29 +101,33 @@ Users can generate this vector by providing their own data. It must be a named n terminals <- Tgfb_phospho str(terminals) ``` -
+
After properly obtaining the PPI network and scoring it, we employ the PCSF approach to identify the subnetwork with the following function, in which the arguments are: `ppi` - a weighted PPI network, `terminals` - a named numeric vector which corresponds to the list of genes with prizes, `w` - a parameter for tuning the number of trees in the subnetwork, `b` - a numeric value for tuning the node prizes, `mu` - a parameter for hub penalization. This function outputs the subnetwork as an `igraph` object. ```{r, message=FALSE, warning=FALSE, results='hide'} subnet <- PCSF(ppi, terminals, w = 2, b = 1, mu = 0.0005) ``` -
+
The dynamic and interactive version of final subnetwork can be plotted with the `plot.PCSF()` function, where it takes the arguments: `x` - the output obtained by PCSF approach, `style` - a boolean value to determine the visualization style of the network, `edge_width` - a variable to adjust edge widths, `node_size` - a numeric value to adjust the size of nodes, `node_label_cex` - a numeric value to set node label size, `Steiner_node_color` - a variable to color the `Steiner` nodes, `Terminal_node_color` - a variable to color `terminal` nodes. The node sizes and edge widths in the figure are proportional to the prize of nodes and probability of existence of the edges, respectively, and they are adjusted according to `node_size` and `edge_width` parameters. ```{r, eval=FALSE} -plot(subnet, style = 1, edge_width=5, node_size=40, node_label_cex = 30, Steiner_node_color = "lightblue", - Terminal_node_color = "lightgreen") +plot(subnet, + style = 1, edge_width = 5, node_size = 40, node_label_cex = 30, Steiner_node_color = "lightblue", + Terminal_node_color = "lightgreen" +) ```
```{r, echo=FALSE, fig.width=10, fig.height=6} -plot(subnet, style = 1, edge_width=5, node_size=40, node_label_cex = 30, Steiner_node_color = "lightblue", - Terminal_node_color = "lightgreen") +plot(subnet, + style = 1, edge_width = 5, node_size = 40, node_label_cex = 30, Steiner_node_color = "lightblue", + Terminal_node_color = "lightgreen" +) ```
-
+
Now, let's observe how the hub penalization parameter is effecting the final subnetwork. We solve the PCSF with a higher `mu` value than previous one (`mu=0.05`), and plot the subnetwork. It is clear that when the `mu` value is increased, we get very limited number of `Steiner` nodes and a smaller subnetwork overall. @@ -134,7 +140,7 @@ plot(subnet, style = 1) plot(subnet, style = 1) ``` -
+
However, if we set `mu` to zero, we see that the forest relies on the hub node UBC, or the regulatory protein ubiquitin-C. These hub nodes are often not specific to the system in the experiment. @@ -148,8 +154,8 @@ plot(subnet, style = 1) ``` -
-
+
+
#### Adding random noise to the edge costs @@ -158,7 +164,7 @@ We must be cautious making a biological interpretation of data based on a single ```{r, results='hide', message=FALSE, warning=FALSE} -subnet <- PCSF_rand(ppi, terminals, n=10, r = 0.1, w = 2, b = 1, mu = 0.0005) +subnet <- PCSF_rand(ppi, terminals, n = 10, r = 0.1, w = 2, b = 1, mu = 0.0005) ```

@@ -169,14 +175,14 @@ subnet <- PCSF_rand(ppi, terminals, n=10, r = 0.1, w = 2, b = 1, mu = 0.0005) The enrichment analysis of the final subnetwork is performed with the `enrichment_analysis()` function. The subnetwork is clustered by edge betweenness algorithm from the `igraph` package, and for each cluster the functional enrichment is done by employing either EnrichR [@Chen] API or topGO [@Alexa] R-package that can be specified by the user. Note that EnrichR API requires a working internet connection to perform the enrichment. If not specified, the package defaults to EnrichR, it uses topGO if there is no internet connection. -The `enrichment_analysis()` fuction requires the following arguments: `subnet` - the final subnetwork obtained by the PCSF method, `mode` - a binary variable to choose the method for enrichment analysis, where 0 is for EnrichR API and 1 is for topGO package, and `gene_universe` - a complete list of genes (vector of gene symbols) used as background in enrichment analysis by topGO package. +The `enrichment_analysis()` fuction requires the following arguments: `subnet` - the final subnetwork obtained by the PCSF method, `mode` - a binary variable to choose the method for enrichment analysis, where 0 is for EnrichR API and 1 is for topGO package, and `gene_universe` - a complete list of genes (vector of gene symbols) used as background in enrichment analysis by topGO package. -It is required to define a `gene_universe` to use topGO, and the gene_universe in this example is all the genes in the PPI template network. It performs enrichment analysis for `Biological_Process` terms in Gene Ontology database within our implementation. +It is required to define a `gene_universe` to use topGO, and the gene_universe in this example is all the genes in the PPI template network. It performs enrichment analysis for `Biological_Process` terms in Gene Ontology database within our implementation. ```{r, results='hide', message=FALSE, warning=FALSE, eval=FALSE} library(topGO) gene_universe <- V(ppi)$name -res <- enrichment_analysis(subnet, mode=1, gene_universe) +res <- enrichment_analysis(subnet, mode = 1, gene_universe) ``` In contrast, EnrichR API does not require a `gene_universe`, and it gathers and combines the enrichment analyses for `GO_Biological_Process_2015`,`KEGG_2016`, `Reactome_2016`, and `BioCarta_2016` databases. @@ -189,7 +195,7 @@ The `enrichment_analysis()` returns an annotated subnetwork (`igraph` object) an
-An interactive version of the annotated subnetwork is visualized by the `plot.PCSFe()` function, where each cluster is colored differently. The plotting function requires the following arguments: `x` - an annotated subnetwork obtained by the `enrichment_analysis()` function, `edge_weight` - a variable to set the edge weights, `node_size` - a variable to adjust the size of nodes, `node_label_cex` - a numeric value to adjust the node label size. +An interactive version of the annotated subnetwork is visualized by the `plot.PCSFe()` function, where each cluster is colored differently. The plotting function requires the following arguments: `x` - an annotated subnetwork obtained by the `enrichment_analysis()` function, `edge_weight` - a variable to set the edge weights, `node_size` - a variable to adjust the size of nodes, `node_label_cex` - a numeric value to adjust the node label size. The node sizes and edge widths are proportional to the amount of times that node or edge appeared in the noisy runs. Nodes are colored according to cluster membership. As in the ENRICHR API, the p-value is calculated using the Fisher test and adjusted for multiple hypotheses. The combined score corresponds to multiplication of the log p-value and the z-score of the deviation from the expected rank of that term in random lists of genes. The top 15 functional enrichment terms for each cluster are ranked according to the adjusted p-value and displayed in a tabular format when the mouse hovers over a node in that cluster. Each cluster can be visualized separately by “Select by group” icon located at the top of the figure. @@ -202,13 +208,11 @@ plot(res$subnet, edge_width = 8, node_size = 30, node_label_cex = 1) plot(res$subnet, edge_width = 8, node_size = 30, node_label_cex = 1) ``` - + In this case, the presence of subnetworks enriched for Gene Ontology terms like 'mesenchymal-epithelial cell signaling' and 'EGFR downregulation' confirm the importance of these pathways in this lung cancer model. We also see Steiner nodes such as CBL, which has been shown to be involved in several models of non-small cell lung cancers [@Tan], like the H358 cell line. Therefore, we see that the PSCF algorithm points out proteins and pathways that are highly relevant to the system under study. - +

#### REFERENCES - - From 3f0b3fb6de2bc6dd34fcdce7fe24546b6ebca07d Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:02:21 -0400 Subject: [PATCH 04/13] build: add the utilities folder with utility scripts Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- .Rbuildignore | 1 + DESCRIPTION | 2 +- codemeta.json | 2 +- utilities/bump-version.sh | 43 +++++++++++++++++++++++++++++++++++ utilities/create_tag.sh | 24 +++++++++++++++++++ utilities/rename-package.R | 39 +++++++++++++++++++++++++++++++ utilities/update-changelog.sh | 14 ++++++++++++ 7 files changed, 123 insertions(+), 2 deletions(-) create mode 100755 utilities/bump-version.sh create mode 100755 utilities/create_tag.sh create mode 100755 utilities/rename-package.R create mode 100755 utilities/update-changelog.sh diff --git a/.Rbuildignore b/.Rbuildignore index ff875cb..ecb9886 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -6,3 +6,4 @@ ^codemeta\.json$ ^renv$ ^renv\.lock$ +^utilities$ diff --git a/DESCRIPTION b/DESCRIPTION index b8d42e8..f678d05 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: PCSF Title: Network-based interpretation of highthroughput data -Version: 0.99.1 +Version: 0.99.67 Date: 2017-02-01 Author: Murodzhon Akhmedov, Amanda Kedaigle, Renan Escalante, Roberto Montemanni, Francesco Bertoni, Ernest Fraenkel, Ivo Kwee diff --git a/codemeta.json b/codemeta.json index ef7b474..a046d9d 100644 --- a/codemeta.json +++ b/codemeta.json @@ -5,7 +5,7 @@ "description": "The PCSF package performs an integrated analysis of highthroughput data using the interaction networks as a template, and interprets the biological landscape of interaction networks with respect to the data, which potentially leads to predictions of functional units. It also interactively visualize the resulting subnetwork with functional enrichment analysis.", "name": "PCSF: Network-based interpretation of highthroughput data", "license": "https://spdx.org/licenses/MIT", - "version": "0.99.1", + "version": "0.99.67", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", diff --git a/utilities/bump-version.sh b/utilities/bump-version.sh new file mode 100755 index 0000000..c421e6a --- /dev/null +++ b/utilities/bump-version.sh @@ -0,0 +1,43 @@ +#!/bin/bash +set -euo pipefail + +# Define file paths +DESCRIPTION_FILE="DESCRIPTION" +CODEMETA_FILE="codemeta.json" + +# Extract the base version (MAJOR.MINOR) from the DESCRIPTION file +BASE_VERSION=$(grep '^Version:' $DESCRIPTION_FILE | awk '{print $2}' | cut -d. -f1,2) + +# Get the total number of commits in the Git history (this will be used as the patch number) +PATCH_NUMBER=$(git rev-list --count HEAD) + +# Combine the base version with the patch number +NEW_VERSION="$BASE_VERSION.$PATCH_NUMBER" + +# Get the current version from the DESCRIPTION file +CURRENT_VERSION=$(grep '^Version:' $DESCRIPTION_FILE | awk '{print $2}' || true) + +# Check if the version is already up to date +if [[ "$CURRENT_VERSION" == "$NEW_VERSION" ]]; then + echo "Version is already up-to-date: $NEW_VERSION" + exit 0 +fi + +echo "Updating version to: $NEW_VERSION" + +export SKIP="bump-version,codemeta-json-updated" + +# Update the DESCRIPTION file with the new version +if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/Version: $CURRENT_VERSION/Version: $NEW_VERSION/" $DESCRIPTION_FILE +else + sed -i "s/Version: $CURRENT_VERSION/Version: $NEW_VERSION/" $DESCRIPTION_FILE +fi + +# Update the codemeta.json file with the new version (assuming the version is under a "version" key) +jq --arg new_version "$NEW_VERSION" '.version = $new_version' "$CODEMETA_FILE" >tmp.$$.json && mv tmp.$$.json "$CODEMETA_FILE" + +# Stage the updated files +git add $DESCRIPTION_FILE $CODEMETA_FILE + +echo "Version updated to $NEW_VERSION." diff --git a/utilities/create_tag.sh b/utilities/create_tag.sh new file mode 100755 index 0000000..eaa5111 --- /dev/null +++ b/utilities/create_tag.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# This script creates a tag for the current commit +# It reads the current version string from the DESCRIPTION file + +DESCRIPTION_FILE="DESCRIPTION" + +# Extract the version from the DESCRIPTION file +VERSION=$(grep '^Version:' "$DESCRIPTION_FILE" | awk '{print $2}') +TAG="v$VERSION" + +# Check if the tag already exists +if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "Tag $TAG already exists. Exiting." + exit 0 +fi + +# Create a signed tag if it doesn't already exist +echo "Creating tag for version $VERSION" +git tag -s -a "$TAG" -m "build: New Version $VERSION" + +echo "Tag $TAG created" diff --git a/utilities/rename-package.R b/utilities/rename-package.R new file mode 100755 index 0000000..6f829fc --- /dev/null +++ b/utilities/rename-package.R @@ -0,0 +1,39 @@ +#!/usr/bin/env -S Rscript --vanilla + +# This script takes in a name and renames it to include the current R +# version and the current platform. It is intended to be used to rename +# packages that are being uploaded to releases on GitHub. + +## Parse the first argument as the package name + package version +args <- commandArgs(trailingOnly = TRUE) +if (length(args) != 1L) { + stop("Usage: rename-package.R ") +} + +message("Received package name: ", args[[1L]]) + +packageName <- strsplit(args, "_")[[1L]][[1L]] +message("Package name: ", packageName) +packageVersion <- strsplit(args, "_")[[1L]][[2L]] +message("Package version: ", packageVersion) + +newName <- paste( + packageName, paste("R", + getRversion(), + sep = "-" + ), + paste0("v", packageVersion), + sep = "_" +) + +message("Renaming package to: ", newName) + +value <- file.rename(args[[1L]], newName) + +if (value) { + message("Successfully renamed package to: ", newName) + cat(newName) +} else { + stop("Failed to rename package to: ", newName) + cat("") +} diff --git a/utilities/update-changelog.sh b/utilities/update-changelog.sh new file mode 100755 index 0000000..f2a29dc --- /dev/null +++ b/utilities/update-changelog.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -euo pipefail + +# Check if there commitizen binary on PATH +if ! [ -x "$(command -v cz)" ]; then + echo "Commitizen is not installed. Please install it with 'npm install -g commitizen'." + exit 1 +fi + +# Get the most recent tag +tag=$(git describe --tags $(git rev-list --tags --max-count=1)) + +# Update the changelog. Assume this is not the first tag +cz changelog From 4d0b4e7e7a1a08e7c4ad60f3ee56b2e45f12540a Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:06:00 -0400 Subject: [PATCH 05/13] ci: add all the github scripts Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- .github/.gitignore | 1 + .github/workflows/create_github_release.yaml | 89 ++++++++++++++++++++ .github/workflows/rworkflows.yml | 68 +++++++++++++++ .github/workflows/test-coverage.yaml | 62 ++++++++++++++ .pre-commit-config.yaml | 2 +- DESCRIPTION | 2 +- codemeta.json | 4 +- inst/WORDLIST | 1 + 8 files changed, 225 insertions(+), 4 deletions(-) create mode 100644 .github/.gitignore create mode 100644 .github/workflows/create_github_release.yaml create mode 100644 .github/workflows/rworkflows.yml create mode 100644 .github/workflows/test-coverage.yaml diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000..2d19fc7 --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/.github/workflows/create_github_release.yaml b/.github/workflows/create_github_release.yaml new file mode 100644 index 0000000..f23de06 --- /dev/null +++ b/.github/workflows/create_github_release.yaml @@ -0,0 +1,89 @@ +on: + push: + branches: + - devel + - RELEASE* + +name: Create Github Release + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + optimize_ci: + runs-on: ubuntu-latest + outputs: + skip: ${{ steps.check_skip.outputs.skip }} + steps: + - name: Optimize CI + id: check_skip + uses: withgraphite/graphite-ci-action@main + with: + graphite_token: ${{secrets.GRAPHITE_TOKEN}} + create-release: + runs-on: ubuntu-latest + needs: [optimize_ci] + if: needs.optimize_ci.outputs.skip == 'false' + permissions: + contents: write + outputs: + tag_version: ${{ steps.create_release.outputs.tag_version }} + steps: + - name: Checkout + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + with: + fetch-depth: 0 + - name: Get most recent tag + id: get_tag + run: echo "TAG_VERSION=$(git describe --tags $(git rev-list --tags --max-count=1))" >> "$GITHUB_ENV" + - name: Create Release + id: create_release + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + echo "Creating release for tag $TAG_VERSION" + gh release create $TAG_VERSION --title "Release $TAG_VERSION" --notes "Release $TAG_VERSION" --target ${{ github.ref }} + echo "tag_version=$TAG_VERSION" >> "$GITHUB_OUTPUT" + create_release_artifacts: + needs: [create-release] + permissions: + contents: write + strategy: + fail-fast: false + matrix: + r_version: ['release', 'devel'] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - name: Update system repositories + run: sudo apt-get update + - name: Install system dependencies + run: | + sudo apt-get install -y libxml2-dev \ + libssl-dev libcurl4-openssl-dev \ + libharfbuzz-dev libfribidi-dev \ + pandoc + - name: Setup R + uses: r-lib/actions/setup-r@e6be4b3706e0f39bc7a4cf4496a5f2c4cb840040 # v2.10.1 + with: + r-version: ${{ matrix.r_version }} + use-public-rspm: true + id: r + - name: Install dependencies + uses: r-lib/actions/setup-renv@e6be4b3706e0f39bc7a4cf4496a5f2c4cb840040 # v2.10.1 + - name: Build Package + run: R CMD build . + - name: Rename Package + run: echo "NEWNAME=$(./utilities/rename-package.R *.tar.gz)" >> "$GITHUB_ENV" + - name: debug + run: | + echo "R version: ${{ steps.r.outputs.installed-r-version }}" + echo "Current Tag: ${{ needs.create-release.outputs.tag_version }}" + echo "Release File Name: ${{ env.NEWNAME }}" + - name: Upload Release Artifact + env: + RELEASE_TAG: ${{ needs.create-release.outputs.tag_version }} + GH_TOKEN: ${{ github.token }} + run: gh release upload ${{ env.RELEASE_TAG }} ${{ env.NEWNAME }} diff --git a/.github/workflows/rworkflows.yml b/.github/workflows/rworkflows.yml new file mode 100644 index 0000000..790486e --- /dev/null +++ b/.github/workflows/rworkflows.yml @@ -0,0 +1,68 @@ +name: Continuous Integration / R Workflows +on: + workflow_dispatch: + push: + branches-ignore: + - master + - main + - RELEASE_** + - graphite-** + pull_request: + branches: + - master + - main + - devel + - RELEASE_** + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + optimize_ci: + runs-on: ubuntu-latest + outputs: + skip: ${{ steps.check_skip.outputs.skip }} + steps: + - name: Optimize CI + id: check_skip + uses: withgraphite/graphite-ci-action@main + with: + graphite_token: ${{secrets.GRAPHITE_TOKEN}} + rworkflows: + runs-on: ${{ matrix.config.os }} + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + container: ${{ matrix.config.cont }} + needs: [optimize_ci] + if: needs.optimize_ci.outputs.skip == 'false' + strategy: + fail-fast: ${{ false }} + matrix: + config: + - os: ubuntu-latest + bioc: devel + r: auto + cont: bioconductor/bioconductor_docker:devel + rspm: https://packagemanager.rstudio.com/cran/__linux__/focal/release + - os: macOS-latest + bioc: devel + r: auto + - os: windows-latest + bioc: devel + r: auto + steps: + - uses: neurogenomics/rworkflows@master + with: + run_bioccheck: ${{ true }} + run_rcmdcheck: ${{ true }} + as_cran: ${{ true }} + run_vignettes: ${{ true }} + has_testthat: ${{ true }} + run_covr: ${{ false }} + run_pkgdown: ${{ false }} + has_runit: ${{ false }} + has_latex: ${{ false }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run_docker: ${{ false }} + runner_os: ${{ runner.os }} + cache_version: cache-v1 diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml new file mode 100644 index 0000000..f528449 --- /dev/null +++ b/.github/workflows/test-coverage.yaml @@ -0,0 +1,62 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master, devel] + pull_request: + branches: [main, master, devel] + +name: test-coverage + +jobs: + optimize_ci: + runs-on: ubuntu-latest + outputs: + skip: ${{ steps.check_skip.outputs.skip }} + steps: + - name: Optimize CI + id: check_skip + uses: withgraphite/graphite-ci-action@main + with: + graphite_token: ${{secrets.GRAPHITE_TOKEN}} + test-coverage: + runs-on: ubuntu-latest + needs: [optimize_ci] + if: needs.optimize_ci.outputs.skip == 'false' + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + + steps: + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4 + + - uses: r-lib/actions/setup-r@e6be4b3706e0f39bc7a4cf4496a5f2c4cb840040 # v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@e6be4b3706e0f39bc7a4cf4496a5f2c4cb840040 # v2 + with: + extra-packages: any::covr + needs: coverage + + - name: Test coverage + run: | + covr::codecov( + quiet = FALSE, + clean = FALSE, + install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") + ) + shell: Rscript {0} + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: always() + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index db6d09b..3dd1023 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,7 +39,7 @@ repos: data/.*| .*\.(gz|xz|bz2)| (.*/|)codemeta.json| - COMMIT_EDITMSG + (.*)COMMIT_EDITMSG| )$ - id: readme-rmd-rendered - id: parsable-R diff --git a/DESCRIPTION b/DESCRIPTION index f678d05..b92b4f1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: PCSF Title: Network-based interpretation of highthroughput data -Version: 0.99.67 +Version: 0.99.68 Date: 2017-02-01 Author: Murodzhon Akhmedov, Amanda Kedaigle, Renan Escalante, Roberto Montemanni, Francesco Bertoni, Ernest Fraenkel, Ivo Kwee diff --git a/codemeta.json b/codemeta.json index a046d9d..3fb0438 100644 --- a/codemeta.json +++ b/codemeta.json @@ -5,7 +5,7 @@ "description": "The PCSF package performs an integrated analysis of highthroughput data using the interaction networks as a template, and interprets the biological landscape of interaction networks with respect to the data, which potentially leads to predictions of functional units. It also interactively visualize the resulting subnetwork with functional enrichment analysis.", "name": "PCSF: Network-based interpretation of highthroughput data", "license": "https://spdx.org/licenses/MIT", - "version": "0.99.67", + "version": "0.99.68", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", @@ -181,7 +181,7 @@ }, "SystemRequirements": null }, - "fileSize": "7741.971KB", + "fileSize": "7741.975KB", "codeRepository": "https://github.com/CogDisResLab/PCSF", "readme": "https://github.com/CogDisResLab/PCSF/blob/master/README.md" } diff --git a/inst/WORDLIST b/inst/WORDLIST index 45a098b..2818172 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -13,6 +13,7 @@ biomolecule biomolecules BMC CBL +ci CMake config downregulation From db26ffd062e90eaee4081ddd5c5adda7c0dfbb4c Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:18:26 -0400 Subject: [PATCH 06/13] build: update the DESCRIPTION file Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- DESCRIPTION | 36 ++++++++++++++++++++++-------------- codemeta.json | 42 +++++++++++++++++++++++++++++++----------- inst/WORDLIST | 7 +++++++ 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index b92b4f1..bc596d5 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,21 +1,26 @@ Type: Package Package: PCSF -Title: Network-based interpretation of highthroughput data -Version: 0.99.68 -Date: 2017-02-01 -Author: Murodzhon Akhmedov, Amanda Kedaigle, Renan Escalante, Roberto - Montemanni, Francesco Bertoni, Ernest Fraenkel, Ivo Kwee -Maintainer: Murodzhon Akhmedov -Description: The PCSF package performs an integrated analysis of - highthroughput data using the interaction networks as a template, and - interprets the biological landscape of interaction networks with - respect to the data, which potentially leads to predictions of - functional units. It also interactively visualize the resulting - subnetwork with functional enrichment analysis. +Title: Network-Based Interpretation of High-Throughput Data +Version: 1.0.69 +Date: 2024-10-26 +Authors@R: c( + person("Murodzhon", "Akhmedov", email = "murodzhon@idsia.ch", role = c("aut", "cre")), + person("Amanda", "Kedaigle", role = "aut"), + person("Renan", "Escalante", role = "aut"), + person("Roberto", "Montemanni", role = "aut"), + person("Francesco", "Bertoni", role = "aut"), + person("Ernest", "Fraenkel", role = "aut"), + person("Ivo", "Kwee", role = "aut")) +Description: Provides an integrated analysis of high-throughput data using interaction networks as templates. + The package interprets biological networks within the context of provided data, potentially predicting + functional units. Additionally, the package supports interactive visualization of subnetworks and + functional enrichment analysis. License: MIT + file LICENSE +URL: https://github.com/CogDisResLab/PCSF +BugReports: https://github.com/CogDisResLab/PCSF/issues Depends: + R (>= 4.0.0), igraph, - R (>= 3.1.0), visNetwork Imports: BH, @@ -27,9 +32,12 @@ Imports: topGO Suggests: knitr, - rmarkdown + rmarkdown, + testthat (>= 3.0.0) LinkingTo: BH, Rcpp Encoding: UTF-8 RoxygenNote: 7.3.2 +Config/testthat/edition: 3 +LazyData: true diff --git a/codemeta.json b/codemeta.json index 3fb0438..361542f 100644 --- a/codemeta.json +++ b/codemeta.json @@ -2,10 +2,12 @@ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "identifier": "PCSF", - "description": "The PCSF package performs an integrated analysis of highthroughput data using the interaction networks as a template, and interprets the biological landscape of interaction networks with respect to the data, which potentially leads to predictions of functional units. It also interactively visualize the resulting subnetwork with functional enrichment analysis.", - "name": "PCSF: Network-based interpretation of highthroughput data", + "description": "Provides an integrated analysis of high-throughput data using interaction networks as templates. The package interprets biological networks within the context of provided data, potentially predicting functional units. Additionally, the package supports interactive visualization of subnetworks and functional enrichment analysis.", + "name": "PCSF: Network-Based Interpretation of High-Throughput Data", + "codeRepository": "https://github.com/CogDisResLab/PCSF", + "issueTracker": "https://github.com/CogDisResLab/PCSF/issues", "license": "https://spdx.org/licenses/MIT", - "version": "0.99.68", + "version": "1.0.69", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", @@ -13,6 +15,12 @@ }, "runtimePlatform": "R version 4.4.1 (2024-06-14)", "author": [ + { + "@type": "Person", + "givenName": "Murodzhon", + "familyName": "Akhmedov", + "email": "murodzhon@idsia.ch" + }, { "@type": "Person", "givenName": "Amanda", @@ -76,10 +84,29 @@ "url": "https://cran.r-project.org" }, "sameAs": "https://CRAN.R-project.org/package=rmarkdown" + }, + { + "@type": "SoftwareApplication", + "identifier": "testthat", + "name": "testthat", + "version": ">= 3.0.0", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=testthat" } ], "softwareRequirements": { "1": { + "@type": "SoftwareApplication", + "identifier": "R", + "name": "R", + "version": ">= 4.0.0" + }, + "2": { "@type": "SoftwareApplication", "identifier": "igraph", "name": "igraph", @@ -91,12 +118,6 @@ }, "sameAs": "https://CRAN.R-project.org/package=igraph" }, - "2": { - "@type": "SoftwareApplication", - "identifier": "R", - "name": "R", - "version": ">= 3.1.0" - }, "3": { "@type": "SoftwareApplication", "identifier": "visNetwork", @@ -181,7 +202,6 @@ }, "SystemRequirements": null }, - "fileSize": "7741.975KB", - "codeRepository": "https://github.com/CogDisResLab/PCSF", + "fileSize": "7742.364KB", "readme": "https://github.com/CogDisResLab/PCSF/blob/master/README.md" } diff --git a/inst/WORDLIST b/inst/WORDLIST index 2818172..8c07ae2 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -3,6 +3,7 @@ Akhmedov al Alexa AliSajid +aut Avi Bertoni betweenness @@ -12,10 +13,13 @@ BioMed biomolecule biomolecules BMC +BugReports CBL ci CMake +CogDisResLab config +cre downregulation dplyr dysregulated @@ -36,6 +40,7 @@ GW highthroughput highthrougput Hs +https httr idsia igraph @@ -47,6 +52,7 @@ Ivo Kedaigle knitr Kwee +LazyData LeNail lightblue LinkingTo @@ -86,6 +92,7 @@ subnet subnetwork subnetworks subunits +testthat TGF Tgfb topGO From 1dc95639ae0de61915fbe768907c71d64a5e9a2f Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:24:57 -0400 Subject: [PATCH 07/13] build: add a renovate.json file for renovate integration Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- DESCRIPTION | 2 +- codemeta.json | 4 ++-- inst/WORDLIST | 13 +++++++++++++ renovate.json | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 renovate.json diff --git a/DESCRIPTION b/DESCRIPTION index bc596d5..d650ded 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: PCSF Title: Network-Based Interpretation of High-Throughput Data -Version: 1.0.69 +Version: 1.0.70 Date: 2024-10-26 Authors@R: c( person("Murodzhon", "Akhmedov", email = "murodzhon@idsia.ch", role = c("aut", "cre")), diff --git a/codemeta.json b/codemeta.json index 361542f..008b717 100644 --- a/codemeta.json +++ b/codemeta.json @@ -7,7 +7,7 @@ "codeRepository": "https://github.com/CogDisResLab/PCSF", "issueTracker": "https://github.com/CogDisResLab/PCSF/issues", "license": "https://spdx.org/licenses/MIT", - "version": "1.0.69", + "version": "1.0.70", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", @@ -202,6 +202,6 @@ }, "SystemRequirements": null }, - "fileSize": "7742.364KB", + "fileSize": "7743.344KB", "readme": "https://github.com/CogDisResLab/PCSF/blob/master/README.md" } diff --git a/inst/WORDLIST b/inst/WORDLIST index 8c07ae2..98d32b3 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -3,8 +3,11 @@ Akhmedov al Alexa AliSajid +assignees aut +automerge Avi +baseBranches Bertoni betweenness BH @@ -14,12 +17,15 @@ biomolecule biomolecules BMC BugReports +bumpVersion CBL ci CMake CogDisResLab config cre +definitelyTyped +dependencyDashboard downregulation dplyr dysregulated @@ -36,6 +42,7 @@ Francesco fuction functionla github +githubArtifactActions GW highthroughput highthrougput @@ -49,6 +56,7 @@ interactome intra iref Ivo +json Kedaigle knitr Kwee @@ -56,6 +64,7 @@ LazyData LeNail lightblue LinkingTo +matchManagers MERCHANTABILITY mesenchymal miscore @@ -68,12 +77,14 @@ noreply obrained Omics pacakge +packageRules PCSF PCSFe phos phosphoproteomic Phosphoproteomic phosphotyrosine +platformCommit PPI pre PSCF @@ -83,9 +94,11 @@ rando randomised Rcpp Renan +renovatebot rmarkdown RoxygenNote Sajid +semanticCommits Steiners sublicense subnet diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..d8949bd --- /dev/null +++ b/renovate.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "assignees": [ + "AliSajid" + ], + "baseBranches": [ + "devel" + ], + "dependencyDashboard": true, + "bumpVersion": "patch", + "extends": [ + "config:best-practices", + "group:definitelyTyped", + "group:githubArtifactActions" + ], + "labels": [ + "dependencies", + "renovate", + "merge-queue" + ], + "pre-commit": { + "enabled": true + }, + "packageRules": [ + { + "automerge": true, + "matchManagers": [ + "pre-commit", + "github-actions" + ], + "schedule": [ + "before 5am every weekday" + ] + } + ], + "platformCommit": "enabled", + "schedule": [ + "after 10pm every weekday", + "every weekend", + "before 5am every weekday" + ], + "semanticCommits": "enabled" +} From 9ebb6d4fca5ea0ac6a474d61006c410739b695f2 Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:32:11 -0400 Subject: [PATCH 08/13] build: ignore the .github directory Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- .Rbuildignore | 1 + DESCRIPTION | 2 +- codemeta.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index ecb9886..a993b1f 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -2,6 +2,7 @@ ^HISTORY\.rst$ ^LICENSE\.md$ ^\.Rproj\.user$ +^\.github$ ^\.pre-commit-config\.yaml$ ^codemeta\.json$ ^renv$ diff --git a/DESCRIPTION b/DESCRIPTION index d650ded..c2236a4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: PCSF Title: Network-Based Interpretation of High-Throughput Data -Version: 1.0.70 +Version: 1.0.71 Date: 2024-10-26 Authors@R: c( person("Murodzhon", "Akhmedov", email = "murodzhon@idsia.ch", role = c("aut", "cre")), diff --git a/codemeta.json b/codemeta.json index 008b717..496145f 100644 --- a/codemeta.json +++ b/codemeta.json @@ -7,7 +7,7 @@ "codeRepository": "https://github.com/CogDisResLab/PCSF", "issueTracker": "https://github.com/CogDisResLab/PCSF/issues", "license": "https://spdx.org/licenses/MIT", - "version": "1.0.70", + "version": "1.0.71", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", From b4d470f3ba4c5ebc21119dbe7a11dab9dfe5ab26 Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:37:33 -0400 Subject: [PATCH 09/13] test: add basic test infrastructure Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- DESCRIPTION | 2 +- codemeta.json | 2 +- tests/testthat.R | 12 ++++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/testthat.R diff --git a/DESCRIPTION b/DESCRIPTION index c2236a4..3149b6e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: PCSF Title: Network-Based Interpretation of High-Throughput Data -Version: 1.0.71 +Version: 1.0.72 Date: 2024-10-26 Authors@R: c( person("Murodzhon", "Akhmedov", email = "murodzhon@idsia.ch", role = c("aut", "cre")), diff --git a/codemeta.json b/codemeta.json index 496145f..9f3ddda 100644 --- a/codemeta.json +++ b/codemeta.json @@ -7,7 +7,7 @@ "codeRepository": "https://github.com/CogDisResLab/PCSF", "issueTracker": "https://github.com/CogDisResLab/PCSF/issues", "license": "https://spdx.org/licenses/MIT", - "version": "1.0.71", + "version": "1.0.72", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..2cfe74c --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(PCSF) + +test_check("PCSF") From 72db667b88ed14b708ce8102c547fcf8d93889e2 Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:47:17 -0400 Subject: [PATCH 10/13] build: fix the version numbers Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- DESCRIPTION | 2 +- codemeta.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 3149b6e..6530888 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: PCSF Title: Network-Based Interpretation of High-Throughput Data -Version: 1.0.72 +Version: 0.99.73 Date: 2024-10-26 Authors@R: c( person("Murodzhon", "Akhmedov", email = "murodzhon@idsia.ch", role = c("aut", "cre")), diff --git a/codemeta.json b/codemeta.json index 9f3ddda..176b375 100644 --- a/codemeta.json +++ b/codemeta.json @@ -7,7 +7,7 @@ "codeRepository": "https://github.com/CogDisResLab/PCSF", "issueTracker": "https://github.com/CogDisResLab/PCSF/issues", "license": "https://spdx.org/licenses/MIT", - "version": "1.0.72", + "version": "0.99.73", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", @@ -202,6 +202,6 @@ }, "SystemRequirements": null }, - "fileSize": "7743.344KB", + "fileSize": "7743.733KB", "readme": "https://github.com/CogDisResLab/PCSF/blob/master/README.md" } From 2bf34c6648b01f58452b4f77301e09ff250149cf Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:53:44 -0400 Subject: [PATCH 11/13] build: update DESCRIPTION for the new maintainer Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- DESCRIPTION | 5 +- codemeta.json | 16 +- inst/WORDLIST | 1 + renv.lock | 70 ++--- renv/activate.R | 681 +++++++++++++++++++++++++++--------------------- 5 files changed, 433 insertions(+), 340 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 6530888..4466cce 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,10 +1,11 @@ Type: Package Package: PCSF Title: Network-Based Interpretation of High-Throughput Data -Version: 0.99.73 +Version: 0.99.74 Date: 2024-10-26 Authors@R: c( - person("Murodzhon", "Akhmedov", email = "murodzhon@idsia.ch", role = c("aut", "cre")), + person("Imami", "Ali Sajid", role = c("aut", "cre"), email = "Ali.Sajid.Imami@gmail.com"), + person("Murodzhon", "Akhmedov", email = "murodzhon@idsia.ch", role = c("aut")), person("Amanda", "Kedaigle", role = "aut"), person("Renan", "Escalante", role = "aut"), person("Roberto", "Montemanni", role = "aut"), diff --git a/codemeta.json b/codemeta.json index 176b375..ca04a82 100644 --- a/codemeta.json +++ b/codemeta.json @@ -7,7 +7,7 @@ "codeRepository": "https://github.com/CogDisResLab/PCSF", "issueTracker": "https://github.com/CogDisResLab/PCSF/issues", "license": "https://spdx.org/licenses/MIT", - "version": "0.99.73", + "version": "0.99.74", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", @@ -15,6 +15,12 @@ }, "runtimePlatform": "R version 4.4.1 (2024-06-14)", "author": [ + { + "@type": "Person", + "givenName": "Imami", + "familyName": "Ali Sajid", + "email": "Ali.Sajid.Imami@gmail.com" + }, { "@type": "Person", "givenName": "Murodzhon", @@ -55,9 +61,9 @@ "maintainer": [ { "@type": "Person", - "givenName": "Murodzhon", - "familyName": "Akhmedov", - "email": "murodzhon@idsia.ch" + "givenName": "Imami", + "familyName": "Ali Sajid", + "email": "Ali.Sajid.Imami@gmail.com" } ], "softwareSuggestions": [ @@ -202,6 +208,6 @@ }, "SystemRequirements": null }, - "fileSize": "7743.733KB", + "fileSize": "7743.827KB", "readme": "https://github.com/CogDisResLab/PCSF/blob/master/README.md" } diff --git a/inst/WORDLIST b/inst/WORDLIST index 98d32b3..8dc03cc 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -43,6 +43,7 @@ fuction functionla github githubArtifactActions +gmail GW highthroughput highthrougput diff --git a/renv.lock b/renv.lock index 0fd5861..86e1806 100644 --- a/renv.lock +++ b/renv.lock @@ -216,7 +216,7 @@ }, "Matrix": { "Package": "Matrix", - "Version": "1.7-0", + "Version": "1.7-1", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -229,7 +229,7 @@ "stats", "utils" ], - "Hash": "1920b2f11133b12350024297d8a4ff4a" + "Hash": "5122bb14d8736372411f955e1b16bc8a" }, "R6": { "Package": "R6", @@ -333,13 +333,13 @@ }, "askpass": { "Package": "askpass", - "Version": "1.2.0", + "Version": "1.2.1", "Source": "Repository", - "Repository": "RSPM", + "Repository": "CRAN", "Requirements": [ "sys" ], - "Hash": "cad6cf7f1d5f6e906700b9d3e718c796" + "Hash": "c39f4155b3ceb1a9a2799d700fbd4b6a" }, "base64enc": { "Package": "base64enc", @@ -389,7 +389,7 @@ }, "bslib": { "Package": "bslib", - "Version": "0.7.0", + "Version": "0.8.0", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -407,7 +407,7 @@ "rlang", "sass" ], - "Hash": "8644cc53f43828f19133548195d7e59e" + "Hash": "b299c6741ca9746fb227debcb0f9fb6c" }, "cachem": { "Package": "cachem", @@ -422,14 +422,14 @@ }, "cli": { "Package": "cli", - "Version": "3.6.2", + "Version": "3.6.3", "Source": "Repository", - "Repository": "RSPM", + "Repository": "CRAN", "Requirements": [ "R", "utils" ], - "Hash": "1216ac65ac55ec0058a6f75d7ca0fd52" + "Hash": "b21916dd77a27642b447374a5d30ecf3" }, "cpp11": { "Package": "cpp11", @@ -465,14 +465,14 @@ }, "digest": { "Package": "digest", - "Version": "0.6.35", + "Version": "0.6.37", "Source": "Repository", - "Repository": "RSPM", + "Repository": "CRAN", "Requirements": [ "R", "utils" ], - "Hash": "698ece7ba5a4fa4559e3d537e7ec3d31" + "Hash": "33698c4b3127fc9f506654607fb73676" }, "dplyr": { "Package": "dplyr", @@ -499,14 +499,13 @@ }, "evaluate": { "Package": "evaluate", - "Version": "0.24.0", + "Version": "1.0.1", "Source": "Repository", "Repository": "CRAN", "Requirements": [ - "R", - "methods" + "R" ], - "Hash": "a1066cbc05caee9a4bf6d90f194ff4da" + "Hash": "3fd29944b231036ad67c3edb32e02201" }, "fansi": { "Package": "fansi", @@ -563,14 +562,14 @@ }, "glue": { "Package": "glue", - "Version": "1.7.0", + "Version": "1.8.0", "Source": "Repository", - "Repository": "RSPM", + "Repository": "CRAN", "Requirements": [ "R", "methods" ], - "Hash": "e0b3a53876554bd45879e596cdb10a52" + "Hash": "5899f1eaa825580172bb56c08266f37c" }, "graph": { "Package": "graph", @@ -679,13 +678,13 @@ }, "jsonlite": { "Package": "jsonlite", - "Version": "1.8.8", + "Version": "1.8.9", "Source": "Repository", - "Repository": "RSPM", + "Repository": "https://cran.r-project.org", "Requirements": [ "methods" ], - "Hash": "e1b9c55281c5adc4dd113652d9e26768" + "Hash": "4e993b65c2c3ffbffce7bb3e2c6f832b" }, "knitr": { "Package": "knitr", @@ -774,13 +773,13 @@ }, "openssl": { "Package": "openssl", - "Version": "2.2.0", + "Version": "2.2.2", "Source": "Repository", - "Repository": "CRAN", + "Repository": "https://cran.r-project.org", "Requirements": [ "askpass" ], - "Hash": "2bcca3848e4734eb3b16103bc9aa4b8e" + "Hash": "d413e0fef796c9401a4419485f709ca1" }, "org.Hs.eg.db": { "Package": "org.Hs.eg.db", @@ -849,13 +848,13 @@ }, "renv": { "Package": "renv", - "Version": "1.0.7", + "Version": "1.0.11", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "utils" ], - "Hash": "397b7b2a265bc5a7a06852524dabae20" + "Hash": "47623f66b4e80b3b0587bc5d7b309888" }, "rlang": { "Package": "rlang", @@ -907,10 +906,10 @@ }, "sys": { "Package": "sys", - "Version": "3.4.2", + "Version": "3.4.3", "Source": "Repository", - "Repository": "RSPM", - "Hash": "3a1be13d68d47a8cd0bfd74739ca1555" + "Repository": "CRAN", + "Hash": "de342ebfebdbf40477d0758d05426646" }, "tibble": { "Package": "tibble", @@ -949,13 +948,13 @@ }, "tinytex": { "Package": "tinytex", - "Version": "0.51", + "Version": "0.53", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "xfun" ], - "Hash": "d44e2fcd2e4e076f0aac540208559d1d" + "Hash": "9db859e8aabbb474293dde3097839420" }, "topGO": { "Package": "topGO", @@ -1033,15 +1032,16 @@ }, "xfun": { "Package": "xfun", - "Version": "0.44", + "Version": "0.48", "Source": "Repository", "Repository": "CRAN", "Requirements": [ + "R", "grDevices", "stats", "tools" ], - "Hash": "317a0538d32f4a009658bcedb7923f4b" + "Hash": "89e455b87c84e227eb7f60a1b4e5fe1f" }, "yaml": { "Package": "yaml", diff --git a/renv/activate.R b/renv/activate.R index d13f993..c5ca796 100644 --- a/renv/activate.R +++ b/renv/activate.R @@ -2,7 +2,7 @@ local({ # the requested version of renv - version <- "1.0.7" + version <- "1.0.11" attr(version, "sha") <- NULL # the project directory @@ -97,24 +97,84 @@ local({ if ("renv" %in% loadedNamespaces()) unloadNamespace("renv") - # load bootstrap tools + # load bootstrap tools + ansify <- function(text) { + if (renv_ansify_enabled()) + renv_ansify_enhanced(text) + else + renv_ansify_default(text) + } + + renv_ansify_enabled <- function() { + + override <- Sys.getenv("RENV_ANSIFY_ENABLED", unset = NA) + if (!is.na(override)) + return(as.logical(override)) + + pane <- Sys.getenv("RSTUDIO_CHILD_PROCESS_PANE", unset = NA) + if (identical(pane, "build")) + return(FALSE) + + testthat <- Sys.getenv("TESTTHAT", unset = "false") + if (tolower(testthat) %in% "true") + return(FALSE) + + iderun <- Sys.getenv("R_CLI_HAS_HYPERLINK_IDE_RUN", unset = "false") + if (tolower(iderun) %in% "false") + return(FALSE) + + TRUE + + } + + renv_ansify_default <- function(text) { + text + } + + renv_ansify_enhanced <- function(text) { + + # R help links + pattern <- "`\\?(renv::(?:[^`])+)`" + replacement <- "`\033]8;;ide:help:\\1\a?\\1\033]8;;\a`" + text <- gsub(pattern, replacement, text, perl = TRUE) + + # runnable code + pattern <- "`(renv::(?:[^`])+)`" + replacement <- "`\033]8;;ide:run:\\1\a\\1\033]8;;\a`" + text <- gsub(pattern, replacement, text, perl = TRUE) + + # return ansified text + text + + } + + renv_ansify_init <- function() { + + envir <- renv_envir_self() + if (renv_ansify_enabled()) + assign("ansify", renv_ansify_enhanced, envir = envir) + else + assign("ansify", renv_ansify_default, envir = envir) + + } + `%||%` <- function(x, y) { if (is.null(x)) y else x } - + catf <- function(fmt, ..., appendLF = TRUE) { - + quiet <- getOption("renv.bootstrap.quiet", default = FALSE) if (quiet) return(invisible()) - + msg <- sprintf(fmt, ...) cat(msg, file = stdout(), sep = if (appendLF) "\n" else "") - + invisible(msg) - + } - + header <- function(label, ..., prefix = "#", @@ -125,37 +185,40 @@ local({ n <- max(n - nchar(label) - nchar(prefix) - 2L, 8L) if (n <= 0) return(paste(prefix, label)) - + tail <- paste(rep.int(suffix, n), collapse = "") paste0(prefix, " ", label, " ", tail) - + } - + heredoc <- function(text, leave = 0) { - + # remove leading, trailing whitespace trimmed <- gsub("^\\s*\\n|\\n\\s*$", "", text) - + # split into lines lines <- strsplit(trimmed, "\n", fixed = TRUE)[[1L]] - + # compute common indent indent <- regexpr("[^[:space:]]", lines) common <- min(setdiff(indent, -1L)) - leave - paste(substring(lines, common), collapse = "\n") - + text <- paste(substring(lines, common), collapse = "\n") + + # substitute in ANSI links for executable renv code + ansify(text) + } - + startswith <- function(string, prefix) { substring(string, 1, nchar(prefix)) == prefix } - + bootstrap <- function(version, library) { - + friendly <- renv_bootstrap_version_friendly(version) section <- header(sprintf("Bootstrapping renv %s", friendly)) catf(section) - + # attempt to download renv catf("- Downloading renv ... ", appendLF = FALSE) withCallingHandlers( @@ -167,7 +230,7 @@ local({ ) catf("OK") on.exit(unlink(tarball), add = TRUE) - + # now attempt to install catf("- Installing renv ... ", appendLF = FALSE) withCallingHandlers( @@ -178,174 +241,177 @@ local({ } ) catf("OK") - + # add empty line to break up bootstrapping from normal output catf("") - + return(invisible()) } - + renv_bootstrap_tests_running <- function() { getOption("renv.tests.running", default = FALSE) } - + renv_bootstrap_repos <- function() { - + # get CRAN repository cran <- getOption("renv.repos.cran", "https://cloud.r-project.org") - + # check for repos override repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) if (!is.na(repos)) { - + # check for RSPM; if set, use a fallback repository for renv rspm <- Sys.getenv("RSPM", unset = NA) if (identical(rspm, repos)) repos <- c(RSPM = rspm, CRAN = cran) - + return(repos) - + } - + # check for lockfile repositories repos <- tryCatch(renv_bootstrap_repos_lockfile(), error = identity) if (!inherits(repos, "error") && length(repos)) return(repos) - + # retrieve current repos repos <- getOption("repos") - + # ensure @CRAN@ entries are resolved repos[repos == "@CRAN@"] <- cran - + # add in renv.bootstrap.repos if set default <- c(FALLBACK = "https://cloud.r-project.org") extra <- getOption("renv.bootstrap.repos", default = default) repos <- c(repos, extra) - + # remove duplicates that might've snuck in dupes <- duplicated(repos) | duplicated(names(repos)) repos[!dupes] - + } - + renv_bootstrap_repos_lockfile <- function() { - + lockpath <- Sys.getenv("RENV_PATHS_LOCKFILE", unset = "renv.lock") if (!file.exists(lockpath)) return(NULL) - + lockfile <- tryCatch(renv_json_read(lockpath), error = identity) if (inherits(lockfile, "error")) { warning(lockfile) return(NULL) } - + repos <- lockfile$R$Repositories if (length(repos) == 0) return(NULL) - + keys <- vapply(repos, `[[`, "Name", FUN.VALUE = character(1)) vals <- vapply(repos, `[[`, "URL", FUN.VALUE = character(1)) names(vals) <- keys - + return(vals) - + } - + renv_bootstrap_download <- function(version) { - + sha <- attr(version, "sha", exact = TRUE) - + methods <- if (!is.null(sha)) { - + # attempting to bootstrap a development version of renv c( function() renv_bootstrap_download_tarball(sha), function() renv_bootstrap_download_github(sha) ) - + } else { - + # attempting to bootstrap a release version of renv c( function() renv_bootstrap_download_tarball(version), function() renv_bootstrap_download_cran_latest(version), function() renv_bootstrap_download_cran_archive(version) ) - + } - + for (method in methods) { path <- tryCatch(method(), error = identity) if (is.character(path) && file.exists(path)) return(path) } - + stop("All download methods failed") - + } - + renv_bootstrap_download_impl <- function(url, destfile) { - + mode <- "wb" - + # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 fixup <- Sys.info()[["sysname"]] == "Windows" && substring(url, 1L, 5L) == "file:" - + if (fixup) mode <- "w+b" - + args <- list( url = url, destfile = destfile, mode = mode, quiet = TRUE ) - - if ("headers" %in% names(formals(utils::download.file))) - args$headers <- renv_bootstrap_download_custom_headers(url) - + + if ("headers" %in% names(formals(utils::download.file))) { + headers <- renv_bootstrap_download_custom_headers(url) + if (length(headers) && is.character(headers)) + args$headers <- headers + } + do.call(utils::download.file, args) - + } - + renv_bootstrap_download_custom_headers <- function(url) { - + headers <- getOption("renv.download.headers") if (is.null(headers)) return(character()) - + if (!is.function(headers)) stopf("'renv.download.headers' is not a function") - + headers <- headers(url) if (length(headers) == 0L) return(character()) - + if (is.list(headers)) headers <- unlist(headers, recursive = FALSE, use.names = TRUE) - + ok <- is.character(headers) && is.character(names(headers)) && all(nzchar(names(headers))) - + if (!ok) stop("invocation of 'renv.download.headers' did not return a named character vector") - + headers - + } - + renv_bootstrap_download_cran_latest <- function(version) { - + spec <- renv_bootstrap_download_cran_latest_find(version) type <- spec$type repos <- spec$repos - + baseurl <- utils::contrib.url(repos = repos, type = type) ext <- if (identical(type, "source")) ".tar.gz" @@ -355,161 +421,180 @@ local({ ".tgz" name <- sprintf("renv_%s%s", version, ext) url <- paste(baseurl, name, sep = "/") - + destfile <- file.path(tempdir(), name) status <- tryCatch( renv_bootstrap_download_impl(url, destfile), condition = identity ) - + if (inherits(status, "condition")) return(FALSE) - + # report success and return destfile - + } - + renv_bootstrap_download_cran_latest_find <- function(version) { - + # check whether binaries are supported on this system binary <- getOption("renv.bootstrap.binary", default = TRUE) && !identical(.Platform$pkgType, "source") && !identical(getOption("pkgType"), "source") && Sys.info()[["sysname"]] %in% c("Darwin", "Windows") - + types <- c(if (binary) "binary", "source") - + # iterate over types + repositories for (type in types) { for (repos in renv_bootstrap_repos()) { - + + # build arguments for utils::available.packages() call + args <- list(type = type, repos = repos) + + # add custom headers if available -- note that + # utils::available.packages() will pass this to download.file() + if ("headers" %in% names(formals(utils::download.file))) { + headers <- renv_bootstrap_download_custom_headers(repos) + if (length(headers) && is.character(headers)) + args$headers <- headers + } + # retrieve package database db <- tryCatch( as.data.frame( - utils::available.packages(type = type, repos = repos), + do.call(utils::available.packages, args), stringsAsFactors = FALSE ), error = identity ) - + if (inherits(db, "error")) next - + # check for compatible entry entry <- db[db$Package %in% "renv" & db$Version %in% version, ] if (nrow(entry) == 0) next - + # found it; return spec to caller spec <- list(entry = entry, type = type, repos = repos) return(spec) - + } } - + # if we got here, we failed to find renv fmt <- "renv %s is not available from your declared package repositories" stop(sprintf(fmt, version)) - + } - + renv_bootstrap_download_cran_archive <- function(version) { - + name <- sprintf("renv_%s.tar.gz", version) repos <- renv_bootstrap_repos() urls <- file.path(repos, "src/contrib/Archive/renv", name) destfile <- file.path(tempdir(), name) - + for (url in urls) { - + status <- tryCatch( renv_bootstrap_download_impl(url, destfile), condition = identity ) - + if (identical(status, 0L)) return(destfile) - + } - + return(FALSE) - + } - + renv_bootstrap_download_tarball <- function(version) { - + # if the user has provided the path to a tarball via # an environment variable, then use it tarball <- Sys.getenv("RENV_BOOTSTRAP_TARBALL", unset = NA) if (is.na(tarball)) return() - + # allow directories if (dir.exists(tarball)) { name <- sprintf("renv_%s.tar.gz", version) tarball <- file.path(tarball, name) } - + # bail if it doesn't exist if (!file.exists(tarball)) { - + # let the user know we weren't able to honour their request fmt <- "- RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist." msg <- sprintf(fmt, tarball) warning(msg) - + # bail return() - + } - + catf("- Using local tarball '%s'.", tarball) tarball - + + } + + renv_bootstrap_github_token <- function() { + for (envvar in c("GITHUB_TOKEN", "GITHUB_PAT", "GH_TOKEN")) { + envval <- Sys.getenv(envvar, unset = NA) + if (!is.na(envval)) + return(envval) + } } - + renv_bootstrap_download_github <- function(version) { - + enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") if (!identical(enabled, "TRUE")) return(FALSE) - + # prepare download options - pat <- Sys.getenv("GITHUB_PAT") - if (nzchar(Sys.which("curl")) && nzchar(pat)) { + token <- renv_bootstrap_github_token() + if (nzchar(Sys.which("curl")) && nzchar(token)) { fmt <- "--location --fail --header \"Authorization: token %s\"" - extra <- sprintf(fmt, pat) + extra <- sprintf(fmt, token) saved <- options("download.file.method", "download.file.extra") options(download.file.method = "curl", download.file.extra = extra) on.exit(do.call(base::options, saved), add = TRUE) - } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { + } else if (nzchar(Sys.which("wget")) && nzchar(token)) { fmt <- "--header=\"Authorization: token %s\"" - extra <- sprintf(fmt, pat) + extra <- sprintf(fmt, token) saved <- options("download.file.method", "download.file.extra") options(download.file.method = "wget", download.file.extra = extra) on.exit(do.call(base::options, saved), add = TRUE) } - + url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) name <- sprintf("renv_%s.tar.gz", version) destfile <- file.path(tempdir(), name) - + status <- tryCatch( renv_bootstrap_download_impl(url, destfile), condition = identity ) - + if (!identical(status, 0L)) return(FALSE) - + renv_bootstrap_download_augment(destfile) - + return(destfile) - + } - + # Add Sha to DESCRIPTION. This is stop gap until #890, after which we # can use renv::install() to fully capture metadata. renv_bootstrap_download_augment <- function(destfile) { @@ -517,13 +602,13 @@ local({ if (is.null(sha)) { return() } - + # Untar tempdir <- tempfile("renv-github-") on.exit(unlink(tempdir, recursive = TRUE), add = TRUE) untar(destfile, exdir = tempdir) pkgdir <- dir(tempdir, full.names = TRUE)[[1]] - + # Modify description desc_path <- file.path(pkgdir, "DESCRIPTION") desc_lines <- readLines(desc_path) @@ -537,173 +622,173 @@ local({ paste("RemoteSha: ", sha) ) writeLines(c(desc_lines[desc_lines != ""], remotes_fields), con = desc_path) - + # Re-tar local({ old <- setwd(tempdir) on.exit(setwd(old), add = TRUE) - + tar(destfile, compression = "gzip") }) invisible() } - + # Extract the commit hash from a git archive. Git archives include the SHA1 # hash as the comment field of the tarball pax extended header # (see https://www.kernel.org/pub/software/scm/git/docs/git-archive.html) # For GitHub archives this should be the first header after the default one # (512 byte) header. renv_bootstrap_git_extract_sha1_tar <- function(bundle) { - + # open the bundle for reading # We use gzcon for everything because (from ?gzcon) # > Reading from a connection which does not supply a 'gzip' magic # > header is equivalent to reading from the original connection conn <- gzcon(file(bundle, open = "rb", raw = TRUE)) on.exit(close(conn)) - + # The default pax header is 512 bytes long and the first pax extended header # with the comment should be 51 bytes long # `52 comment=` (11 chars) + 40 byte SHA1 hash len <- 0x200 + 0x33 res <- rawToChar(readBin(conn, "raw", n = len)[0x201:len]) - + if (grepl("^52 comment=", res)) { sub("52 comment=", "", res) } else { NULL } } - + renv_bootstrap_install <- function(version, tarball, library) { - + # attempt to install it into project library dir.create(library, showWarnings = FALSE, recursive = TRUE) output <- renv_bootstrap_install_impl(library, tarball) - + # check for successful install status <- attr(output, "status") if (is.null(status) || identical(status, 0L)) return(status) - + # an error occurred; report it header <- "installation of renv failed" lines <- paste(rep.int("=", nchar(header)), collapse = "") text <- paste(c(header, lines, output), collapse = "\n") stop(text) - + } - + renv_bootstrap_install_impl <- function(library, tarball) { - + # invoke using system2 so we can capture and report output bin <- R.home("bin") exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" R <- file.path(bin, exe) - + args <- c( "--vanilla", "CMD", "INSTALL", "--no-multiarch", "-l", shQuote(path.expand(library)), shQuote(path.expand(tarball)) ) - + system2(R, args, stdout = TRUE, stderr = TRUE) - + } - + renv_bootstrap_platform_prefix <- function() { - + # construct version prefix version <- paste(R.version$major, R.version$minor, sep = ".") prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-") - + # include SVN revision for development versions of R # (to avoid sharing platform-specific artefacts with released versions of R) devel <- identical(R.version[["status"]], "Under development (unstable)") || identical(R.version[["nickname"]], "Unsuffered Consequences") - + if (devel) prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") - + # build list of path components components <- c(prefix, R.version$platform) - + # include prefix if provided by user prefix <- renv_bootstrap_platform_prefix_impl() if (!is.na(prefix) && nzchar(prefix)) components <- c(prefix, components) - + # build prefix paste(components, collapse = "/") - + } - + renv_bootstrap_platform_prefix_impl <- function() { - + # if an explicit prefix has been supplied, use it prefix <- Sys.getenv("RENV_PATHS_PREFIX", unset = NA) if (!is.na(prefix)) return(prefix) - + # if the user has requested an automatic prefix, generate it auto <- Sys.getenv("RENV_PATHS_PREFIX_AUTO", unset = NA) if (is.na(auto) && getRversion() >= "4.4.0") auto <- "TRUE" - + if (auto %in% c("TRUE", "True", "true", "1")) return(renv_bootstrap_platform_prefix_auto()) - + # empty string on failure "" - + } - + renv_bootstrap_platform_prefix_auto <- function() { - + prefix <- tryCatch(renv_bootstrap_platform_os(), error = identity) if (inherits(prefix, "error") || prefix %in% "unknown") { - + msg <- paste( "failed to infer current operating system", "please file a bug report at https://github.com/rstudio/renv/issues", sep = "; " ) - + warning(msg) - + } - + prefix - + } - + renv_bootstrap_platform_os <- function() { - + sysinfo <- Sys.info() sysname <- sysinfo[["sysname"]] - + # handle Windows + macOS up front if (sysname == "Windows") return("windows") else if (sysname == "Darwin") return("macos") - + # check for os-release files for (file in c("/etc/os-release", "/usr/lib/os-release")) if (file.exists(file)) return(renv_bootstrap_platform_os_via_os_release(file, sysinfo)) - + # check for redhat-release files if (file.exists("/etc/redhat-release")) return(renv_bootstrap_platform_os_via_redhat_release()) - + "unknown" - + } - + renv_bootstrap_platform_os_via_os_release <- function(file, sysinfo) { - + # read /etc/os-release release <- utils::read.table( file = file, @@ -713,13 +798,13 @@ local({ comment.char = "#", stringsAsFactors = FALSE ) - + vars <- as.list(release$Value) names(vars) <- release$Key - + # get os name os <- tolower(sysinfo[["sysname"]]) - + # read id id <- "unknown" for (field in c("ID", "ID_LIKE")) { @@ -728,7 +813,7 @@ local({ break } } - + # read version version <- "unknown" for (field in c("UBUNTU_CODENAME", "VERSION_CODENAME", "VERSION_ID", "BUILD_ID")) { @@ -737,17 +822,17 @@ local({ break } } - + # join together paste(c(os, id, version), collapse = "-") - + } - + renv_bootstrap_platform_os_via_redhat_release <- function() { - + # read /etc/redhat-release contents <- readLines("/etc/redhat-release", warn = FALSE) - + # infer id id <- if (grepl("centos", contents, ignore.case = TRUE)) "centos" @@ -755,73 +840,73 @@ local({ "redhat" else "unknown" - + # try to find a version component (very hacky) version <- "unknown" - + parts <- strsplit(contents, "[[:space:]]")[[1L]] for (part in parts) { - + nv <- tryCatch(numeric_version(part), error = identity) if (inherits(nv, "error")) next - + version <- nv[1, 1] break - + } - + paste(c("linux", id, version), collapse = "-") - + } - + renv_bootstrap_library_root_name <- function(project) { - + # use project name as-is if requested asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE") if (asis) return(basename(project)) - + # otherwise, disambiguate based on project's path id <- substring(renv_bootstrap_hash_text(project), 1L, 8L) paste(basename(project), id, sep = "-") - + } - + renv_bootstrap_library_root <- function(project) { - + prefix <- renv_bootstrap_profile_prefix() - + path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) if (!is.na(path)) return(paste(c(path, prefix), collapse = "/")) - + path <- renv_bootstrap_library_root_impl(project) if (!is.null(path)) { name <- renv_bootstrap_library_root_name(project) return(paste(c(path, prefix, name), collapse = "/")) } - + renv_bootstrap_paths_renv("library", project = project) - + } - + renv_bootstrap_library_root_impl <- function(project) { - + root <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) if (!is.na(root)) return(root) - + type <- renv_bootstrap_project_type(project) if (identical(type, "package")) { userdir <- renv_bootstrap_user_dir() return(file.path(userdir, "library")) } - + } - + renv_bootstrap_validate_version <- function(version, description = NULL) { - + # resolve description file # # avoid passing lib.loc to `packageDescription()` below, since R will @@ -829,17 +914,17 @@ local({ # this function should only be called after 'renv' is loaded # https://github.com/rstudio/renv/issues/1625 description <- description %||% packageDescription("renv") - + # check whether requested version 'version' matches loaded version of renv sha <- attr(version, "sha", exact = TRUE) valid <- if (!is.null(sha)) renv_bootstrap_validate_version_dev(sha, description) else renv_bootstrap_validate_version_release(version, description) - + if (valid) return(TRUE) - + # the loaded version of renv doesn't match the requested version; # give the user instructions on how to proceed dev <- identical(description[["RemoteType"]], "github") @@ -847,103 +932,103 @@ local({ paste("rstudio/renv", description[["RemoteSha"]], sep = "@") else paste("renv", description[["Version"]], sep = "@") - + # display both loaded version + sha if available friendly <- renv_bootstrap_version_friendly( version = description[["Version"]], sha = if (dev) description[["RemoteSha"]] ) - + fmt <- heredoc(" renv %1$s was loaded from project library, but this project is configured to use renv %2$s. - Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile. - Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library. ") catf(fmt, friendly, renv_bootstrap_version_friendly(version), remote) - + FALSE - + } - + renv_bootstrap_validate_version_dev <- function(version, description) { expected <- description[["RemoteSha"]] is.character(expected) && startswith(expected, version) } - + renv_bootstrap_validate_version_release <- function(version, description) { expected <- description[["Version"]] is.character(expected) && identical(expected, version) } - + renv_bootstrap_hash_text <- function(text) { - + hashfile <- tempfile("renv-hash-") on.exit(unlink(hashfile), add = TRUE) - + writeLines(text, con = hashfile) tools::md5sum(hashfile) - + } - + renv_bootstrap_load <- function(project, libpath, version) { - + # try to load renv from the project library if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) return(FALSE) - + # warn if the version of renv loaded does not match renv_bootstrap_validate_version(version) - + # execute renv load hooks, if any hooks <- getHook("renv::autoload") for (hook in hooks) if (is.function(hook)) tryCatch(hook(), error = warnify) - + # load the project renv::load(project) - + TRUE - + } - + renv_bootstrap_profile_load <- function(project) { - + # if RENV_PROFILE is already set, just use that profile <- Sys.getenv("RENV_PROFILE", unset = NA) if (!is.na(profile) && nzchar(profile)) return(profile) - + # check for a profile file (nothing to do if it doesn't exist) path <- renv_bootstrap_paths_renv("profile", profile = FALSE, project = project) if (!file.exists(path)) return(NULL) - + # read the profile, and set it if it exists contents <- readLines(path, warn = FALSE) if (length(contents) == 0L) return(NULL) - + # set RENV_PROFILE profile <- contents[[1L]] if (!profile %in% c("", "default")) Sys.setenv(RENV_PROFILE = profile) - + profile - + } - + renv_bootstrap_profile_prefix <- function() { profile <- renv_bootstrap_profile_get() if (!is.null(profile)) return(file.path("profiles", profile, "renv")) } - + renv_bootstrap_profile_get <- function() { profile <- Sys.getenv("RENV_PROFILE", unset = "") renv_bootstrap_profile_normalize(profile) } - + renv_bootstrap_profile_set <- function(profile) { profile <- renv_bootstrap_profile_normalize(profile) if (is.null(profile)) @@ -951,25 +1036,25 @@ local({ else Sys.setenv(RENV_PROFILE = profile) } - + renv_bootstrap_profile_normalize <- function(profile) { - + if (is.null(profile) || profile %in% c("", "default")) return(NULL) - + profile - + } - + renv_bootstrap_path_absolute <- function(path) { - + substr(path, 1L, 1L) %in% c("~", "/", "\\") || ( substr(path, 1L, 1L) %in% c(letters, LETTERS) && substr(path, 2L, 3L) %in% c(":/", ":\\") ) - + } - + renv_bootstrap_paths_renv <- function(..., profile = TRUE, project = NULL) { renv <- Sys.getenv("RENV_PATHS_RENV", unset = "renv") root <- if (renv_bootstrap_path_absolute(renv)) NULL else project @@ -977,50 +1062,50 @@ local({ components <- c(root, renv, prefix, ...) paste(components, collapse = "/") } - + renv_bootstrap_project_type <- function(path) { - + descpath <- file.path(path, "DESCRIPTION") if (!file.exists(descpath)) return("unknown") - + desc <- tryCatch( read.dcf(descpath, all = TRUE), error = identity ) - + if (inherits(desc, "error")) return("unknown") - + type <- desc$Type if (!is.null(type)) return(tolower(type)) - + package <- desc$Package if (!is.null(package)) return("package") - + "unknown" - + } - + renv_bootstrap_user_dir <- function() { dir <- renv_bootstrap_user_dir_impl() path.expand(chartr("\\", "/", dir)) } - + renv_bootstrap_user_dir_impl <- function() { - + # use local override if set override <- getOption("renv.userdir.override") if (!is.null(override)) return(override) - + # use R_user_dir if available tools <- asNamespace("tools") if (is.function(tools$R_user_dir)) return(tools$R_user_dir("renv", "cache")) - + # try using our own backfill for older versions of R envvars <- c("R_USER_CACHE_DIR", "XDG_CACHE_HOME") for (envvar in envvars) { @@ -1028,7 +1113,7 @@ local({ if (!is.na(root)) return(file.path(root, "R/renv")) } - + # use platform-specific default fallbacks if (Sys.info()[["sysname"]] == "Windows") file.path(Sys.getenv("LOCALAPPDATA"), "R/cache/R/renv") @@ -1036,109 +1121,109 @@ local({ "~/Library/Caches/org.R-project.R/R/renv" else "~/.cache/R/renv" - + } - + renv_bootstrap_version_friendly <- function(version, shafmt = NULL, sha = NULL) { sha <- sha %||% attr(version, "sha", exact = TRUE) parts <- c(version, sprintf(shafmt %||% " [sha: %s]", substring(sha, 1L, 7L))) paste(parts, collapse = "") } - + renv_bootstrap_exec <- function(project, libpath, version) { if (!renv_bootstrap_load(project, libpath, version)) renv_bootstrap_run(version, libpath) } - + renv_bootstrap_run <- function(version, libpath) { - + # perform bootstrap bootstrap(version, libpath) - + # exit early if we're just testing bootstrap if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) return(TRUE) - + # try again to load if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { return(renv::load(project = getwd())) } - + # failed to download or load renv; warn the user msg <- c( "Failed to find an renv installation: the project will not be loaded.", "Use `renv::activate()` to re-initialize the project." ) - + warning(paste(msg, collapse = "\n"), call. = FALSE) - + } - + renv_json_read <- function(file = NULL, text = NULL) { - + jlerr <- NULL - + # if jsonlite is loaded, use that instead if ("jsonlite" %in% loadedNamespaces()) { - + json <- tryCatch(renv_json_read_jsonlite(file, text), error = identity) if (!inherits(json, "error")) return(json) - + jlerr <- json - + } - + # otherwise, fall back to the default JSON reader json <- tryCatch(renv_json_read_default(file, text), error = identity) if (!inherits(json, "error")) return(json) - + # report an error if (!is.null(jlerr)) stop(jlerr) else stop(json) - + } - + renv_json_read_jsonlite <- function(file = NULL, text = NULL) { text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") jsonlite::fromJSON(txt = text, simplifyVector = FALSE) } - + renv_json_read_default <- function(file = NULL, text = NULL) { - + # find strings in the JSON text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") pattern <- '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' locs <- gregexpr(pattern, text, perl = TRUE)[[1]] - + # if any are found, replace them with placeholders replaced <- text strings <- character() replacements <- character() - + if (!identical(c(locs), -1L)) { - + # get the string values starts <- locs ends <- locs + attr(locs, "match.length") - 1L strings <- substring(text, starts, ends) - + # only keep those requiring escaping strings <- grep("[[\\]{}:]", strings, perl = TRUE, value = TRUE) - + # compute replacements replacements <- sprintf('"\032%i\032"', seq_along(strings)) - + # replace the strings mapply(function(string, replacement) { replaced <<- sub(string, replacement, replaced, fixed = TRUE) }, strings, replacements) - + } - + # transform the JSON into something the R parser understands transformed <- replaced transformed <- gsub("{}", "`names<-`(list(), character())", transformed, fixed = TRUE) @@ -1146,38 +1231,38 @@ local({ transformed <- gsub("[]}]", ")", transformed, perl = TRUE) transformed <- gsub(":", "=", transformed, fixed = TRUE) text <- paste(transformed, collapse = "\n") - + # parse it json <- parse(text = text, keep.source = FALSE, srcfile = NULL)[[1L]] - + # construct map between source strings, replaced strings map <- as.character(parse(text = strings)) names(map) <- as.character(parse(text = replacements)) - + # convert to list map <- as.list(map) - + # remap strings in object remapped <- renv_json_read_remap(json, map) - + # evaluate eval(remapped, envir = baseenv()) - + } - + renv_json_read_remap <- function(json, map) { - + # fix names if (!is.null(names(json))) { lhs <- match(names(json), names(map), nomatch = 0L) rhs <- match(names(map), names(json), nomatch = 0L) names(json)[rhs] <- map[lhs] } - + # fix values if (is.character(json)) return(map[[json]] %||% json) - + # handle true, false, null if (is.name(json)) { text <- as.character(json) @@ -1188,16 +1273,16 @@ local({ else if (text == "null") return(NULL) } - + # recurse if (is.recursive(json)) { for (i in seq_along(json)) { json[i] <- list(renv_json_read_remap(json[[i]], map)) } } - + json - + } # load the renv profile, if any From 2b0ebce5f2efd2fb8815450321f295cf33bfb7de Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 19:56:02 -0400 Subject: [PATCH 12/13] build: add configs for markdownlint and lintr Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- .lintr | 12 ++++++++++++ .markdownlint.json | 16 ++++++++++++++++ .markdownlintignore | 3 +++ DESCRIPTION | 2 +- codemeta.json | 4 ++-- inst/WORDLIST | 1 + 6 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 .lintr create mode 100644 .markdownlint.json create mode 100644 .markdownlintignore diff --git a/.lintr b/.lintr new file mode 100644 index 0000000..2e3aaae --- /dev/null +++ b/.lintr @@ -0,0 +1,12 @@ +linters: linters_with_tags( + tags = c("default", "style", "misc", "potential-bug", "performance", "documentation", "risky", "package_development"), + line_length_linter(length = 80L), + indentation_linter(indent = 4L, hanging_indent_style = "never"), + undesirable_function_linter(modify_defaults( + defaults = default_undesirable_functions, library = NULL)), + object_usage_linter = NULL, + object_name_linter(styles = c("camelCase"))) +encoding: "UTF-8" +exclusions: list( + "renv/activate.R", + "doc/") diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..dff59bf --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,16 @@ +{ + "MD003": { + "style": "atx" + }, + "MD007": { + "indent": 2 + }, + "MD013": false, + "MD024": false, + "MD033": false, + "MD041": false, + "MD036": false, + "default": true, + "no-hard-tabs": true, + "whitespace": false +} diff --git a/.markdownlintignore b/.markdownlintignore new file mode 100644 index 0000000..0e5fe1c --- /dev/null +++ b/.markdownlintignore @@ -0,0 +1,3 @@ +^LICENSE +.github/**/* +meta/LICENSE-HEADER diff --git a/DESCRIPTION b/DESCRIPTION index 4466cce..5c37115 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: PCSF Title: Network-Based Interpretation of High-Throughput Data -Version: 0.99.74 +Version: 0.99.75 Date: 2024-10-26 Authors@R: c( person("Imami", "Ali Sajid", role = c("aut", "cre"), email = "Ali.Sajid.Imami@gmail.com"), diff --git a/codemeta.json b/codemeta.json index ca04a82..cdb86db 100644 --- a/codemeta.json +++ b/codemeta.json @@ -7,7 +7,7 @@ "codeRepository": "https://github.com/CogDisResLab/PCSF", "issueTracker": "https://github.com/CogDisResLab/PCSF/issues", "license": "https://spdx.org/licenses/MIT", - "version": "0.99.74", + "version": "0.99.75", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", @@ -208,6 +208,6 @@ }, "SystemRequirements": null }, - "fileSize": "7743.827KB", + "fileSize": "7743.831KB", "readme": "https://github.com/CogDisResLab/PCSF/blob/master/README.md" } diff --git a/inst/WORDLIST b/inst/WORDLIST index 8dc03cc..f84cbbf 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -4,6 +4,7 @@ al Alexa AliSajid assignees +atx aut automerge Avi From f0d24272ca67c7890b14cc8648a588d2d3e2feb2 Mon Sep 17 00:00:00 2001 From: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> Date: Sat, 26 Oct 2024 20:11:12 -0400 Subject: [PATCH 13/13] build: update renv Signed-off-by: Ali Sajid Imami <395482+AliSajid@users.noreply.github.com> --- DESCRIPTION | 2 +- codemeta.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 5c37115..4cfe371 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: PCSF Title: Network-Based Interpretation of High-Throughput Data -Version: 0.99.75 +Version: 0.99.76 Date: 2024-10-26 Authors@R: c( person("Imami", "Ali Sajid", role = c("aut", "cre"), email = "Ali.Sajid.Imami@gmail.com"), diff --git a/codemeta.json b/codemeta.json index cdb86db..349b82f 100644 --- a/codemeta.json +++ b/codemeta.json @@ -7,7 +7,7 @@ "codeRepository": "https://github.com/CogDisResLab/PCSF", "issueTracker": "https://github.com/CogDisResLab/PCSF/issues", "license": "https://spdx.org/licenses/MIT", - "version": "0.99.75", + "version": "0.99.76", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R",