From 8a3d8ad5c96bed445c2bb0624c117c42faadba35 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 16 Aug 2024 17:42:40 -0500 Subject: [PATCH 01/14] Update stop conditions; add JVM init check --- R/class_haplotype_graph.R | 8 ++++++-- R/class_phg_con_server.R | 2 +- R/class_phg_metrics.R | 8 ++++---- R/filter_ref_ranges.R | 2 +- R/filter_samples.R | 2 +- R/utils_api_brapi.R | 2 +- R/utils_general.R | 29 +++++++++++++++++++++++++++++ R/utils_jvm.R | 4 ++-- R/utils_metrics.R | 30 +++++++++++++++++++++++++++++- tests/testthat/setup.R | 21 ++++++++++++++++----- 10 files changed, 90 insertions(+), 18 deletions(-) diff --git a/R/class_haplotype_graph.R b/R/class_haplotype_graph.R index 79dd674..a3ca3ef 100644 --- a/R/class_haplotype_graph.R +++ b/R/class_haplotype_graph.R @@ -80,12 +80,16 @@ setValidity("HaplotypeGraph", function(object) { buildHaplotypeGraph <- function( phgLocalCon ) { + if (!isJvmInitialized()) { + rlang::abort("JVM is not initialized - please run 'initPhg()' with PHGv2 library path") + } + if (!is(phgLocalCon, "PHGLocalCon")) { - stop("phgLocalCon object is not of type PHGLocalCon") + rlang::abort("phgLocalCon object is not of type PHGLocalCon") } if (!is.na(host(phgLocalCon))) { - stop("TileDB retrieval methods currently not implemented") + rlang::abort("TileDB retrieval methods currently not implemented") } else { jvmGraph <- hapGraphConstructor(hVcfFiles(phgLocalCon)) } diff --git a/R/class_phg_con_server.R b/R/class_phg_con_server.R index 20b970b..a0ddcbf 100644 --- a/R/class_phg_con_server.R +++ b/R/class_phg_con_server.R @@ -144,7 +144,7 @@ PHGServerCon <- function( # Check if at least mandatory serverinfo endpoint can be called if (!brapiEndpointExists(url)) { - stop("Cannot resolve mandatory endpoint: {serverinfo}", call. = FALSE) + rlang::abort("Cannot resolve mandatory endpoint: {serverinfo}", call. = FALSE) } methods::new( diff --git a/R/class_phg_metrics.R b/R/class_phg_metrics.R index 772c1fc..bdacadb 100644 --- a/R/class_phg_metrics.R +++ b/R/class_phg_metrics.R @@ -55,7 +55,7 @@ PHGMetrics <- function(paths = NULL, metadata = NULL) { # V02 - if no files or directories exist: exception if (length(dirFilt) == 0 && length(filFilt) == 0) { - stop("No valid paths given") + rlang::abort("No valid paths given") } # V03 - recursively pull metric files from directories (if found) @@ -93,7 +93,7 @@ PHGMetrics <- function(paths = NULL, metadata = NULL) { # V07 - if no .tsv or .anchorspro files are identified: exception if (length(gvcfMet) == 0 && length(algnMet) == 0) { - stop("No valid gVCF or AnchorWave files detected from paths") + rlang::abort("No valid gVCF or AnchorWave files detected from paths") } # If files are fully vetted: read into memory and add to list @@ -366,7 +366,7 @@ setMethod( } if (!name %in% metricsIds(object) && !is.null(name)) { - stop("Provided 'name' not found in object") + rlang::abort("Provided 'name' not found in object") } if (!is.null(name) && is.null(type)) { @@ -383,7 +383,7 @@ setMethod( if (!is.null(type) && is.null(name)) { if (!type %in% PHG_METRICS$VALID_METRICS_IDS) { - stop("Provided 'type' not a valid metrics ID") + rlang::abort("Provided 'type' not a valid metrics ID") } metrics <- switch (type, diff --git a/R/filter_ref_ranges.R b/R/filter_ref_ranges.R index 788820a..cdef48e 100644 --- a/R/filter_ref_ranges.R +++ b/R/filter_ref_ranges.R @@ -18,7 +18,7 @@ filterRefRangesFromPhgDataSet <- function(object, gRanges) { IRanges::subsetByOverlaps(refRanges, gRanges) ) if (length(fRefRanges) == 0) { - stop("No reference ranges identified with given query") + rlang::abort("No reference ranges identified with given query") } # Filter hap ID matrix by ref range column diff --git a/R/filter_samples.R b/R/filter_samples.R index 8400632..0990c4e 100644 --- a/R/filter_samples.R +++ b/R/filter_samples.R @@ -13,7 +13,7 @@ filterSamplesFromPhgDataSet <- function(object, sampleIds) { # Filter for samples in ID vector fSamples <- samples[samples %in% sampleIds] if (length(fSamples) == 0) { - stop("No samples identified with given query") + rlang::abort("No samples identified with given query") } # Generate a regex pattern for row subsetting diff --git a/R/utils_api_brapi.R b/R/utils_api_brapi.R index 5cf95bc..6a3bc8e 100644 --- a/R/utils_api_brapi.R +++ b/R/utils_api_brapi.R @@ -131,7 +131,7 @@ parseJSON <- function(url, verbose = FALSE) { ) if (is.na(res)) { - stop("Could not resolve BrAPI endpoint") + rlang::abort("Could not resolve BrAPI endpoint") } return(res) diff --git a/R/utils_general.R b/R/utils_general.R index 6d78483..76922a9 100644 --- a/R/utils_general.R +++ b/R/utils_general.R @@ -9,6 +9,35 @@ camelToSnake <- function(x) { } +## ---- +# Check if the JVM is Initialized +# +# @description +# This function checks whether the Java Virtual Machine (JVM) has been +# initialized using the `rJava` package. +# +# The function attempts to retrieve the current Java version by calling a Java +# method. If the JVM is not initialized, an error is caught, and the function +# returns `FALSE`. If the JVM is initialized, it returns `TRUE`. +# +# @return +# A logical value indicating whether the JVM has been initialized. Returns +# `TRUE` if the JVM is initialized, otherwise `FALSE`. +isJvmInitialized <- function() { + tryCatch({ + # Attempt to get the current Java version + javaVersion <- rJava::.jcall( + obj = "java/lang/System", + returnSig = "S", + method = "getProperty", "java.version" + ) + return(TRUE) + }, error = function(e) { + return(FALSE) + }) +} + + ## ---- #' @title #' User-defined function for pre-evaluated names in vectors diff --git a/R/utils_jvm.R b/R/utils_jvm.R index 8f50de7..008333e 100644 --- a/R/utils_jvm.R +++ b/R/utils_jvm.R @@ -44,7 +44,7 @@ initPhg <- function(phgPath, verbose = TRUE) { # @param kl A PHG/Kotlin RList object kotlinListToRDataFrame <- function(kl) { if (!grepl("phgv2_r_list", kl$toString())) { - stop("Object does not have a 'RList' signature") + rlang::abort("Object does not have a 'RList' signature") } rdf <- kl$getMatrixData() |> @@ -63,7 +63,7 @@ kotlinListToRDataFrame <- function(kl) { # @param kmat A PHG/Kotlin (Int|Dbl|String)Matrix object kotlin2DArrayToRMatrix <- function(kmat) { if (!grepl("MatrixWithNames", kmat$getClass()$toString())) { - stop("Object does not have a 'MatrixWithNames' signature") + rlang::abort("Object does not have a 'MatrixWithNames' signature") } rmat <- kmat$getMatrixData() |> rJava::.jevalArray(simplify = TRUE) diff --git a/R/utils_metrics.R b/R/utils_metrics.R index a957485..62f0c84 100644 --- a/R/utils_metrics.R +++ b/R/utils_metrics.R @@ -3,7 +3,8 @@ ## ---- # Find text lines for validation sans "comments" # -# @filePath plain text file to check +# @param filePath +# plain text file to check findFirstNonCommentLine <- function(filePath) { connection <- file(filePath, open = "r") firstLine <- NULL @@ -23,6 +24,7 @@ findFirstNonCommentLine <- function(filePath) { ## ---- # Generate a Colored and Formatted Message Based on Success or Failure # +# @description # This function creates a custom message incorporating user-defined # actions, notes, and a success indicator. It uses color coding to # distinguish between successful and warning messages. If the operation @@ -98,12 +100,38 @@ validateHeaders <- function(line, validHeaders, delimiter = "\t") { # /// Primary functions ///////////////////////////////////////////// +## ---- +# Apply Custom Grey Color to Text +# +# @description +# This function applies a custom grey ANSI style to the input text using the +# specified grey shade. +# +# The function generates a grey color based on the `shade` parameter and then +# uses the `cli::make_ansi_style` function to apply the corresponding ANSI +# styling to the text. The styled text is returned with the specified grey +# shade. +# +# @param text +# A character string. The text to be styled with a grey color. +# @param shade +# An integer (default is 50). The shade of grey to apply, which should be +# between 0 and 100. +# +# @return The input text styled with the specified grey shade, returned as a +# character string with ANSI styling. +# +# @examples +# # Example usage +# colCustGrey("This is grey text", shade = 70) +# colCustGrey("This is darker grey text", shade = 30) colCustGrey <- function(text, shade = 50) { greyColor <- paste0("grey", shade) style <- cli::make_ansi_style(greyColor) style(text) } + ## ---- # Helper function to display dimensions of metrics # diff --git a/tests/testthat/setup.R b/tests/testthat/setup.R index 453ba4b..bcb1fa6 100644 --- a/tests/testthat/setup.R +++ b/tests/testthat/setup.R @@ -26,7 +26,7 @@ getLatestReleaseUrl <- function(repo) { # Check if the request was successful if (httr::http_status(response)$category != "Success") { - stop( + rlang::abort( sprintf( "Failed to fetch the latest release info for '%s'. HTTP status code: %s", repo, @@ -40,7 +40,7 @@ getLatestReleaseUrl <- function(repo) { # Check if the asset URL is available if (length(parsed$assets) == 0 || is.null(parsed$assets$browser_download_url)) { - stop(sprintf("No assets found in the latest release for '%s'.", repo)) + rlang::abort(sprintf("No assets found in the latest release for '%s'.", repo)) } assetUrl <- parsed$assets$browser_download_url @@ -60,7 +60,7 @@ downloadJavaLibraries <- function(dir, repo = "maize-genetics/phg_v2") { libraryUrl <- tryCatch({ getLatestReleaseUrl(repo) }, error = function(e) { - stop(sprintf("Error fetching latest release URL: %s", e$message)) + rlang::abort(sprintf("Error fetching latest release URL: %s", e$message)) }) destFile <- file.path(dir, "phg_java_libs.tar.gz") @@ -69,14 +69,14 @@ downloadJavaLibraries <- function(dir, repo = "maize-genetics/phg_v2") { tryCatch({ utils::download.file(libraryUrl, destFile, mode = "wb") }, error = function(e) { - stop(sprintf("Error downloading the Java library from '%s': %s", libraryUrl, e$message)) + rlang::abort(sprintf("Error downloading the Java library from '%s': %s", libraryUrl, e$message)) }) # Attempt to decompress the file with error handling tryCatch({ utils::untar(destFile, exdir = dir) }, error = function(e) { - stop(sprintf("Error decompressing the Java library archive: %s", e$message)) + rlang::abort(sprintf("Error decompressing the Java library archive: %s", e$message)) }) } @@ -93,6 +93,17 @@ phgLibPath <- file.path(phgLibDir, "phg", "lib") downloadJavaLibraries(phgLibDir) +## Test pre-initialization ---- +test_that("JVM init checker works", { + expect_false(isJvmInitialized()) + + hVcfFileDir <- system.file("extdata", package = "rPHG2") + hVcfFiles <- list.files(hVcfFileDir, pattern = ".h.vcf$", full.names = TRUE) + locCon <- PHGLocalCon(hVcfFiles) + expect_error(buildHaplotypeGraph(locCon)) +}) + + ## Initialize JVM and add PHGv2 JARs to classpath ---- initPhg(phgLibPath) From 90427ec5e3063b3685b7e12ad6295363d2c0fe74 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 16 Aug 2024 19:17:19 -0500 Subject: [PATCH 02/14] Add press release --- DESCRIPTION | 2 +- NEWS.md | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 9cef286..18033ce 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: rPHG2 Title: R interface to PHGv2 -Version: 0.6.1 +Version: 0.6.2 Authors@R: person( given = "Brandon", diff --git a/NEWS.md b/NEWS.md index 6a50813..f5fbe28 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,14 +2,17 @@ * Added new parameter to `plotHaploCounts()`: + `geom` + allows user to specify a given geometry (line, bar, or point) +* Added new conditionals for to `buildHaplotypeGraph()`: + + Checks to see if the JVM is initialized. If not, it will cause an exception + and direct user to run `initPhg()` ## rPHG2 0.6 * Added new parameters to `plogtGvcf()`: + `mData` and `mVar` - + allows user to override default sample color option with categorical data + + Allows user to override default sample color option with categorical data * Added new generic, `numberOfHaplotypes()`: - + returns the number of unique haplotypes found within each reference range or + + Returns the number of unique haplotypes found within each reference range or the total value found within a `PHGDataSet` object * Added getters to `PHGDataSet` objects: + `numberOfChromosomes()` @@ -26,8 +29,8 @@ ## rPHG2 0.5 * Added new visualization method, `plotGvcf()`: - + auto plotting various gVCF metrics - + granular metric support through formula subsetting + + Auto plotting various gVCF metrics + + Granular metric support through formula subsetting * Added new accessor and setting method, `seqnames()` + Returns all contig IDs found in a `PHGMetrics` object + Setter version (`seqnames()<-`) will update old IDs found within a @@ -76,10 +79,12 @@ * Added new function `readHapIdMetaData()` + Reads ALT header metadata for each haplotype ID from a connection object * Added new function `readHapIdPosMetaData()` - + Reads ALT header positional metadata for each haplotype ID from a connection object + + Reads ALT header positional metadata for each haplotype ID from a + connection object * Added new function `readSamples()` + Reads sample IDs from a connection object * Added new function `readRefRanges()` - + Read reference range positional information as a `GRanges` object from a connection object + + Reads reference range positional information as a `GRanges` object from a + connection object From ac36c3e21ccf6606c1ca05f2f1e6d6cf59977c1f Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 19 Aug 2024 20:23:59 -0500 Subject: [PATCH 03/14] Add JVM stats class --- NAMESPACE | 3 + R/class_jvm_stats.R | 208 ++++++++++++++++++++++++++++++++++++ man/JvmStats-class.Rd | 39 +++++++ man/jvmStats.Rd | 53 +++++++++ man/show-JvmStats-method.Rd | 20 ++++ 5 files changed, 323 insertions(+) create mode 100644 R/class_jvm_stats.R create mode 100644 man/JvmStats-class.Rd create mode 100644 man/jvmStats.Rd create mode 100644 man/show-JvmStats-method.Rd diff --git a/NAMESPACE b/NAMESPACE index d39762f..473595b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -19,6 +19,7 @@ export(httProtocol) export(initPhg) export(javaMemoryAddress) export(javaRefObj) +export(jvmStats) export(metricsIds) export(metricsMetaData) export(metricsTable) @@ -40,6 +41,7 @@ export(readRefRanges) export(readSamples) export(serverInfo) exportClasses(HaplotypeGraph) +exportClasses(JvmStats) exportClasses(PHGCon) exportClasses(PHGDataSet) exportClasses(PHGLocalCon) @@ -79,6 +81,7 @@ exportMethods(readRefRanges) exportMethods(readSamples) exportMethods(seqnames) exportMethods(serverInfo) +exportMethods(show) importFrom(GenomeInfoDb,"seqnames<-") importFrom(GenomeInfoDb,seqnames) importFrom(curl,has_internet) diff --git a/R/class_jvm_stats.R b/R/class_jvm_stats.R new file mode 100644 index 0000000..d849acf --- /dev/null +++ b/R/class_jvm_stats.R @@ -0,0 +1,208 @@ +## ---- +#' @title A JvmStats Class +#' +#' @description +#' An S4 class to represent statistics related to the Java Virtual Machine +#' (JVM). +#' +#' @slot nJars +#' An integer representing the number of JAR files currently loaded in the JVM. +#' @slot javaVersion +#' A character string representing the version of Java being used. +#' @slot phgVersion +#' A character string representing the version of PHG (Practical Haplotype +#' Graph). +#' @slot maxMem +#' A numeric value representing the maximum amount of memory (in bytes) that +#' the JVM can use. +#' @slot totMem +#' A numeric value representing the total amount of memory (in bytes) currently +#' allocated to the JVM. +#' @slot freeMem +#' A numeric value representing the amount of free memory (in bytes) in the +#' JVM. +#' @slot allocMem +#' A numeric value representing the amount of memory (in bytes) currently +#' allocated by the JVM. +#' @slot memUnit +#' A character string representing the unit of memory (e.g., "bytes", "MB", +#' "GB"). +#' +#' @return An object of class \code{JvmStats}. +#' @example +#' \dontrun{ +#' # Create an instance of the JvmStats class +#' jvm_stats <- new( +#' "JvmStats", +#' nJars = 12, +#' javaVersion = "17", +# phgVersion = "2.4.1", +# maxMem = 2147483648, +# totMem = 1073741824, +#' freeMem = 536870912, +#' allocMem = 1073741824, +#' memUnit = "bytes" +#' ) +#' } +#' +#' @name JvmStats-class +#' @rdname JvmStats-class +#' @exportClass JvmStats +setClass( + Class = "JvmStats", + slots = c( + nJars = "integer", + javaVersion = "character", + phgVersion = "character", + maxMem = "numeric", + totMem = "numeric", + freeMem = "numeric", + allocMem = "numeric", + memUnit = "character" + ), + prototype = list( + nJars = NA_integer_, + javaVersion = NA_character_, + phgVersion = NA_character_, + maxMem = NA_real_, + totMem = NA_real_, + freeMem = NA_real_, + allocMem = NA_real_, + memUnit = NA_character_ + ) +) + + +## ---- +#' @title Create an instance of the JvmStats class +#' +#' @description +#' Collects JVM statistics such as the number of JAR files loaded, Java +#' version, PHG version, and memory usage. Returns an instance of the +#' \code{JvmStats} class populated with these statistics. +#' +#' @return An object of class \code{JvmStats}, containing the following +#' fields: +#' \itemize{ +#' \item \code{nJars}: The number of JAR files in the JVM classpath. +#' \item \code{javaVersion}: The version of Java being used. +#' \item \code{phgVersion}: The version of PHG (Practical Haplotype +#' Graph) being used. +#' \item \code{maxMem}: The maximum memory (in GB) that the JVM can use. +#' \item \code{totMem}: The total memory (in GB) allocated to the JVM. +#' \item \code{freeMem}: The amount of free memory (in GB) in the JVM. +#' \item \code{allocMem}: The amount of allocated memory (in GB) in the +#' JVM. +#' } +#' +#' @details +#' This function requires that the JVM is initialized. If the JVM is not +#' initialized, it will throw an error. Use the \code{initPhg()} function +#' to initialize the JVM with the PHG library path before calling this +#' function. +#' +#' The function retrieves the number of JAR files in the classpath, the +#' version of Java and PHG being used, and memory statistics including +#' maximum memory, total memory, free memory, and allocated memory (all in +#' gigabytes). +#' +#' @examples +#' \dontrun{ +#' # Ensure that the JVM is initialized with PHGv2 library path +#' initPhg("/path/to/phgv2") +#' +#' # Collect JVM statistics +#' stats <- jvmStats() +#' show(stats) +#' } +#' +#' @seealso \code{\link{JvmStats-class}} +#' +#' @export +jvmStats <- function() { + if (!isJvmInitialized()) { + rlang::abort("JVM is not initialized - please run 'initPhg()' with PHGv2 library path") + } + + # Get number of JARs in class path + classPath <- rJava::.jclassPath() + nJars <- length(classPath[grepl("\\.jar$", classPath)]) + + # Get Java version + javaVersion <- rJava::.jcall("java/lang/System", "S", "getProperty", "java.version") + + # Attempt to get PHG version + genUtils <- rJava::J("net.maizegenetics.phgv2.utils.GeneralUtilitiesKt") + if (!any(grepl("phgVersion()", names(genUtils)))) { + phgVersion <- "Upgrade to current version!" + } else { + phgVersion <- genUtils$phgVersion() + } + + # Get memory profile + runtime <- rJava::.jcall("java/lang/Runtime", "Ljava/lang/Runtime;", "getRuntime") + gbConv <- 1024 ^ 3 + maxMem <- round(rJava::.jcall(runtime, "J", "maxMemory") / gbConv, 3) + totMem <- round(rJava::.jcall(runtime, "J", "totalMemory") / gbConv, 3) + freeMem <- round(rJava::.jcall(runtime, "J", "freeMemory") / gbConv, 3) + allocMem <- totMem - freeMem + + new( + Class = "JvmStats", + nJars = nJars, + javaVersion = javaVersion, + phgVersion = phgVersion, + maxMem = maxMem, + totMem = totMem, + freeMem = freeMem, + allocMem = allocMem + ) +} + + + +# /// Methods (show) //////////////////////////////////////////////// + +## ---- +#' @title Show method for JvmStats class +#' +#' @description +#' Displays JVM statistics in a formatted manner. +#' +#' @param object +#' An object of class \code{JvmStats}. +#' +#' @details +#' This method provides a structured and formatted output of the JVM statistics. It displays +#' the number of JARs, the Java version, the PHG version, and detailed memory statistics +#' (maximum memory, total memory, free memory, and allocated memory) in a human-readable format. +#' Memory values are shown in the respective units (e.g., bytes, MB, GB) defined in the object. +#' +#' @export +setMethod( + f = "show", + signature = "JvmStats", + definition = function(object) { + pointerSymbol <- cli::col_green(cli::symbol$pointer) + + msg <- c( + cli::style_bold("JVM Stats:"), + paste0(" ", pointerSymbol, " # of JARs......: ", cli::style_bold(object@nJars)), + paste0(" ", pointerSymbol, " Java version...: ", cli::style_bold(object@javaVersion)), + paste0(" ", pointerSymbol, " PHG version....: ", cli::style_bold(object@phgVersion)), + "", + cli::style_bold("Memory Stats (GB):"), + paste0(" ", pointerSymbol, " Max............: ", cli::style_bold(object@maxMem)), + paste0(" ", pointerSymbol, " Total..........: ", cli::style_bold(object@totMem)), + paste0(" ", pointerSymbol, " Free...........: ", cli::style_bold(object@freeMem)), + paste0(" ", pointerSymbol, " Allocated......: ", cli::style_bold(object@allocMem)) + ) + + cat(msg, sep = "\n") + } +) + + + + + diff --git a/man/JvmStats-class.Rd b/man/JvmStats-class.Rd new file mode 100644 index 0000000..d58750f --- /dev/null +++ b/man/JvmStats-class.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/class_jvm_stats.R +\docType{class} +\name{JvmStats-class} +\alias{JvmStats-class} +\title{A JvmStats Class} +\value{ +An object of class \code{JvmStats}. +} +\description{ +An S4 class to represent statistics related to the Java Virtual Machine +(JVM). +} +\section{Slots}{ + +\describe{ +\item{\code{nJars}}{An integer representing the number of JAR files currently loaded in the JVM.} + +\item{\code{javaVersion}}{A character string representing the version of Java being used.} + +\item{\code{phgVersion}}{A character string representing the version of PHG (Practical Haplotype +Graph).} + +\item{\code{maxMem}}{A numeric value representing the maximum amount of memory (in bytes) that +the JVM can use.} + +\item{\code{totMem}}{A numeric value representing the total amount of memory (in bytes) currently +allocated to the JVM.} + +\item{\code{freeMem}}{A numeric value representing the amount of free memory (in bytes) in the +JVM.} + +\item{\code{allocMem}}{A numeric value representing the amount of memory (in bytes) currently +allocated by the JVM.} + +\item{\code{memUnit}}{A character string representing the unit of memory (e.g., "bytes", "MB", +"GB").} +}} + diff --git a/man/jvmStats.Rd b/man/jvmStats.Rd new file mode 100644 index 0000000..6f675f7 --- /dev/null +++ b/man/jvmStats.Rd @@ -0,0 +1,53 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/class_jvm_stats.R +\name{jvmStats} +\alias{jvmStats} +\title{Create an instance of the JvmStats class} +\usage{ +jvmStats() +} +\value{ +An object of class \code{JvmStats}, containing the following +fields: +\itemize{ +\item \code{nJars}: The number of JAR files in the JVM classpath. +\item \code{javaVersion}: The version of Java being used. +\item \code{phgVersion}: The version of PHG (Practical Haplotype +Graph) being used. +\item \code{maxMem}: The maximum memory (in GB) that the JVM can use. +\item \code{totMem}: The total memory (in GB) allocated to the JVM. +\item \code{freeMem}: The amount of free memory (in GB) in the JVM. +\item \code{allocMem}: The amount of allocated memory (in GB) in the +JVM. +} +} +\description{ +Collects JVM statistics such as the number of JAR files loaded, Java +version, PHG version, and memory usage. Returns an instance of the +\code{JvmStats} class populated with these statistics. +} +\details{ +This function requires that the JVM is initialized. If the JVM is not +initialized, it will throw an error. Use the \code{initPhg()} function +to initialize the JVM with the PHG library path before calling this +function. + +The function retrieves the number of JAR files in the classpath, the +version of Java and PHG being used, and memory statistics including +maximum memory, total memory, free memory, and allocated memory (all in +gigabytes). +} +\examples{ +\dontrun{ +# Ensure that the JVM is initialized with PHGv2 library path +initPhg("/path/to/phgv2") + +# Collect JVM statistics +stats <- jvmStats() +show(stats) +} + +} +\seealso{ +\code{\link{JvmStats-class}} +} diff --git a/man/show-JvmStats-method.Rd b/man/show-JvmStats-method.Rd new file mode 100644 index 0000000..65f1a38 --- /dev/null +++ b/man/show-JvmStats-method.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/class_jvm_stats.R +\name{show,JvmStats-method} +\alias{show,JvmStats-method} +\title{Show method for JvmStats class} +\usage{ +\S4method{show}{JvmStats}(object) +} +\arguments{ +\item{object}{An object of class \code{JvmStats}.} +} +\description{ +Displays JVM statistics in a formatted manner. +} +\details{ +This method provides a structured and formatted output of the JVM statistics. It displays +the number of JARs, the Java version, the PHG version, and detailed memory statistics +(maximum memory, total memory, free memory, and allocated memory) in a human-readable format. +Memory values are shown in the respective units (e.g., bytes, MB, GB) defined in the object. +} From 296986c27750a2014bcea77b775fcd5e3f86e578 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 20 Aug 2024 15:14:30 -0500 Subject: [PATCH 04/14] Add getters --- NAMESPACE | 10 +++ R/class_all_generics.R | 72 ++++++++++++++++++++++ R/class_jvm_stats.R | 131 ++++++++++++++++++++++++++++++++++------ R/class_phg_con_local.R | 6 +- R/constants.R | 1 + man/brapiVersion.Rd | 7 ++- man/javaVersion.Rd | 23 +++++++ man/jvmMemStats.Rd | 19 ++++++ man/numberOfJars.Rd | 19 ++++++ man/phgVersion.Rd | 23 +++++++ tests/testthat/setup.R | 8 +-- 11 files changed, 293 insertions(+), 26 deletions(-) create mode 100644 man/javaVersion.Rd create mode 100644 man/jvmMemStats.Rd create mode 100644 man/numberOfJars.Rd create mode 100644 man/phgVersion.Rd diff --git a/NAMESPACE b/NAMESPACE index 473595b..696f5df 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -11,6 +11,7 @@ export(PHGServerCon) export(brapiURL) export(brapiVersion) export(buildHaplotypeGraph) +export(classPath) export(filterRefRanges) export(filterSamples) export(hVcfFiles) @@ -19,15 +20,19 @@ export(httProtocol) export(initPhg) export(javaMemoryAddress) export(javaRefObj) +export(javaVersion) +export(jvmMemStats) export(jvmStats) export(metricsIds) export(metricsMetaData) export(metricsTable) export(numberOfChromosomes) export(numberOfHaplotypes) +export(numberOfJars) export(numberOfRefRanges) export(numberOfSamples) export(phgType) +export(phgVersion) export(plotDot) export(plotGvcf) export(plotHaploCounts) @@ -53,6 +58,7 @@ exportMethods("metricsTable<-") exportMethods("seqnames<-") exportMethods(brapiURL) exportMethods(brapiVersion) +exportMethods(classPath) exportMethods(filterRefRanges) exportMethods(filterSamples) exportMethods(hVcfFiles) @@ -60,14 +66,18 @@ exportMethods(host) exportMethods(httProtocol) exportMethods(javaMemoryAddress) exportMethods(javaRefObj) +exportMethods(javaVersion) +exportMethods(jvmMemStats) exportMethods(metricsIds) exportMethods(metricsMetaData) exportMethods(metricsTable) exportMethods(numberOfChromosomes) exportMethods(numberOfHaplotypes) +exportMethods(numberOfJars) exportMethods(numberOfRefRanges) exportMethods(numberOfSamples) exportMethods(phgType) +exportMethods(phgVersion) exportMethods(plotDot) exportMethods(plotGvcf) exportMethods(plotHaploCounts) diff --git a/R/class_all_generics.R b/R/class_all_generics.R index 79579c3..b4dd07e 100644 --- a/R/class_all_generics.R +++ b/R/class_all_generics.R @@ -26,6 +26,20 @@ setGeneric("brapiURL", function(object, ...) standardGeneric("brapiURL")) setGeneric("brapiVersion", function(object, ...) standardGeneric("brapiVersion")) +## ---- +#' @title Return JAR files from class path +#' +#' @description +#' Returns a list of JAR files from an added class path for JVM use. +#' +#' @param object an \code{rPHG2 JvmStats} object +#' @param ... Additional arguments, for use in specific methods +#' +#' @rdname brapiVersion +#' @export +setGeneric("classPath", function(object, ...) standardGeneric("classPath")) + + ## ---- #' @title Filter data by reference range #' @@ -110,6 +124,21 @@ setGeneric("hVcfFiles", function(object, ...) standardGeneric("hVcfFiles")) setGeneric("javaMemoryAddress", function(object, ...) standardGeneric("javaMemoryAddress")) +## ---- +#' @title Return Java version +#' +#' @description +#' This generic function retrieves the Java version associated with the +#' specified object. +#' +#' @param object an \code{rPHG2 JvmStats} object +#' @param ... Additional arguments passed to methods. +#' +#' @rdname javaVersion +#' @export +setGeneric("javaVersion", function(object, ...) standardGeneric("javaVersion")) + + ## ---- #' @title Return \code{rJava} reference object #' @@ -124,6 +153,20 @@ setGeneric("javaMemoryAddress", function(object, ...) standardGeneric("javaMemor setGeneric("javaRefObj", function(object, ...) standardGeneric("javaRefObj")) +## ---- +#' @title Return JVM memory stats +#' +#' @description +#' Returns the set memory stats for initialized JVM session +#' +#' @param object an \code{rPHG2 JvmStats} object +#' @param ... Additional arguments, for use in specific methods +#' +#' @rdname jvmMemStats +#' @export +setGeneric("jvmMemStats", function(object, ...) standardGeneric("jvmMemStats")) + + ## ---- #' @title Return metrics table IDs #' @@ -203,6 +246,20 @@ setGeneric("numberOfChromosomes", function(object, ...) standardGeneric("numberO setGeneric("numberOfHaplotypes", function(object, ...) standardGeneric("numberOfHaplotypes")) +## ---- +#' @title Return number of JAR files in class path +#' +#' @description +#' Returns the number of JAR files for a given \code{JvmStats} object +#' +#' @param object an \code{rPHG2 JvmStats} object +#' @param ... Additional arguments, for use in specific methods +#' +#' @rdname numberOfJars +#' @export +setGeneric("numberOfJars", function(object, ...) standardGeneric("numberOfJars")) + + ## ---- #' @title Return number of reference ranges #' @@ -246,6 +303,21 @@ setGeneric("numberOfSamples", function(object, ...) standardGeneric("numberOfSam setGeneric("phgType", function(object, ...) standardGeneric("phgType")) +## ---- +#' @title Return PHG version +#' +#' @description +#' This generic function retrieves the PHG version associated with the +#' specified object. +#' +#' @param object an \code{rPHG2 JvmStats} object +#' @param ... Additional arguments passed to methods. +#' +#' @rdname phgVersion +#' @export +setGeneric("phgVersion", function(object, ...) standardGeneric("phgVersion")) + + ## ---- #' @title Generate dot plots #' diff --git a/R/class_jvm_stats.R b/R/class_jvm_stats.R index d849acf..7b1153c 100644 --- a/R/class_jvm_stats.R +++ b/R/class_jvm_stats.R @@ -29,21 +29,6 @@ #' "GB"). #' #' @return An object of class \code{JvmStats}. -#' @example -#' \dontrun{ -#' # Create an instance of the JvmStats class -#' jvm_stats <- new( -#' "JvmStats", -#' nJars = 12, -#' javaVersion = "17", -# phgVersion = "2.4.1", -# maxMem = 2147483648, -# totMem = 1073741824, -#' freeMem = 536870912, -#' allocMem = 1073741824, -#' memUnit = "bytes" -#' ) -#' } #' #' @name JvmStats-class #' @rdname JvmStats-class @@ -54,6 +39,7 @@ setClass( nJars = "integer", javaVersion = "character", phgVersion = "character", + classPath = "character", maxMem = "numeric", totMem = "numeric", freeMem = "numeric", @@ -132,9 +118,9 @@ jvmStats <- function() { javaVersion <- rJava::.jcall("java/lang/System", "S", "getProperty", "java.version") # Attempt to get PHG version - genUtils <- rJava::J("net.maizegenetics.phgv2.utils.GeneralUtilitiesKt") + genUtils <- rJava::J(PHG_JVM$GEN_UTILS) if (!any(grepl("phgVersion()", names(genUtils)))) { - phgVersion <- "Upgrade to current version!" + phgVersion <- paste0(cli::symbol$leq, " 2.4.1.155") } else { phgVersion <- genUtils$phgVersion() } @@ -152,6 +138,7 @@ jvmStats <- function() { nJars = nJars, javaVersion = javaVersion, phgVersion = phgVersion, + classPath = classPath, maxMem = maxMem, totMem = totMem, freeMem = freeMem, @@ -186,7 +173,7 @@ setMethod( pointerSymbol <- cli::col_green(cli::symbol$pointer) msg <- c( - cli::style_bold("JVM Stats:"), + cli::style_bold("General Stats:"), paste0(" ", pointerSymbol, " # of JARs......: ", cli::style_bold(object@nJars)), paste0(" ", pointerSymbol, " Java version...: ", cli::style_bold(object@javaVersion)), paste0(" ", pointerSymbol, " PHG version....: ", cli::style_bold(object@phgVersion)), @@ -204,5 +191,113 @@ setMethod( +# /// Methods (general) ///////////////////////////////////////////// + +## ---- +#' @rdname javaVersion +#' @export +setMethod( + f = "classPath", + signature = signature(object = "JvmStats"), + definition = function(object) { + return(object@classPath) + } +) + + +## ---- +#' @rdname javaVersion +#' @export +setMethod( + f = "javaVersion", + signature = signature(object = "JvmStats"), + definition = function(object) { + return(object@javaVersion) + } +) + + +## ---- +#' @rdname jvmMemStats +#' @export +setMethod( + f = "jvmMemStats", + signature = signature(object = "JvmStats"), + definition = function(object) { + return( + list( + "max_memory" = object@maxMem, + "total_memory" = object@totMem, + "free_memory" = object@freeMem, + "alloc_memory" = object@allocMem + ) + ) + } +) + + +## ---- +#' @rdname numberOfJars +#' @export +setMethod( + f = "numberOfJars", + signature = signature(object = "JvmStats"), + definition = function(object) { + return(object@nJars) + } +) + + +## ---- +#' @param granular +#' Should a \code{list} object be returned with major/minor/build/patch values? +#' Defaults to \code{FALSE} +#' +#' @rdname phgVersion +#' @export +setMethod( + f = "phgVersion", + signature = signature(object = "JvmStats"), + definition = function(object, granular = FALSE) { + phgVersion <- object@phgVersion + + if (phgVersion == "\u2264 2.4.1") { + if (granular) { + return( + list( + "major" = NA, + "minor" = NA, + "build" = NA, + "patch" = NA, + "note" = "Build is older than v2.4.1" + ) + ) + } else { + return("<= 2.4.1.155") + } + } else { + if (granular) { + vSplit <- unlist(strsplit(phgVersion, "\\.")) + return( + list( + "major" = vSplit[1], + "minor" = vSplit[2], + "patch" = vSplit[3], + "build" = vSplit[4] + ) + ) + } else { + return(phgVersion) + } + } + } +) + + + + + + + diff --git a/R/class_phg_con_local.R b/R/class_phg_con_local.R index ec415f3..7d3392a 100644 --- a/R/class_phg_con_local.R +++ b/R/class_phg_con_local.R @@ -90,8 +90,8 @@ setMethod( signature = "PHGLocalCon", definition = function(object) { pointerSymbol <- cli::col_green(cli::symbol$pointer) - present <- cli::col_green(cli::symbol$radio_on) - absent <- cli::col_grey(cli::symbol$radio_off) + present <- cli::col_green(cli::symbol$square_small_filled) + absent <- cli::col_grey(cli::symbol$square_small) dbUriStatus <- ifelse(is.na(object@host), absent, present) @@ -103,7 +103,7 @@ setMethod( msg <- c( paste0("A ", cli::style_bold("PHGLocalCon"), " connection object"), - paste0(" ", pointerSymbol, " DB URI.... : ", dbUriStatus), + paste0(" ", pointerSymbol, " DB URI.......: ", dbUriStatus), paste0(" ", pointerSymbol, " hVCF Files...: ", hVcfStatus) ) diff --git a/R/constants.R b/R/constants.R index 93aa74c..79f17bf 100644 --- a/R/constants.R +++ b/R/constants.R @@ -83,6 +83,7 @@ GVCF_MAP <- data.frame( # Commonly used JVM and PHG API classes PHG_JVM <- list( "ARRAY_LIST" = "java.util.ArrayList", + "GEN_UTILS" = "net.maizegenetics.phgv2.utils.GeneralUtilitiesKt", "HAP_GRAPH" = "net.maizegenetics.phgv2.api.HaplotypeGraph", "LIST" = "java/util/List", "R_METHODS" = "net.maizegenetics.phgv2.rphg.RMethods" diff --git a/man/brapiVersion.Rd b/man/brapiVersion.Rd index bae31a4..d9242e2 100644 --- a/man/brapiVersion.Rd +++ b/man/brapiVersion.Rd @@ -2,18 +2,23 @@ % Please edit documentation in R/class_all_generics.R, R/class_phg_con_server.R \name{brapiVersion} \alias{brapiVersion} +\alias{classPath} \alias{brapiVersion,PHGServerCon-method} \title{Return BrAPI version ID} \usage{ brapiVersion(object, ...) +classPath(object, ...) + \S4method{brapiVersion}{PHGServerCon}(object) } \arguments{ -\item{object}{an \code{rPHG2} local or server connection object} +\item{object}{an \code{rPHG2 JvmStats} object} \item{...}{Additional arguments, for use in specific methods} } \description{ Returns the version ID for a BrAPI-compliant PHG server + +Returns a list of JAR files from an added class path for JVM use. } diff --git a/man/javaVersion.Rd b/man/javaVersion.Rd new file mode 100644 index 0000000..efd4c21 --- /dev/null +++ b/man/javaVersion.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/class_all_generics.R, R/class_jvm_stats.R +\name{javaVersion} +\alias{javaVersion} +\alias{classPath,JvmStats-method} +\alias{javaVersion,JvmStats-method} +\title{Return Java version} +\usage{ +javaVersion(object, ...) + +\S4method{classPath}{JvmStats}(object) + +\S4method{javaVersion}{JvmStats}(object) +} +\arguments{ +\item{object}{an \code{rPHG2 JvmStats} object} + +\item{...}{Additional arguments passed to methods.} +} +\description{ +This generic function retrieves the Java version associated with the +specified object. +} diff --git a/man/jvmMemStats.Rd b/man/jvmMemStats.Rd new file mode 100644 index 0000000..a54a8d3 --- /dev/null +++ b/man/jvmMemStats.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/class_all_generics.R, R/class_jvm_stats.R +\name{jvmMemStats} +\alias{jvmMemStats} +\alias{jvmMemStats,JvmStats-method} +\title{Return JVM memory stats} +\usage{ +jvmMemStats(object, ...) + +\S4method{jvmMemStats}{JvmStats}(object) +} +\arguments{ +\item{object}{an \code{rPHG2 JvmStats} object} + +\item{...}{Additional arguments, for use in specific methods} +} +\description{ +Returns the set memory stats for initialized JVM session +} diff --git a/man/numberOfJars.Rd b/man/numberOfJars.Rd new file mode 100644 index 0000000..4ba8192 --- /dev/null +++ b/man/numberOfJars.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/class_all_generics.R, R/class_jvm_stats.R +\name{numberOfJars} +\alias{numberOfJars} +\alias{numberOfJars,JvmStats-method} +\title{Return number of JAR files in class path} +\usage{ +numberOfJars(object, ...) + +\S4method{numberOfJars}{JvmStats}(object) +} +\arguments{ +\item{object}{an \code{rPHG2 JvmStats} object} + +\item{...}{Additional arguments, for use in specific methods} +} +\description{ +Returns the number of JAR files for a given \code{JvmStats} object +} diff --git a/man/phgVersion.Rd b/man/phgVersion.Rd new file mode 100644 index 0000000..19dc321 --- /dev/null +++ b/man/phgVersion.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/class_all_generics.R, R/class_jvm_stats.R +\name{phgVersion} +\alias{phgVersion} +\alias{phgVersion,JvmStats-method} +\title{Return PHG version} +\usage{ +phgVersion(object, ...) + +\S4method{phgVersion}{JvmStats}(object, granular = FALSE) +} +\arguments{ +\item{object}{an \code{rPHG2 JvmStats} object} + +\item{...}{Additional arguments passed to methods.} + +\item{granular}{Should a \code{list} object be returned with major/minor/build/patch values? +Defaults to \code{FALSE}} +} +\description{ +This generic function retrieves the PHG version associated with the +specified object. +} diff --git a/tests/testthat/setup.R b/tests/testthat/setup.R index bcb1fa6..fb8c78d 100644 --- a/tests/testthat/setup.R +++ b/tests/testthat/setup.R @@ -94,13 +94,13 @@ downloadJavaLibraries(phgLibDir) ## Test pre-initialization ---- -test_that("JVM init checker works", { - expect_false(isJvmInitialized()) +testthat::test_that("JVM init checker works", { + testthat::expect_false(rPHG2:::isJvmInitialized()) hVcfFileDir <- system.file("extdata", package = "rPHG2") hVcfFiles <- list.files(hVcfFileDir, pattern = ".h.vcf$", full.names = TRUE) - locCon <- PHGLocalCon(hVcfFiles) - expect_error(buildHaplotypeGraph(locCon)) + locCon <- rPHG2::PHGLocalCon(hVcfFiles) + testthat::expect_error(rPHG2::buildHaplotypeGraph(locCon)) }) From 689fe6c66c6e72580b1cd7130f6fc85078f4ad71 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 8 Oct 2024 10:14:15 -0500 Subject: [PATCH 05/14] Add color override --- R/class_jvm_stats.R | 2 +- R/class_phg_metrics.R | 37 ++++++++++++++++++++------- R/utils_general.R | 12 +++++++++ R/vis_plot_gvcf.R | 59 +++++++++++++++++++++++++------------------ man/plotGvcf.Rd | 6 ++++- 5 files changed, 80 insertions(+), 36 deletions(-) diff --git a/R/class_jvm_stats.R b/R/class_jvm_stats.R index 7b1153c..b1d1e9a 100644 --- a/R/class_jvm_stats.R +++ b/R/class_jvm_stats.R @@ -131,7 +131,7 @@ jvmStats <- function() { maxMem <- round(rJava::.jcall(runtime, "J", "maxMemory") / gbConv, 3) totMem <- round(rJava::.jcall(runtime, "J", "totalMemory") / gbConv, 3) freeMem <- round(rJava::.jcall(runtime, "J", "freeMemory") / gbConv, 3) - allocMem <- totMem - freeMem + allocMem <- round(totMem - freeMem, 3) new( Class = "JvmStats", diff --git a/R/class_phg_metrics.R b/R/class_phg_metrics.R index bdacadb..1d2412b 100644 --- a/R/class_phg_metrics.R +++ b/R/class_phg_metrics.R @@ -586,6 +586,9 @@ setMethod( #' If \code{mData} is specified, what categorical column do you want plotted? If #' \code{NULL}, the first non-\code{sample}/\code{taxa}/\code{line} column will #' be selected. +#' @param colorOverride +#' If \code{colorOverride} is specified, all default colors will be overridden +#' with specified classic color or hex-based RGB value (e.g., \code{#000FFF}). #' #' @return A plot object generated from the specified gVCF data and layout. #' @@ -602,7 +605,8 @@ setMethod( nCol = NULL, tag = "A", mData = NULL, - mVar = NULL + mVar = NULL, + colorOverride = NULL ) { if (length(metricId) > 1) { rlang::abort("This method currently does not support multiple ID plotting") @@ -662,15 +666,30 @@ setMethod( } } + if (!is.null(colorOverride)) { + if (!is.character(colorOverride)) { + rlang::abort("'colorOverride' is not of type 'character'") + } + + if (length(colorOverride) != 1) { + rlang::abort("'colorOverride' parameter can only be of length '1'") + } + + if (!isValidColor(colorOverride)) { + rlang::abort("value given for 'colorOverride' is not a valid color") + } + } + p <- plotGvcfFromMetrics( - df = df, - formula = f, - nRow = nRow, - nCol = nCol, - tag = tag, - vIdCol = vIdCol, - mData = mData, - mVar = mVar + df = df, + formula = f, + nRow = nRow, + nCol = nCol, + tag = tag, + vIdCol = vIdCol, + mData = mData, + mVar = mVar, + colorOverride = colorOverride ) return(p) diff --git a/R/utils_general.R b/R/utils_general.R index 76922a9..46be9f3 100644 --- a/R/utils_general.R +++ b/R/utils_general.R @@ -38,6 +38,18 @@ isJvmInitialized <- function() { } +## ---- +isValidColor <- function(color) { + isHex <- grepl( + pattern = "^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$", + x = color + ) + isNamedColor <- color %in% colors() + + return(isHex || isNamedColor) +} + + ## ---- #' @title #' User-defined function for pre-evaluated names in vectors diff --git a/R/vis_plot_gvcf.R b/R/vis_plot_gvcf.R index 4de9da9..e3d9522 100644 --- a/R/vis_plot_gvcf.R +++ b/R/vis_plot_gvcf.R @@ -32,7 +32,8 @@ plotGvcfFromMetrics <- function( tag, vIdCol, mData, - mVar + mVar, + colorOverride ) { parsedForm <- parseFormula(formula) lhsVars <- parsedForm$lhs @@ -72,23 +73,32 @@ plotGvcfFromMetrics <- function( } # Join metadata to filtered GVCF data (if possible) - fillVar <- NULL - fillTxt <- NULL - ggGlobTheme <- NULL - if (!is.null(mData)) { - if (!any(mData[[vIdCol]] %in% filtData[["taxa"]])) { - rlang::abort("No valid sample IDs were identified in 'mData' parameter") - } - fillVar <- rlang::sym(mVar) - filtData <- tibble::as_tibble( - merge( - filtData, mData, - by.x = "taxa", - by.y = vIdCol, - all.x = TRUE + fillVar <- rlang::sym("taxa") + fillTxt <- "Sample" + ggGlobTheme <- ggplot2::theme( + axis.text.x = ggplot2::element_blank(), + axis.ticks.x = ggplot2::element_blank(), + legend.position = "bottom" + ) + + # Process metadata and color override conditions + if (!is.null(mData) || !is.null(colorOverride)) { + if (!is.null(mData)) { + if (!any(mData[[vIdCol]] %in% filtData[["taxa"]])) { + rlang::abort("No valid sample IDs were identified in 'mData' parameter") + } + fillVar <- rlang::sym(mVar) + filtData <- tibble::as_tibble( + merge( + filtData, mData, + by.x = "taxa", + by.y = vIdCol, + all.x = TRUE + ) ) - ) - fillTxt <- mVar + fillTxt <- mVar + } + ggGlobTheme <- ggplot2::theme( axis.text.x = ggplot2::element_text( angle = 45, @@ -96,14 +106,13 @@ plotGvcfFromMetrics <- function( hjust = 1 ) ) + } + + + if (is.null(colorOverride)) { + ggBar <- ggplot2::geom_bar(stat = "identity") } else { - fillVar <- rlang::sym("taxa") - fillTxt <- "Sample" - ggGlobTheme <- ggplot2::theme( - axis.text.x = ggplot2::element_blank(), - axis.ticks.x = ggplot2::element_blank(), - legend.position = "bottom" - ) + ggBar <- ggplot2::geom_bar(stat = "identity", fill = colorOverride) } # Loop through each column in "filtered" colKeepMap and create a bar plot @@ -118,7 +127,7 @@ plotGvcfFromMetrics <- function( y = !!rlang::sym(col), fill = !!fillVar ) + - ggplot2::geom_bar(stat = "identity") + + ggBar + ggplot2::labs( title = row$plt, x = NULL, diff --git a/man/plotGvcf.Rd b/man/plotGvcf.Rd index aa97d7e..7a2676b 100644 --- a/man/plotGvcf.Rd +++ b/man/plotGvcf.Rd @@ -15,7 +15,8 @@ plotGvcf(object, ...) nCol = NULL, tag = "A", mData = NULL, - mVar = NULL + mVar = NULL, + colorOverride = NULL ) } \arguments{ @@ -42,6 +43,9 @@ for plotting.} \item{mVar}{If \code{mData} is specified, what categorical column do you want plotted? If \code{NULL}, the first non-\code{sample}/\code{taxa}/\code{line} column will be selected.} + +\item{colorOverride}{If \code{colorOverride} is specified, all default colors will be overridden +with specified classic color or hex-based RGB value (e.g., \code{#000FFF}).} } \value{ A plot object generated from the specified gVCF data and layout. From b88c44e090c5498937cf8fe3270ee6cfb3e0a7b6 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 8 Oct 2024 14:55:16 -0500 Subject: [PATCH 06/14] Add init checks --- R/class_phg_metrics.R | 23 +++++++- R/init_phg.R | 78 +++++++++++++++++++++++++ R/utils_general.R | 29 --------- R/utils_jvm.R | 61 +++++++++++++++---- R/vis_plot_gvcf.R | 12 +++- man/initPhg.Rd | 14 +++-- man/plotGvcf.Rd | 8 ++- tests/testthat/test_class_jvm_stats.R | 16 +++++ tests/testthat/test_class_phg_metrics.R | 21 +++++++ tests/testthat/test_utils_general.R | 16 +++++ 10 files changed, 228 insertions(+), 50 deletions(-) create mode 100644 R/init_phg.R create mode 100644 tests/testthat/test_class_jvm_stats.R create mode 100644 tests/testthat/test_utils_general.R diff --git a/R/class_phg_metrics.R b/R/class_phg_metrics.R index 1d2412b..a75293d 100644 --- a/R/class_phg_metrics.R +++ b/R/class_phg_metrics.R @@ -589,6 +589,11 @@ setMethod( #' @param colorOverride #' If \code{colorOverride} is specified, all default colors will be overridden #' with specified classic color or hex-based RGB value (e.g., \code{#000FFF}). +#' @param sampleOrder +#' A \code{character} vector of sample IDs for manual order override. If +#' \code{sampleOrder} is specified, bars will be ordered based on order in +#' vector object. Additionally, this can be used as a method to subset the +#' base set for a given number of selected samples. #' #' @return A plot object generated from the specified gVCF data and layout. #' @@ -606,7 +611,8 @@ setMethod( tag = "A", mData = NULL, mVar = NULL, - colorOverride = NULL + colorOverride = NULL, + sampleOrder = NULL ) { if (length(metricId) > 1) { rlang::abort("This method currently does not support multiple ID plotting") @@ -680,6 +686,18 @@ setMethod( } } + if (!is.null(sampleOrder)) { + if (!is.character(sampleOrder)) { + rlang::abort("'sampleOrder' is not of type 'character'") + } + + if (any(duplicated(sampleOrder))) { + rlang::warn("Duplicate elements detected in 'sampleOrder' - retaining unique elements...") + + sampleOrder <- unique(sampleOrder) + } + } + p <- plotGvcfFromMetrics( df = df, formula = f, @@ -689,7 +707,8 @@ setMethod( vIdCol = vIdCol, mData = mData, mVar = mVar, - colorOverride = colorOverride + colorOverride = colorOverride, + sampleOrder = sampleOrder ) return(p) diff --git a/R/init_phg.R b/R/init_phg.R new file mode 100644 index 0000000..ea48dde --- /dev/null +++ b/R/init_phg.R @@ -0,0 +1,78 @@ +## ---- +#' Initialize JVM and add class path +#' +#' This function is needed for all PHGv2 API-related tasks (e.g., building +#' graph objects from hVCF files or DB connections). +#' +#' @param phgPath +#' Path to PHGv2 lib folder +#' @param check +#' Checks for latest PHGv2 release and correct Java version. Defaults to +#' \code{TRUE}. +#' +#' @export +initPhg <- function(phgPath, check = TRUE) { + if (!"phg_v2.jar" %in% dir(phgPath)) { + rlang::abort("Cannot find 'phg_v2.jar' in library path") + } + + if (isJvmInitialized() && "phg_v2.jar" %in% basename(rJava::.jclassPath())) { + rlang::abort("PHGv2 JARs already added to class path") + } + + tryCatch( + { + rJava::.jinit() + rJava::.jaddClassPath(dir(phgPath, full.names = TRUE)) + }, + error = function(e) { + rlang::abort("Java initialization or class path addition failed", parent = e) + } + ) + + if (check) { + jvmStats <- jvmStats() + jvmVersion <- javaVersion(jvmStats) + currentPhgVersion <- phgVersion(jvmStats) + latestPhgVersion <- rPHG2:::getLatestPhgVersion() + + jvmMajor <- as.numeric(unlist(strsplit(jvmVersion, "\\."))[1]) + + # Note: I **know** there are easier ways of accomplishing this but I + # need to do this 'ad-hoc' for JupyterHub notebooks! + cliSuccess <- cli::col_green(cli::symbol$tick) + cliInform <- cli::col_blue(cli::symbol$info) + cliWarn <- cli::col_red(cli::symbol$warning) + + jvmMsg <- NULL + if (jvmMajor < 17) { + errMsg <- paste0("Your Java version is out of date (", cli::style_bold(jvmVersion), "). Version ", cli::style_bold(cli::symbol$geq, " 17 "), "is needed.") + rlang::abort(errMsg) + } else { + jvmMsg <- paste0(cliInform, " Using Java version ", cli::style_bold(jvmVersion)) + } + + cliCurrent <- cli::style_bold(currentPhgVersion) + if (currentPhgVersion != latestPhgVersion) { + cliLatest <- paste0(cli::style_bold("Latest version: "), cli::style_bold(cli::col_green(latestPhgVersion))) + phgVMsg <- paste0( + cliWarn, cli::style_bold(" Note: "), "current version of PHGv2 (", cliCurrent, ") ", + "is out of date (", cliLatest, ")\n", + paste0( + " ", cli::col_blue(cli::symbol$arrow_right), + " consider updating (", + cli::col_blue("https://github.com/maize-genetics/phg_v2/releases/latest"), + ")" + ) + ) + } else { + phgVMsg <- paste0(cliSuccess, " Using latest version of PHGv2 (", cliCurrent, ")") + } + + loadMsg <- paste0(cliSuccess, " PHG JARs added to class path") + msg <- c(phgVMsg, jvmMsg, loadMsg) + cat(msg, sep = "\n") + } +} + + diff --git a/R/utils_general.R b/R/utils_general.R index 46be9f3..783e37e 100644 --- a/R/utils_general.R +++ b/R/utils_general.R @@ -9,35 +9,6 @@ camelToSnake <- function(x) { } -## ---- -# Check if the JVM is Initialized -# -# @description -# This function checks whether the Java Virtual Machine (JVM) has been -# initialized using the `rJava` package. -# -# The function attempts to retrieve the current Java version by calling a Java -# method. If the JVM is not initialized, an error is caught, and the function -# returns `FALSE`. If the JVM is initialized, it returns `TRUE`. -# -# @return -# A logical value indicating whether the JVM has been initialized. Returns -# `TRUE` if the JVM is initialized, otherwise `FALSE`. -isJvmInitialized <- function() { - tryCatch({ - # Attempt to get the current Java version - javaVersion <- rJava::.jcall( - obj = "java/lang/System", - returnSig = "S", - method = "getProperty", "java.version" - ) - return(TRUE) - }, error = function(e) { - return(FALSE) - }) -} - - ## ---- isValidColor <- function(color) { isHex <- grepl( diff --git a/R/utils_jvm.R b/R/utils_jvm.R index 008333e..2795a57 100644 --- a/R/utils_jvm.R +++ b/R/utils_jvm.R @@ -8,6 +8,31 @@ createRMethodInterface <- function() { } +## ---- +getLatestPhgVersion <- function() { + + apiUrl <- "https://api.github.com/repos/maize-genetics/phg_v2/releases/latest" + response <- httr::GET(apiUrl) + + # Check if the request was successful + if (httr::http_status(response)$category != "Success") { + rlang::abort( + sprintf( + "Failed to fetch the latest release info for '%s'. HTTP status code: %s", + repo, + httr::http_status(response)$reason + ) + ) + } + + responseContent <- httr::content(response, "text") + parsed <- jsonlite::fromJSON(responseContent) + + + return(parsed$tag_name) +} + + ## ---- # Constructor for instantiating a PHGv2 HaplotypeGraph object # @@ -24,17 +49,31 @@ hapGraphConstructor <- function(l) { ## ---- -#' Initialize JVM and add class path (for R&D purposes only) -#' -#' @param phgPath path to PHGv2 lib folder -#' @param verbose Display all JARs added classpath? Defaults to FALSE. -#' -#' @export -initPhg <- function(phgPath, verbose = TRUE) { - rJava::.jinit() - rJava::.jaddClassPath(dir(phgPath, full.names = TRUE)) - - if (verbose) message("PHG JARs added to class path") +# Check if the JVM is Initialized +# +# @description +# This function checks whether the Java Virtual Machine (JVM) has been +# initialized using the `rJava` package. +# +# The function attempts to retrieve the current Java version by calling a Java +# method. If the JVM is not initialized, an error is caught, and the function +# returns `FALSE`. If the JVM is initialized, it returns `TRUE`. +# +# @return +# A logical value indicating whether the JVM has been initialized. Returns +# `TRUE` if the JVM is initialized, otherwise `FALSE`. +isJvmInitialized <- function() { + tryCatch({ + # Attempt to get the current Java version + javaVersion <- rJava::.jcall( + obj = "java/lang/System", + returnSig = "S", + method = "getProperty", "java.version" + ) + return(TRUE) + }, error = function(e) { + return(FALSE) + }) } diff --git a/R/vis_plot_gvcf.R b/R/vis_plot_gvcf.R index e3d9522..50064ec 100644 --- a/R/vis_plot_gvcf.R +++ b/R/vis_plot_gvcf.R @@ -33,7 +33,8 @@ plotGvcfFromMetrics <- function( vIdCol, mData, mVar, - colorOverride + colorOverride, + sampleOrder ) { parsedForm <- parseFormula(formula) lhsVars <- parsedForm$lhs @@ -108,6 +109,15 @@ plotGvcfFromMetrics <- function( ) } + # Filter/order data.frame based on 'sampleOrder' parameter + if (!is.null(sampleOrder)) { + if (!any(sampleOrder %in% unique(filtData$taxa))) { + rlang::abort("No sample IDs in 'sampleOrder' were found in base data") + } + filtData <- filtData[filtData$taxa %in% sampleOrder, ] + filtData$taxa <- factor(filtData$taxa, levels = sampleOrder) + } + if (is.null(colorOverride)) { ggBar <- ggplot2::geom_bar(stat = "identity") diff --git a/man/initPhg.Rd b/man/initPhg.Rd index d73ea8e..4a8fba5 100644 --- a/man/initPhg.Rd +++ b/man/initPhg.Rd @@ -1,16 +1,18 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils_jvm.R +% Please edit documentation in R/init_phg.R \name{initPhg} \alias{initPhg} -\title{Initialize JVM and add class path (for R&D purposes only)} +\title{Initialize JVM and add class path} \usage{ -initPhg(phgPath, verbose = TRUE) +initPhg(phgPath, check = TRUE) } \arguments{ -\item{phgPath}{path to PHGv2 lib folder} +\item{phgPath}{Path to PHGv2 lib folder} -\item{verbose}{Display all JARs added classpath? Defaults to FALSE.} +\item{check}{Checks for latest PHGv2 release and correct Java version. Defaults to +\code{TRUE}.} } \description{ -Initialize JVM and add class path (for R&D purposes only) +This function is needed for all PHGv2 API-related tasks (e.g., building +graph objects from hVCF files or DB connections). } diff --git a/man/plotGvcf.Rd b/man/plotGvcf.Rd index 7a2676b..ea4f67b 100644 --- a/man/plotGvcf.Rd +++ b/man/plotGvcf.Rd @@ -16,7 +16,8 @@ plotGvcf(object, ...) tag = "A", mData = NULL, mVar = NULL, - colorOverride = NULL + colorOverride = NULL, + sampleOrder = NULL ) } \arguments{ @@ -46,6 +47,11 @@ be selected.} \item{colorOverride}{If \code{colorOverride} is specified, all default colors will be overridden with specified classic color or hex-based RGB value (e.g., \code{#000FFF}).} + +\item{sampleOrder}{A \code{character} vector of sample IDs for manual order override. If +\code{sampleOrder} is specified, bars will be ordered based on order in +vector object. Additionally, this can be used as a method to subset the +base set for a given number of selected samples.} } \value{ A plot object generated from the specified gVCF data and layout. diff --git a/tests/testthat/test_class_jvm_stats.R b/tests/testthat/test_class_jvm_stats.R new file mode 100644 index 0000000..bf89f6e --- /dev/null +++ b/tests/testthat/test_class_jvm_stats.R @@ -0,0 +1,16 @@ +test_that("JvmStats class construction tests", { + + jvmTest <- jvmStats() + + expect_true(is(javaVersion(jvmTest), "character")) + expect_true(is(phgVersion(jvmTest), "character")) + expect_true(is(phgVersion(jvmTest, granular = TRUE), "list")) + expect_true(is(classPath(jvmTest), "character")) + expect_true(is(jvmMemStats(jvmTest), "list")) + + + locConOutput <- utils::capture.output(jvmTest) + expect_equal(length(locConOutput), 10) +}) + + diff --git a/tests/testthat/test_class_phg_metrics.R b/tests/testthat/test_class_phg_metrics.R index 9fcb041..6f5c252 100644 --- a/tests/testthat/test_class_phg_metrics.R +++ b/tests/testthat/test_class_phg_metrics.R @@ -378,6 +378,27 @@ test_that("PHGMetrics general gVCF plot tests", { treatment = c("a", "b", "a") ) expect_error(plotGvcf(metBase, mData = mDataError)) + + + # Color overrides + expect_error(plotGvcf(metBase, colorOverride = 1)) + expect_error(plotGvcf(metBase, colorOverride = c("purple", "yellow"))) + expect_error(plotGvcf(metBase, colorOverride = c("greeeeeeen"))) + expect_true(is(plotGvcf(metBase, colorOverride = "green"), "ggplot")) + + + # Sample order + expect_error(plotGvcf(metBase, sampleOrder = 1)) + expect_error(plotGvcf(metBase, sampleOrder = "Xb0111")) + expect_warning(plotGvcf(metBase, sampleOrder = c("Xb03", "Xb03", "Xb02"))) + + sOrdTest <- plotGvcf(metBase, sampleOrder = c("Xb03", "Xb01")) + expect_true(is(sOrdTest, "ggplot")) + expect_equal(levels(sOrdTest[[1]]$data$taxa), c("Xb03", "Xb01")) }) + + + + diff --git a/tests/testthat/test_utils_general.R b/tests/testthat/test_utils_general.R new file mode 100644 index 0000000..2981d6e --- /dev/null +++ b/tests/testthat/test_utils_general.R @@ -0,0 +1,16 @@ +test_that("General utility tests", { + + expect_true(isValidColor("#FFF000")) + expect_true(isValidColor("green")) + expect_true(isValidColor("#fff")) + expect_true(isValidColor("#FFF")) + expect_true(isValidColor("#234")) + expect_true(isValidColor("#111111")) + expect_false(isValidColor("greeeen")) + expect_false(isValidColor("#III234")) + expect_false(isValidColor("#FFFFFFF")) + expect_false(isValidColor("#fffffff")) + +}) + + From 3d847b27ba2d0b05554a481a38353208040ca87e Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 8 Oct 2024 15:25:48 -0500 Subject: [PATCH 07/14] Add better info flow --- R/init_phg.R | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/R/init_phg.R b/R/init_phg.R index ea48dde..b19f737 100644 --- a/R/init_phg.R +++ b/R/init_phg.R @@ -43,34 +43,38 @@ initPhg <- function(phgPath, check = TRUE) { cliSuccess <- cli::col_green(cli::symbol$tick) cliInform <- cli::col_blue(cli::symbol$info) cliWarn <- cli::col_red(cli::symbol$warning) + cliBullet <- cli::symbol$bullet jvmMsg <- NULL if (jvmMajor < 17) { errMsg <- paste0("Your Java version is out of date (", cli::style_bold(jvmVersion), "). Version ", cli::style_bold(cli::symbol$geq, " 17 "), "is needed.") rlang::abort(errMsg) } else { - jvmMsg <- paste0(cliInform, " Using Java version ", cli::style_bold(jvmVersion)) + jvmMsg <- paste0(" ", cliBullet, " Java version...: ", cli::style_bold(jvmVersion)) } cliCurrent <- cli::style_bold(currentPhgVersion) + loadMsg <- paste0(cliSuccess, " PHG JARs added to class path") if (currentPhgVersion != latestPhgVersion) { cliLatest <- paste0(cli::style_bold("Latest version: "), cli::style_bold(cli::col_green(latestPhgVersion))) - phgVMsg <- paste0( - cliWarn, cli::style_bold(" Note: "), "current version of PHGv2 (", cliCurrent, ") ", + phgWarnMsg <- paste0( + " ", cli::symbol$line, "\n", " ", cliWarn, " ", cli::style_bold(cli::symbol$sup_1), "Current version of PHGv2 (", cliCurrent, ") ", "is out of date (", cliLatest, ")\n", paste0( - " ", cli::col_blue(cli::symbol$arrow_right), + " ", cli::col_blue(cli::symbol$arrow_right), " consider updating (", cli::col_blue("https://github.com/maize-genetics/phg_v2/releases/latest"), ")" ) ) + phgVMsg <- paste0(" ", cliBullet, " PHG version....: ", cliCurrent) + loadMsg <- paste0(loadMsg, cli::style_bold(cli::symbol$sup_1)) } else { - phgVMsg <- paste0(cliSuccess, " Using latest version of PHGv2 (", cliCurrent, ")") + phgVMsg <- paste0(" ", cliBullet, " PHG version....: ", cliCurrent) + phgWarnMsg <- NULL } - loadMsg <- paste0(cliSuccess, " PHG JARs added to class path") - msg <- c(phgVMsg, jvmMsg, loadMsg) + msg <- c(loadMsg, jvmMsg, phgVMsg, phgWarnMsg) cat(msg, sep = "\n") } } From 5c2b4cffa2340d2010eacb6ee191cda705269545 Mon Sep 17 00:00:00 2001 From: Brandon Date: Wed, 9 Oct 2024 14:58:53 -0500 Subject: [PATCH 08/14] Add tests --- R/init_phg.R | 4 ++++ tests/testthat/setup.R | 8 ++++++++ tests/testthat/test_init_phg.R | 6 ++++++ tests/testthat/test_utils_jvm.R | 2 -- 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 tests/testthat/test_init_phg.R diff --git a/R/init_phg.R b/R/init_phg.R index b19f737..643addd 100644 --- a/R/init_phg.R +++ b/R/init_phg.R @@ -12,6 +12,10 @@ #' #' @export initPhg <- function(phgPath, check = TRUE) { + if (!is.character(phgPath) || !dir.exists(phgPath)) { + rlang::abort("PHG library path ('phgPath') provided does not exist") + } + if (!"phg_v2.jar" %in% dir(phgPath)) { rlang::abort("Cannot find 'phg_v2.jar' in library path") } diff --git a/tests/testthat/setup.R b/tests/testthat/setup.R index fb8c78d..2391925 100644 --- a/tests/testthat/setup.R +++ b/tests/testthat/setup.R @@ -101,6 +101,8 @@ testthat::test_that("JVM init checker works", { hVcfFiles <- list.files(hVcfFileDir, pattern = ".h.vcf$", full.names = TRUE) locCon <- rPHG2::PHGLocalCon(hVcfFiles) testthat::expect_error(rPHG2::buildHaplotypeGraph(locCon)) + testthat::expect_error(rPHG2::initPhg(locCon)) + testthat::expect_error(rPHG2::initPhg(hVcfFileDir)) }) @@ -108,3 +110,9 @@ testthat::test_that("JVM init checker works", { initPhg(phgLibPath) +## Test post-initialization ---- +testthat::test_that("JVM init checker works", { + testthat::expect_error(rPHG2::initPhg(phgLibPath)) +}) + + diff --git a/tests/testthat/test_init_phg.R b/tests/testthat/test_init_phg.R new file mode 100644 index 0000000..3e1b7de --- /dev/null +++ b/tests/testthat/test_init_phg.R @@ -0,0 +1,6 @@ +test_that("PHG initialization", { + expect_error(initPhg("dir")) + expect_error(initPhg(mtcars)) +}) + + diff --git a/tests/testthat/test_utils_jvm.R b/tests/testthat/test_utils_jvm.R index c4409b4..c852b34 100644 --- a/tests/testthat/test_utils_jvm.R +++ b/tests/testthat/test_utils_jvm.R @@ -8,8 +8,6 @@ test_that("JVM utility tests", { kotlin2DArrayToRMatrix(negControl1), regexp = "Object does not have a \'MatrixWithNames\' signature" ) - - expect_silent(initPhg(phgLibPath, verbose = FALSE)) }) From 86d4627ff16a1a794bc6c1c51993f9c665e55dc7 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 11 Oct 2024 11:11:12 -0500 Subject: [PATCH 09/14] Reorganize code --- R/init_phg.R | 86 ++++++++++++++++++++++++++++---------------------- man/initPhg.Rd | 8 +++-- 2 files changed, 53 insertions(+), 41 deletions(-) diff --git a/R/init_phg.R b/R/init_phg.R index 643addd..27b63df 100644 --- a/R/init_phg.R +++ b/R/init_phg.R @@ -7,11 +7,13 @@ #' @param phgPath #' Path to PHGv2 lib folder #' @param check -#' Checks for latest PHGv2 release and correct Java version. Defaults to -#' \code{TRUE}. +#' Checks for latest PHGv2 release. This will need a working internet +#' connection. Defaults to \code{TRUE}. +#' @param verbose +#' Should check messages be printed to console? Defaults to \code{TRUE} #' #' @export -initPhg <- function(phgPath, check = TRUE) { +initPhg <- function(phgPath, check = TRUE, verbose = TRUE) { if (!is.character(phgPath) || !dir.exists(phgPath)) { rlang::abort("PHG library path ('phgPath') provided does not exist") } @@ -34,51 +36,59 @@ initPhg <- function(phgPath, check = TRUE) { } ) - if (check) { - jvmStats <- jvmStats() - jvmVersion <- javaVersion(jvmStats) - currentPhgVersion <- phgVersion(jvmStats) - latestPhgVersion <- rPHG2:::getLatestPhgVersion() + # Set up CLI message components + # Note: I **know** there are easier ways of accomplishing this but I + # need to do this 'ad-hoc' for JupyterHub notebooks! + cliSuccess <- cli::col_green(cli::symbol$tick) + cliInform <- cli::col_blue(cli::symbol$info) + cliWarn <- cli::col_red(cli::symbol$warning) + cliBullet <- cli::symbol$bullet - jvmMajor <- as.numeric(unlist(strsplit(jvmVersion, "\\."))[1]) + # Get version stats + jvmStats <- jvmStats() - # Note: I **know** there are easier ways of accomplishing this but I - # need to do this 'ad-hoc' for JupyterHub notebooks! - cliSuccess <- cli::col_green(cli::symbol$tick) - cliInform <- cli::col_blue(cli::symbol$info) - cliWarn <- cli::col_red(cli::symbol$warning) - cliBullet <- cli::symbol$bullet + # Get PHG version messages / set up load message + loadMsg <- paste0(cliSuccess, " PHG JARs added to class path") + currentPhgVersion <- phgVersion(jvmStats) + cliCurrent <- cli::style_bold(currentPhgVersion) + phgMsg <- paste0(" ", cliBullet, " PHG version....: ", cliCurrent) + phgWarnMsg <- NULL - jvmMsg <- NULL - if (jvmMajor < 17) { - errMsg <- paste0("Your Java version is out of date (", cli::style_bold(jvmVersion), "). Version ", cli::style_bold(cli::symbol$geq, " 17 "), "is needed.") - rlang::abort(errMsg) - } else { - jvmMsg <- paste0(" ", cliBullet, " Java version...: ", cli::style_bold(jvmVersion)) - } + # Java version check for >= 17 / message setup + jvmVersion <- javaVersion(jvmStats) + jvmMajor <- as.numeric(unlist(strsplit(jvmVersion, "\\."))[1]) + jvmMsg <- paste0(" ", cliBullet, " Java version...: ", cli::style_bold(jvmVersion)) + if (jvmMajor < 17) { + errMsg <- paste0( + "Your Java version is out of date (", cli::style_bold(jvmVersion), "). Version ", + cli::style_bold(cli::symbol$geq, " 17 "), "is needed." + ) + rlang::abort(errMsg) + } - cliCurrent <- cli::style_bold(currentPhgVersion) - loadMsg <- paste0(cliSuccess, " PHG JARs added to class path") + # Latest PHG version check + # Note: based on 'check' parameter since this is internet-dependent + if (check) { + latestPhgVersion <- getLatestPhgVersion() # internet needed if (currentPhgVersion != latestPhgVersion) { cliLatest <- paste0(cli::style_bold("Latest version: "), cli::style_bold(cli::col_green(latestPhgVersion))) - phgWarnMsg <- paste0( - " ", cli::symbol$line, "\n", " ", cliWarn, " ", cli::style_bold(cli::symbol$sup_1), "Current version of PHGv2 (", cliCurrent, ") ", - "is out of date (", cliLatest, ")\n", - paste0( - " ", cli::col_blue(cli::symbol$arrow_right), - " consider updating (", - cli::col_blue("https://github.com/maize-genetics/phg_v2/releases/latest"), - ")" - ) + phgWarnMsg <- sprintf( + " %s\n %s %sCurrent version of PHGv2 (%s) is out of date (%s)\n %s consider updating (%s)", + cli::symbol$line, + cliWarn, + cli::style_bold(cli::symbol$sup_1), + cliCurrent, + cliLatest, + cli::col_blue(cli::symbol$arrow_right), + cli::col_blue("https://github.com/maize-genetics/phg_v2/releases/latest") ) - phgVMsg <- paste0(" ", cliBullet, " PHG version....: ", cliCurrent) loadMsg <- paste0(loadMsg, cli::style_bold(cli::symbol$sup_1)) - } else { - phgVMsg <- paste0(" ", cliBullet, " PHG version....: ", cliCurrent) - phgWarnMsg <- NULL } - msg <- c(loadMsg, jvmMsg, phgVMsg, phgWarnMsg) + } + + if (verbose) { + msg <- c(loadMsg, jvmMsg, phgMsg, phgWarnMsg) cat(msg, sep = "\n") } } diff --git a/man/initPhg.Rd b/man/initPhg.Rd index 4a8fba5..103bff4 100644 --- a/man/initPhg.Rd +++ b/man/initPhg.Rd @@ -4,13 +4,15 @@ \alias{initPhg} \title{Initialize JVM and add class path} \usage{ -initPhg(phgPath, check = TRUE) +initPhg(phgPath, check = TRUE, verbose = TRUE) } \arguments{ \item{phgPath}{Path to PHGv2 lib folder} -\item{check}{Checks for latest PHGv2 release and correct Java version. Defaults to -\code{TRUE}.} +\item{check}{Checks for latest PHGv2 release. This will need a working internet +connection. Defaults to \code{TRUE}.} + +\item{verbose}{Should check messages be printed to console? Defaults to \code{TRUE}} } \description{ This function is needed for all PHGv2 API-related tasks (e.g., building From 68880b4eb2d6045af97b35a578b43fa650b11da1 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 11 Oct 2024 11:11:34 -0500 Subject: [PATCH 10/14] Update documentation --- vignettes/metrics.Rmd | 46 ++++++++++++++++++++++++++++++++++++++++++- vignettes/rPHG2.Rmd | 31 +++++++++++++++++++++++++---- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/vignettes/metrics.Rmd b/vignettes/metrics.Rmd index be5052d..1fb33cd 100644 --- a/vignettes/metrics.Rmd +++ b/vignettes/metrics.Rmd @@ -396,7 +396,6 @@ metData |> plotGvcf(f = CORE ~ ALL, tag = "i") ``` #### Adding metadata - If you want to color bars based on additional categorical data besides sample ID, you can pass a `data.frame` object to the parameter `mData`. This will need the following prerequisites: @@ -444,3 +443,48 @@ metData |> plotGvcf( ``` +#### Overriding color +To override default bar coloring (e.g., if you have many samples) to one +specified color, you can use the `colorOverride` parameter: + +```{r, eval=TRUE, echo=TRUE} +metData |> plotGvcf(colorOverride = "#73beff") +``` + +This parameter can also accept R's default color IDs (i.e., values from the +`grDevices` `colors()` / `colours()` function): + +```{r, eval=TRUE, echo=TRUE} +metData |> plotGvcf(colorOverride = "forestgreen") +``` + + +#### Overriding and filtering sample order +To override the default lexicographic order of sample IDs, you can use the +`sampleOrder` parameter by first defining a `character` vector of specified +order. In the prior examples, the internal sample order is defined as follows: + +``` +Xb01, Xb02, Xb03 +``` + +...if I want to reorder this (e.g., `Xb03`, `Xb01`, `Xb02`), I can use the +following example: + +```{r, eval=TRUE, echo=TRUE} +newOrder <- c("Xb03", "Xb01", "Xb02") + +metData |> plotGvcf(sampleOrder = newOrder) +``` + +We can also use this parameter for subsetting samples. For example, If I want +to subset the plot to only show values for samples `Xb03` and `Xb01` and +keep them in that order, I can specify the vector as follows: + +```{r, eval=TRUE, echo=TRUE} +newOrder <- c("Xb03", "Xb01") + +metData |> plotGvcf(sampleOrder = newOrder) +``` + + diff --git a/vignettes/rPHG2.Rmd b/vignettes/rPHG2.Rmd index 4e082c0..8e6a3d3 100644 --- a/vignettes/rPHG2.Rmd +++ b/vignettes/rPHG2.Rmd @@ -155,15 +155,19 @@ convert the raw hVCF data into a JVM object and bridge the Java reference pointer to R. Before we build the JVM graph object, we need to initialize the JVM and add the JAR files to our environment that are found within the [latest distribution](https://github.com/maize-genetics/phg_v2/releases) -of PHGv2. If you have **not** downloaded this, please see instructions +of PHGv2. + +**Note:** If you have **not** downloaded this, _please_ see instructions [here](https://phg.maizegenetics.net/installation/#get-phgv2) before you -continue! To initialize, run the following command: +continue! + +To initialize, run the following command: ```{r, eval=FALSE, echo=TRUE} -initPhg("phg/lib/path") +initPhg("phg/path/to/lib") ``` -...where `phg/lib/path` is the `lib` directory found within the decompressed +...where `phg/path/to/lib` is the `lib` directory found within the decompressed release of PHGv2. Now that the JVM has been initialized, we can build the JVM graph using `buildHaplotypeGraph()` using the local connection object as input: @@ -182,6 +186,25 @@ pointer object where we can direct data from Java to R: graph |> javaRefObj() ``` +### Returning version and memory values +Since we need to construct an interface to a local instance of Java, errors +may arise due to several issues. Two common causes are version issues and +memory allocated to the JVM. For debugging and monitoring purposes, we can +use the `jvmStats()` function which create a instance of a `JvmStats` object. + +```{r, eval=TRUE, echo=TRUE} +javaStats <- jvmStats() + +javaStats +``` + +This object contains several values: + +* Total number of PHGv2 JAR files added to the class path +* Your local Java version +* The current PHGv2 version added to the class path +* Current memory allocation to the JVM (recorded in gigabytes [`GB`]) + ## Reading data From cf58d1df79982614384082455ad37027064d8425 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 11 Oct 2024 11:12:02 -0500 Subject: [PATCH 11/14] Add press release --- DESCRIPTION | 2 +- NEWS.md | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 18033ce..14c488a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: rPHG2 Title: R interface to PHGv2 -Version: 0.6.2 +Version: 0.7 Authors@R: person( given = "Brandon", diff --git a/NEWS.md b/NEWS.md index f5fbe28..2665007 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,15 @@ * Added new conditionals for to `buildHaplotypeGraph()`: + Checks to see if the JVM is initialized. If not, it will cause an exception and direct user to run `initPhg()` +* Added new class `JvmStats`: + + Returns internal Java and PHG versions and memory information for JVM + session + + Can be instantiated using the `jvmStats()` constructor function +* Added new checks for `initPhg()` +* Added new parameters to `plotGvcf()` function: + + `colorOverride`: Overrides bar color based on given user defined color + + `sampleOrder`: Overrides default bar ordering based on user defined + `character` vector ## rPHG2 0.6 From efe615bb506c659b3f0879840f3cdcf6a995c5cd Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 11 Oct 2024 11:44:13 -0500 Subject: [PATCH 12/14] Fix doc and import issues --- NAMESPACE | 1 - R/class_jvm_stats.R | 8 ++++++-- R/utils_general.R | 2 +- R/utils_jvm.R | 3 +-- man/JvmStats-class.Rd | 17 +++++++++++++++++ man/show-JvmStats-method.Rd | 20 -------------------- 6 files changed, 25 insertions(+), 26 deletions(-) delete mode 100644 man/show-JvmStats-method.Rd diff --git a/NAMESPACE b/NAMESPACE index 696f5df..f971533 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -91,7 +91,6 @@ exportMethods(readRefRanges) exportMethods(readSamples) exportMethods(seqnames) exportMethods(serverInfo) -exportMethods(show) importFrom(GenomeInfoDb,"seqnames<-") importFrom(GenomeInfoDb,seqnames) importFrom(curl,has_internet) diff --git a/R/class_jvm_stats.R b/R/class_jvm_stats.R index b1d1e9a..42d0c62 100644 --- a/R/class_jvm_stats.R +++ b/R/class_jvm_stats.R @@ -12,6 +12,8 @@ #' @slot phgVersion #' A character string representing the version of PHG (Practical Haplotype #' Graph). +#' @slot classPath +#' A character vector representing the JAR files found in the class path. #' @slot maxMem #' A numeric value representing the maximum amount of memory (in bytes) that #' the JVM can use. @@ -133,7 +135,7 @@ jvmStats <- function() { freeMem <- round(rJava::.jcall(runtime, "J", "freeMemory") / gbConv, 3) allocMem <- round(totMem - freeMem, 3) - new( + methods::new( Class = "JvmStats", nJars = nJars, javaVersion = javaVersion, @@ -165,7 +167,9 @@ jvmStats <- function() { #' (maximum memory, total memory, free memory, and allocated memory) in a human-readable format. #' Memory values are shown in the respective units (e.g., bytes, MB, GB) defined in the object. #' -#' @export +#' @docType methods +#' @rdname JvmStats-class +#' @aliases show,JvmStats-method setMethod( f = "show", signature = "JvmStats", diff --git a/R/utils_general.R b/R/utils_general.R index 783e37e..425bed2 100644 --- a/R/utils_general.R +++ b/R/utils_general.R @@ -15,7 +15,7 @@ isValidColor <- function(color) { pattern = "^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$", x = color ) - isNamedColor <- color %in% colors() + isNamedColor <- color %in% grDevices::colors() return(isHex || isNamedColor) } diff --git a/R/utils_jvm.R b/R/utils_jvm.R index 2795a57..9a74c58 100644 --- a/R/utils_jvm.R +++ b/R/utils_jvm.R @@ -18,8 +18,7 @@ getLatestPhgVersion <- function() { if (httr::http_status(response)$category != "Success") { rlang::abort( sprintf( - "Failed to fetch the latest release info for '%s'. HTTP status code: %s", - repo, + "Failed to fetch the latest release info for PHGv2. HTTP status code: %s", httr::http_status(response)$reason ) ) diff --git a/man/JvmStats-class.Rd b/man/JvmStats-class.Rd index d58750f..98465dd 100644 --- a/man/JvmStats-class.Rd +++ b/man/JvmStats-class.Rd @@ -3,13 +3,28 @@ \docType{class} \name{JvmStats-class} \alias{JvmStats-class} +\alias{show,JvmStats-method} \title{A JvmStats Class} +\usage{ +\S4method{show}{JvmStats}(object) +} +\arguments{ +\item{object}{An object of class \code{JvmStats}.} +} \value{ An object of class \code{JvmStats}. } \description{ An S4 class to represent statistics related to the Java Virtual Machine (JVM). + +Displays JVM statistics in a formatted manner. +} +\details{ +This method provides a structured and formatted output of the JVM statistics. It displays +the number of JARs, the Java version, the PHG version, and detailed memory statistics +(maximum memory, total memory, free memory, and allocated memory) in a human-readable format. +Memory values are shown in the respective units (e.g., bytes, MB, GB) defined in the object. } \section{Slots}{ @@ -21,6 +36,8 @@ An S4 class to represent statistics related to the Java Virtual Machine \item{\code{phgVersion}}{A character string representing the version of PHG (Practical Haplotype Graph).} +\item{\code{classPath}}{A character vector representing the JAR files found in the class path.} + \item{\code{maxMem}}{A numeric value representing the maximum amount of memory (in bytes) that the JVM can use.} diff --git a/man/show-JvmStats-method.Rd b/man/show-JvmStats-method.Rd deleted file mode 100644 index 65f1a38..0000000 --- a/man/show-JvmStats-method.Rd +++ /dev/null @@ -1,20 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/class_jvm_stats.R -\name{show,JvmStats-method} -\alias{show,JvmStats-method} -\title{Show method for JvmStats class} -\usage{ -\S4method{show}{JvmStats}(object) -} -\arguments{ -\item{object}{An object of class \code{JvmStats}.} -} -\description{ -Displays JVM statistics in a formatted manner. -} -\details{ -This method provides a structured and formatted output of the JVM statistics. It displays -the number of JARs, the Java version, the PHG version, and detailed memory statistics -(maximum memory, total memory, free memory, and allocated memory) in a human-readable format. -Memory values are shown in the respective units (e.g., bytes, MB, GB) defined in the object. -} From e1848b6160980db16bef2b97cc60688299430899 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 11 Oct 2024 17:01:19 -0500 Subject: [PATCH 13/14] Add constant --- R/class_jvm_stats.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/class_jvm_stats.R b/R/class_jvm_stats.R index 42d0c62..0a6b589 100644 --- a/R/class_jvm_stats.R +++ b/R/class_jvm_stats.R @@ -129,7 +129,7 @@ jvmStats <- function() { # Get memory profile runtime <- rJava::.jcall("java/lang/Runtime", "Ljava/lang/Runtime;", "getRuntime") - gbConv <- 1024 ^ 3 + gbConv <- 1073741824 # 1024 ^ 3 maxMem <- round(rJava::.jcall(runtime, "J", "maxMemory") / gbConv, 3) totMem <- round(rJava::.jcall(runtime, "J", "totalMemory") / gbConv, 3) freeMem <- round(rJava::.jcall(runtime, "J", "freeMemory") / gbConv, 3) From 42814973f070a6456885827a33d575425f081c8d Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 14 Oct 2024 17:52:12 -0500 Subject: [PATCH 14/14] Fix grammar --- vignettes/rPHG2.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/rPHG2.Rmd b/vignettes/rPHG2.Rmd index 8e6a3d3..0409f86 100644 --- a/vignettes/rPHG2.Rmd +++ b/vignettes/rPHG2.Rmd @@ -190,7 +190,7 @@ graph |> javaRefObj() Since we need to construct an interface to a local instance of Java, errors may arise due to several issues. Two common causes are version issues and memory allocated to the JVM. For debugging and monitoring purposes, we can -use the `jvmStats()` function which create a instance of a `JvmStats` object. +use the `jvmStats()` function which creates a instance of a `JvmStats` object. ```{r, eval=TRUE, echo=TRUE} javaStats <- jvmStats()