From caf42a79c8141ad05868beba6c806462f314442f Mon Sep 17 00:00:00 2001 From: Daena Rys Date: Mon, 21 Oct 2024 12:32:01 +0300 Subject: [PATCH 01/12] add plot method for eigenvalues Signed-off-by: Daena Rys --- NAMESPACE | 2 + R/plotScree.R | 151 ++++++++++++++++++++++++++++++++ man/plotScree.Rd | 101 +++++++++++++++++++++ tests/testthat/test-plotScree.R | 44 ++++++++++ 4 files changed, 298 insertions(+) create mode 100644 R/plotScree.R create mode 100644 man/plotScree.Rd create mode 100644 tests/testthat/test-plotScree.R diff --git a/NAMESPACE b/NAMESPACE index a0536b4..6ea3cad 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -14,6 +14,7 @@ export(plotRDA) export(plotRowGraph) export(plotRowPrevalence) export(plotRowTile) +export(plotScree) export(plotSeries) export(plotTaxaPrevalence) exportMethods("colTreeData<-") @@ -37,6 +38,7 @@ exportMethods(plotRowGraph) exportMethods(plotRowPrevalence) exportMethods(plotRowTile) exportMethods(plotRowTree) +exportMethods(plotScree) exportMethods(plotSeries) exportMethods(plotTaxaPrevalence) exportMethods(rowTreeData) diff --git a/R/plotScree.R b/R/plotScree.R new file mode 100644 index 0000000..f364f0d --- /dev/null +++ b/R/plotScree.R @@ -0,0 +1,151 @@ +#' Plot Scree Plot or Eigenvalues +#' +#' \code{plotScree} creates a scree plot or eigenvalues plot starting from a +#' SingleCellExperiment object or a vector of eigenvalues. This visualization +#' shows how the eigenvalues decrease across components. +#' +#' @param x a +#' \code{\link[SingleCellExperiment:SingleCellExperiment]{SingleCellExperiment}} +#' or a vector of eigenvalues. +#' +#' @param dimred \code{Character scalar} or \code{integer scalar}. Determines +#' the reduced dimension to plot. This is used when x is a SingleCellExperiment +#' to extract the eigenvalues from \code{reducedDim(x, dimred)}. +#' +#' @param show.barplot \code{Logical}. Whether to show a barplot. Default is +#' TRUE. +#' +#' @param show.points \code{Logical}. Whether to show points. Default is TRUE. +#' +#' @param show.line \code{Logical}. Whether to show a line connecting points. +#' Default is TRUE. +#' +#' @param show.labels \code{Logical}. Whether to show labels for each point. +#' Default is FALSE. +#' +#' @param cumulative \code{Logical}. Whether to show cumulative explained +#' variance. Default is FALSE. +#' +#' @param ... additional parameters for plotting +#' +#' @details +#' \code{plotScree} creates a scree plot or eigenvalues plot, which is useful +#' for visualizing the relative importance of components in dimensionality +#' reduction techniques like PCA, RDA, or CCA. When the input is a +#' SingleCellExperiment, the function extracts eigenvalues from the specified +#' reduced dimension slot. When the input is a vector, it directly uses these +#' values as eigenvalues. +#' +#' The plot can include a combination of barplot, points, connecting lines, +#' and labels, which can be controlled using the \code{show.*} parameters. +#' +#' An option to show cumulative explained variance is also available by setting +#' \code{cumulative = TRUE}. +#' +#' @return +#' A \code{ggplot2} object +#' +#' @name plotScree +#' +#' @examples +#' # Load necessary libraries +#' library(ggplot2) +#' +#' # Load dataset +#' library(miaViz) +#' data("enterotype", package = "mia") +#' tse <- enterotype +#' +#' # Run RDA and store results into TreeSE +#' tse <- addRDA( +#' tse, +#' formula = assay ~ ClinicalStatus + Gender + Age, +#' FUN = getDissimilarity, +#' distance = "bray", +#' na.action = na.exclude +#' ) +#' +#' # Plot scree plot +#' plotScree(sce, "RDA") +#' +NULL + +#' @rdname plotScree +#' @export +setGeneric("plotScree", signature = c("x"), + function(x, ...) standardGeneric("plotScree")) + +#' @rdname plotScree +#' @export +setMethod("plotScree", signature = c(x = "SingleCellExperiment"), + function(x, dimred, show.barplot = TRUE, show.points = TRUE, + show.line = TRUE, show.labels = FALSE, cumulative = FALSE, ...) { + # Check if dimred exists + if (!dimred %in% reducedDimNames(x)) { + stop("'dimred' must specify a valid reducedDim.", call. = FALSE) + } + + # Extract eigenvalues + eig <- attr(reducedDim(x, dimred), "eig") + if (is.null(eig)) { + stop("No eigenvalues found in the specified reducedDim.", + call. = FALSE) + } + + # Call the vector method + plotScree(as.numeric(eig), names(eig), show.barplot = show.barplot, + show.points = show.points, show.line = show.line, + show.labels = show.labels, cumulative = cumulative, ...) + } +) + +#' @rdname plotScree +#' @export +setMethod("plotScree", signature = c(x = "vector"), + function(x, names = NULL, show.barplot = TRUE, show.points = TRUE, + show.line = TRUE, show.labels = FALSE, cumulative = FALSE, ...) { + if (!is.numeric(x)) { + stop("'x' must be a numeric vector.", call. = FALSE) + } + + # Create data frame + df <- data.frame( + Component = if (!is.null(names)) names else seq_along(x), + Eigenvalue = x + ) + + # Calculate cumulative proportion if needed + if (cumulative) { + df$CumulativeProportion <- cumsum(df$Eigenvalue) / sum(df$Eigenvalue) + } + + # Create base plot + p <- ggplot(df, aes(x = Component, y = if (cumulative) + CumulativeProportion else Eigenvalue)) + + # Add layers based on user preferences + if (show.barplot) { + p <- p + geom_col(fill = "lightblue", color = "black") + } + if (show.points) { + p <- p + geom_point(size = 3) + } + if (show.line) { + p <- p + geom_line() + } + if (show.labels) { + p <- p + geom_text(aes(label = round(if (cumulative) + CumulativeProportion else Eigenvalue, 2)), vjust = -0.5) + } + + # Customize appearance + p <- p + theme_minimal() + + labs(x = "Component", + y = if (cumulative) "Cumulative Proportion of Variance" + else "Eigenvalue", + title = if (cumulative) "Cumulative Explained Variance" + else "Scree Plot") + + return(p) + } +) diff --git a/man/plotScree.Rd b/man/plotScree.Rd new file mode 100644 index 0000000..ddd4103 --- /dev/null +++ b/man/plotScree.Rd @@ -0,0 +1,101 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/plotScree.R +\name{plotScree} +\alias{plotScree} +\alias{plotScree,SingleCellExperiment-method} +\alias{plotScree,vector-method} +\title{Plot Scree Plot or Eigenvalues} +\usage{ +plotScree(x, ...) + +\S4method{plotScree}{SingleCellExperiment}( + x, + dimred, + show.barplot = TRUE, + show.points = TRUE, + show.line = TRUE, + show.labels = FALSE, + cumulative = FALSE, + ... +) + +\S4method{plotScree}{vector}( + x, + names = NULL, + show.barplot = TRUE, + show.points = TRUE, + show.line = TRUE, + show.labels = FALSE, + cumulative = FALSE, + ... +) +} +\arguments{ +\item{x}{a +\code{\link[SingleCellExperiment:SingleCellExperiment]{SingleCellExperiment}} +or a vector of eigenvalues.} + +\item{...}{additional parameters for plotting} + +\item{dimred}{\code{Character scalar} or \code{integer scalar}. Determines +the reduced dimension to plot. This is used when x is a SingleCellExperiment +to extract the eigenvalues from \code{reducedDim(x, dimred)}.} + +\item{show.barplot}{\code{Logical}. Whether to show a barplot. Default is +TRUE.} + +\item{show.points}{\code{Logical}. Whether to show points. Default is TRUE.} + +\item{show.line}{\code{Logical}. Whether to show a line connecting points. +Default is TRUE.} + +\item{show.labels}{\code{Logical}. Whether to show labels for each point. +Default is FALSE.} + +\item{cumulative}{\code{Logical}. Whether to show cumulative explained +variance. Default is FALSE.} +} +\value{ +A \code{ggplot2} object +} +\description{ +\code{plotScree} creates a scree plot or eigenvalues plot starting from a +SingleCellExperiment object or a vector of eigenvalues. This visualization +shows how the eigenvalues decrease across components. +} +\details{ +\code{plotScree} creates a scree plot or eigenvalues plot, which is useful +for visualizing the relative importance of components in dimensionality +reduction techniques like PCA, RDA, or CCA. When the input is a +SingleCellExperiment, the function extracts eigenvalues from the specified +reduced dimension slot. When the input is a vector, it directly uses these +values as eigenvalues. + +The plot can include a combination of barplot, points, connecting lines, +and labels, which can be controlled using the \code{show.*} parameters. + +An option to show cumulative explained variance is also available by setting +\code{cumulative = TRUE}. +} +\examples{ +# Load necessary libraries +library(ggplot2) + +# Load dataset +library(miaViz) +data("enterotype", package = "mia") +tse <- enterotype + +# Run RDA and store results into TreeSE +tse <- addRDA( + tse, + formula = assay ~ ClinicalStatus + Gender + Age, + FUN = getDissimilarity, + distance = "bray", + na.action = na.exclude + ) + +# Plot scree plot +plotScree(sce, "RDA") + +} diff --git a/tests/testthat/test-plotScree.R b/tests/testthat/test-plotScree.R new file mode 100644 index 0000000..f282849 --- /dev/null +++ b/tests/testthat/test-plotScree.R @@ -0,0 +1,44 @@ +test_that("plot Eigenvalues", { + data("enterotype", package = "mia") + tse <- enterotype + + tse <- addRDA( + tse, + formula = assay ~ ClinicalStatus + Gender + Age, + FUN = getDissimilarity, + distance = "bray", + na.action = na.exclude + ) + + # Define some eigenvalues for vector-based tests + eigenvalues <- sort(runif(10), decreasing = TRUE) + + # plotScree handles non-numeric eigenvalues in vector + expect_error(plotScree(c("a", "b", "c")), + "'x' must be a numeric vector.") + + # missing eigenvalues in SingleCellExperiment + sce <- SingleCellExperiment(assays = list(counts = matrix(rpois(1000, 5), + ncol = 10))) + + # Add reducedDim without eigenvalues + reducedDim(sce, "PCA") <- matrix(rnorm(100), ncol = 10) + + expect_error(plotScree(sce, "PCA"), + "No eigenvalues found in the specified reducedDim.") + + # invalid dimred input in SingleCellExperiment + expect_error(plotScree(tse, "invalid_dimred"), + "'dimred' must specify a valid reducedDim.") + + p <- plotScree(eigenvalues) + + # Check if a ggplot object is returned + expect_s3_class(p, "ggplot") + + + p <- plotScree(tse, "RDA") + + # Check if a ggplot object is returned + expect_s3_class(p, "ggplot") + }) \ No newline at end of file From 81b774dd2e425b4b3b009111c6ce26867ee05cc7 Mon Sep 17 00:00:00 2001 From: Daena Rys Date: Mon, 21 Oct 2024 12:56:36 +0300 Subject: [PATCH 02/12] update Signed-off-by: Daena Rys --- R/plotScree.R | 25 +++++++++++++++---------- man/plotScree.Rd | 25 +++++++++++++++---------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/R/plotScree.R b/R/plotScree.R index f364f0d..12fd96a 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -12,19 +12,24 @@ #' the reduced dimension to plot. This is used when x is a SingleCellExperiment #' to extract the eigenvalues from \code{reducedDim(x, dimred)}. #' -#' @param show.barplot \code{Logical}. Whether to show a barplot. Default is -#' TRUE. +#' @param show.barplot \code{Logical scalar}. Whether to show a barplot. +#' (Default: \code{TRUE}). #' -#' @param show.points \code{Logical}. Whether to show points. Default is TRUE. +#' @param show.points \code{Logical scalar}. Whether to show points. +#' (Default: \code{TRUE}). #' -#' @param show.line \code{Logical}. Whether to show a line connecting points. -#' Default is TRUE. +#' @param show.line \code{Logical scalar}. Whether to show a line connecting points. +#' (Default: \code{TRUE}). #' -#' @param show.labels \code{Logical}. Whether to show labels for each point. -#' Default is FALSE. +#' @param show.labels \code{Logical scalar}. Whether to show labels for each point. +#' (Default: \code{FALSE}). #' -#' @param cumulative \code{Logical}. Whether to show cumulative explained -#' variance. Default is FALSE. +#' @param cumulative \code{Logical scalar}. Whether to show cumulative explained +#' variance. (Default: \code{FALSE}). +#' +#' @param names \code{Character vector}. Optional names for the components +#' that will be displayed on the x-axis. If not provided, the components +#' are labeled sequentially as 1, 2, 3, etc. #' #' @param ... additional parameters for plotting #' @@ -66,7 +71,7 @@ #' ) #' #' # Plot scree plot -#' plotScree(sce, "RDA") +#' plotScree(tse, "RDA") #' NULL diff --git a/man/plotScree.Rd b/man/plotScree.Rd index ddd4103..702e847 100644 --- a/man/plotScree.Rd +++ b/man/plotScree.Rd @@ -41,19 +41,24 @@ or a vector of eigenvalues.} the reduced dimension to plot. This is used when x is a SingleCellExperiment to extract the eigenvalues from \code{reducedDim(x, dimred)}.} -\item{show.barplot}{\code{Logical}. Whether to show a barplot. Default is -TRUE.} +\item{show.barplot}{\code{Logical scalar}. Whether to show a barplot. +(Default: \code{TRUE}).} -\item{show.points}{\code{Logical}. Whether to show points. Default is TRUE.} +\item{show.points}{\code{Logical scalar}. Whether to show points. +(Default: \code{TRUE}).} -\item{show.line}{\code{Logical}. Whether to show a line connecting points. -Default is TRUE.} +\item{show.line}{\code{Logical scalar}. Whether to show a line connecting points. +(Default: \code{TRUE}).} -\item{show.labels}{\code{Logical}. Whether to show labels for each point. -Default is FALSE.} +\item{show.labels}{\code{Logical scalar}. Whether to show labels for each point. +(Default: \code{FALSE}).} -\item{cumulative}{\code{Logical}. Whether to show cumulative explained -variance. Default is FALSE.} +\item{cumulative}{\code{Logical scalar}. Whether to show cumulative explained +variance. (Default: \code{FALSE}).} + +\item{names}{\code{Character vector}. Optional names for the components +that will be displayed on the x-axis. If not provided, the components +are labeled sequentially as 1, 2, 3, etc.} } \value{ A \code{ggplot2} object @@ -96,6 +101,6 @@ tse <- addRDA( ) # Plot scree plot -plotScree(sce, "RDA") +plotScree(tse, "RDA") } From 9db93964730de25e25602e72ecf92b1ebc69eab2 Mon Sep 17 00:00:00 2001 From: Daena Rys Date: Mon, 21 Oct 2024 13:08:57 +0300 Subject: [PATCH 03/12] update Signed-off-by: Daena Rys --- R/plotScree.R | 119 ++++++++++++++++++++++------------------------- man/plotScree.Rd | 42 +++-------------- 2 files changed, 62 insertions(+), 99 deletions(-) diff --git a/R/plotScree.R b/R/plotScree.R index 12fd96a..4f261aa 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -1,29 +1,17 @@ #' Plot Scree Plot or Eigenvalues #' #' \code{plotScree} creates a scree plot or eigenvalues plot starting from a -#' SingleCellExperiment object or a vector of eigenvalues. This visualization +#' TreeSummarizedExperiment object or a vector of eigenvalues. This visualization #' shows how the eigenvalues decrease across components. #' #' @param x a -#' \code{\link[SingleCellExperiment:SingleCellExperiment]{SingleCellExperiment}} +#' \code{\link[TreeSummarizedExperiment:TreeSummarizedExperiment-constructor]{TreeSummarizedExperiment}} #' or a vector of eigenvalues. #' #' @param dimred \code{Character scalar} or \code{integer scalar}. Determines -#' the reduced dimension to plot. This is used when x is a SingleCellExperiment +#' the reduced dimension to plot. This is used when x is a TreeSummarizedExperiment #' to extract the eigenvalues from \code{reducedDim(x, dimred)}. #' -#' @param show.barplot \code{Logical scalar}. Whether to show a barplot. -#' (Default: \code{TRUE}). -#' -#' @param show.points \code{Logical scalar}. Whether to show points. -#' (Default: \code{TRUE}). -#' -#' @param show.line \code{Logical scalar}. Whether to show a line connecting points. -#' (Default: \code{TRUE}). -#' -#' @param show.labels \code{Logical scalar}. Whether to show labels for each point. -#' (Default: \code{FALSE}). -#' #' @param cumulative \code{Logical scalar}. Whether to show cumulative explained #' variance. (Default: \code{FALSE}). #' @@ -37,7 +25,7 @@ #' \code{plotScree} creates a scree plot or eigenvalues plot, which is useful #' for visualizing the relative importance of components in dimensionality #' reduction techniques like PCA, RDA, or CCA. When the input is a -#' SingleCellExperiment, the function extracts eigenvalues from the specified +#' TreeSummarizedExperiment, the function extracts eigenvalues from the specified #' reduced dimension slot. When the input is a vector, it directly uses these #' values as eigenvalues. #' @@ -83,8 +71,7 @@ setGeneric("plotScree", signature = c("x"), #' @rdname plotScree #' @export setMethod("plotScree", signature = c(x = "SingleCellExperiment"), - function(x, dimred, show.barplot = TRUE, show.points = TRUE, - show.line = TRUE, show.labels = FALSE, cumulative = FALSE, ...) { + function(x, dimred, cumulative = FALSE, ...) { # Check if dimred exists if (!dimred %in% reducedDimNames(x)) { stop("'dimred' must specify a valid reducedDim.", call. = FALSE) @@ -98,59 +85,65 @@ setMethod("plotScree", signature = c(x = "SingleCellExperiment"), } # Call the vector method - plotScree(as.numeric(eig), names(eig), show.barplot = show.barplot, - show.points = show.points, show.line = show.line, - show.labels = show.labels, cumulative = cumulative, ...) + plotScree(as.numeric(eig), names(eig), cumulative = cumulative, ...) } ) #' @rdname plotScree #' @export setMethod("plotScree", signature = c(x = "vector"), - function(x, names = NULL, show.barplot = TRUE, show.points = TRUE, - show.line = TRUE, show.labels = FALSE, cumulative = FALSE, ...) { + function(x, names = NULL, cumulative = FALSE, ...) { + # Ensure 'x' is numeric if (!is.numeric(x)) { stop("'x' must be a numeric vector.", call. = FALSE) } - - # Create data frame - df <- data.frame( - Component = if (!is.null(names)) names else seq_along(x), - Eigenvalue = x - ) - - # Calculate cumulative proportion if needed - if (cumulative) { - df$CumulativeProportion <- cumsum(df$Eigenvalue) / sum(df$Eigenvalue) - } - - # Create base plot - p <- ggplot(df, aes(x = Component, y = if (cumulative) - CumulativeProportion else Eigenvalue)) - - # Add layers based on user preferences - if (show.barplot) { - p <- p + geom_col(fill = "lightblue", color = "black") - } - if (show.points) { - p <- p + geom_point(size = 3) - } - if (show.line) { - p <- p + geom_line() - } - if (show.labels) { - p <- p + geom_text(aes(label = round(if (cumulative) - CumulativeProportion else Eigenvalue, 2)), vjust = -0.5) - } - - # Customize appearance - p <- p + theme_minimal() + - labs(x = "Component", - y = if (cumulative) "Cumulative Proportion of Variance" - else "Eigenvalue", - title = if (cumulative) "Cumulative Explained Variance" - else "Scree Plot") - - return(p) + # plot vector + .scree_plotter(x, names = names, cumulative = cumulative, ...) } ) + +.scree_plotter <- function(x, names = NULL, show.barplot = TRUE, + show.points = TRUE, + show.line = TRUE, show.labels = FALSE, + cumulative = FALSE, ...) { + # Create data frame + df <- data.frame( + Component = if (!is.null(names)) names else seq_along(x), + Eigenvalue = x + ) + + # Calculate cumulative proportion if needed + if (cumulative) { + df$CumulativeProportion <- cumsum(df$Eigenvalue) / sum(df$Eigenvalue) + } + + # Create base plot + p <- ggplot(df, aes(x = Component, y = if (cumulative) + CumulativeProportion else Eigenvalue)) + + # Add layers based on user preferences + if (show.barplot) { + p <- p + geom_col(fill = "lightblue", color = "black") + } + if (show.points) { + p <- p + geom_point(size = 3) + } + if (show.line) { + p <- p + geom_line() + } + if (show.labels) { + p <- p + geom_text(aes(label = round(if (cumulative) + CumulativeProportion else Eigenvalue, 2)), + vjust = -0.5) + } + + # Customize appearance + p <- p + theme_minimal() + + labs(x = "Component", + y = if (cumulative) "Cumulative Proportion of Variance" + else "Eigenvalue", + title = if (cumulative) "Cumulative Explained Variance" + else "Scree Plot") + + return(p) +} diff --git a/man/plotScree.Rd b/man/plotScree.Rd index 702e847..bd70bcb 100644 --- a/man/plotScree.Rd +++ b/man/plotScree.Rd @@ -8,51 +8,21 @@ \usage{ plotScree(x, ...) -\S4method{plotScree}{SingleCellExperiment}( - x, - dimred, - show.barplot = TRUE, - show.points = TRUE, - show.line = TRUE, - show.labels = FALSE, - cumulative = FALSE, - ... -) +\S4method{plotScree}{SingleCellExperiment}(x, dimred, cumulative = FALSE, ...) -\S4method{plotScree}{vector}( - x, - names = NULL, - show.barplot = TRUE, - show.points = TRUE, - show.line = TRUE, - show.labels = FALSE, - cumulative = FALSE, - ... -) +\S4method{plotScree}{vector}(x, names = NULL, cumulative = FALSE, ...) } \arguments{ \item{x}{a -\code{\link[SingleCellExperiment:SingleCellExperiment]{SingleCellExperiment}} +\code{\link[TreeSummarizedExperiment:TreeSummarizedExperiment-constructor]{TreeSummarizedExperiment}} or a vector of eigenvalues.} \item{...}{additional parameters for plotting} \item{dimred}{\code{Character scalar} or \code{integer scalar}. Determines -the reduced dimension to plot. This is used when x is a SingleCellExperiment +the reduced dimension to plot. This is used when x is a TreeSummarizedExperiment to extract the eigenvalues from \code{reducedDim(x, dimred)}.} -\item{show.barplot}{\code{Logical scalar}. Whether to show a barplot. -(Default: \code{TRUE}).} - -\item{show.points}{\code{Logical scalar}. Whether to show points. -(Default: \code{TRUE}).} - -\item{show.line}{\code{Logical scalar}. Whether to show a line connecting points. -(Default: \code{TRUE}).} - -\item{show.labels}{\code{Logical scalar}. Whether to show labels for each point. -(Default: \code{FALSE}).} - \item{cumulative}{\code{Logical scalar}. Whether to show cumulative explained variance. (Default: \code{FALSE}).} @@ -65,14 +35,14 @@ A \code{ggplot2} object } \description{ \code{plotScree} creates a scree plot or eigenvalues plot starting from a -SingleCellExperiment object or a vector of eigenvalues. This visualization +TreeSummarizedExperiment object or a vector of eigenvalues. This visualization shows how the eigenvalues decrease across components. } \details{ \code{plotScree} creates a scree plot or eigenvalues plot, which is useful for visualizing the relative importance of components in dimensionality reduction techniques like PCA, RDA, or CCA. When the input is a -SingleCellExperiment, the function extracts eigenvalues from the specified +TreeSummarizedExperiment, the function extracts eigenvalues from the specified reduced dimension slot. When the input is a vector, it directly uses these values as eigenvalues. From 64703ec31dd08995bad0a80bbd2e1e878b2ab5e5 Mon Sep 17 00:00:00 2001 From: Daena Rys Date: Mon, 21 Oct 2024 13:18:54 +0300 Subject: [PATCH 04/12] update Signed-off-by: Daena Rys --- R/plotScree.R | 26 ++++++++++++++++++++------ man/plotScree.Rd | 12 +++++++++++- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/R/plotScree.R b/R/plotScree.R index 4f261aa..8d3cc97 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -20,6 +20,16 @@ #' are labeled sequentially as 1, 2, 3, etc. #' #' @param ... additional parameters for plotting +#' \describe{ +#' \item{\code{show.barplot}}{Logical scalar. Whether to show a barplot. +#' (Default: \code{TRUE}).} +#' \item{\code{show.points}}{Logical scalar. Whether to show points. +#' (Default: \code{TRUE}).} +#' \item{\code{show.line}}{Logical scalar. Whether to show a line connecting +#' points. (Default: \code{TRUE}).} +#' \item{\code{show.labels}}{Logical scalar. Whether to show labels for each +#' point. (Default: \code{FALSE}).} +#' } #' #' @details #' \code{plotScree} creates a scree plot or eigenvalues plot, which is useful @@ -97,16 +107,13 @@ setMethod("plotScree", signature = c(x = "vector"), if (!is.numeric(x)) { stop("'x' must be a numeric vector.", call. = FALSE) } + plot_data <- .prepare_data(x, names, cumulative) # plot vector - .scree_plotter(x, names = names, cumulative = cumulative, ...) + .scree_plotter(plot_data, cumulative = cumulative, ...) } ) -.scree_plotter <- function(x, names = NULL, show.barplot = TRUE, - show.points = TRUE, - show.line = TRUE, show.labels = FALSE, - cumulative = FALSE, ...) { - # Create data frame +.prepare_data <- function(x, names = NULL, cumulative = FALSE) { df <- data.frame( Component = if (!is.null(names)) names else seq_along(x), Eigenvalue = x @@ -117,6 +124,13 @@ setMethod("plotScree", signature = c(x = "vector"), df$CumulativeProportion <- cumsum(df$Eigenvalue) / sum(df$Eigenvalue) } + return(df) +} + +.scree_plotter <- function(df, show.barplot = TRUE, + show.points = TRUE, + show.line = TRUE, show.labels = FALSE, + cumulative = FALSE, ...) { # Create base plot p <- ggplot(df, aes(x = Component, y = if (cumulative) CumulativeProportion else Eigenvalue)) diff --git a/man/plotScree.Rd b/man/plotScree.Rd index bd70bcb..6a30609 100644 --- a/man/plotScree.Rd +++ b/man/plotScree.Rd @@ -17,7 +17,17 @@ plotScree(x, ...) \code{\link[TreeSummarizedExperiment:TreeSummarizedExperiment-constructor]{TreeSummarizedExperiment}} or a vector of eigenvalues.} -\item{...}{additional parameters for plotting} +\item{...}{additional parameters for plotting +\describe{ +\item{\code{show.barplot}}{Logical scalar. Whether to show a barplot. +(Default: \code{TRUE}).} +\item{\code{show.points}}{Logical scalar. Whether to show points. +(Default: \code{TRUE}).} +\item{\code{show.line}}{Logical scalar. Whether to show a line connecting +points. (Default: \code{TRUE}).} +\item{\code{show.labels}}{Logical scalar. Whether to show labels for each +point. (Default: \code{FALSE}).} +}} \item{dimred}{\code{Character scalar} or \code{integer scalar}. Determines the reduced dimension to plot. This is used when x is a TreeSummarizedExperiment From b3be334467eca9f977ed0347f9cf4ffb6d6e4624 Mon Sep 17 00:00:00 2001 From: Daena Rys Date: Mon, 21 Oct 2024 13:33:50 +0300 Subject: [PATCH 05/12] update Signed-off-by: Daena Rys --- R/plotScree.R | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/R/plotScree.R b/R/plotScree.R index 8d3cc97..5b84711 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -86,10 +86,16 @@ setMethod("plotScree", signature = c(x = "SingleCellExperiment"), if (!dimred %in% reducedDimNames(x)) { stop("'dimred' must specify a valid reducedDim.", call. = FALSE) } + # Get reducedDim + reduced_dim <- reducedDim(tse, dimred) # Extract eigenvalues - eig <- attr(reducedDim(x, dimred), "eig") - if (is.null(eig)) { + # Check if data is available + ind <- names(attributes(reduced_dim)) %in% c("eig", "varExplained") + if( any(ind) ){ + # Add explained variance + eig <- attributes(reduced_dim)[ind][[1]] + } else{ stop("No eigenvalues found in the specified reducedDim.", call. = FALSE) } From 6f7afe83f4ba421bb1829c712422f9c07c6d45ff Mon Sep 17 00:00:00 2001 From: Daena Rys Date: Mon, 21 Oct 2024 13:52:12 +0300 Subject: [PATCH 06/12] update Signed-off-by: Daena Rys --- R/plotScree.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/plotScree.R b/R/plotScree.R index 5b84711..ffb0da0 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -87,7 +87,7 @@ setMethod("plotScree", signature = c(x = "SingleCellExperiment"), stop("'dimred' must specify a valid reducedDim.", call. = FALSE) } # Get reducedDim - reduced_dim <- reducedDim(tse, dimred) + reduced_dim <- reducedDim(x, dimred) # Extract eigenvalues # Check if data is available From 6154e28f51b2cbb20ad2d58b23687e6e534cd664 Mon Sep 17 00:00:00 2001 From: Daena Rys Date: Thu, 7 Nov 2024 11:50:08 +0200 Subject: [PATCH 07/12] update function Signed-off-by: Daena Rys --- R/plotScree.R | 52 +++++++++++++++++++----------------------------- man/plotScree.Rd | 2 +- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/R/plotScree.R b/R/plotScree.R index ffb0da0..b1c0a18 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -7,18 +7,14 @@ #' @param x a #' \code{\link[TreeSummarizedExperiment:TreeSummarizedExperiment-constructor]{TreeSummarizedExperiment}} #' or a vector of eigenvalues. -#' #' @param dimred \code{Character scalar} or \code{integer scalar}. Determines #' the reduced dimension to plot. This is used when x is a TreeSummarizedExperiment #' to extract the eigenvalues from \code{reducedDim(x, dimred)}. -#' #' @param cumulative \code{Logical scalar}. Whether to show cumulative explained #' variance. (Default: \code{FALSE}). -#' #' @param names \code{Character vector}. Optional names for the components #' that will be displayed on the x-axis. If not provided, the components #' are labeled sequentially as 1, 2, 3, etc. -#' #' @param ... additional parameters for plotting #' \describe{ #' \item{\code{show.barplot}}{Logical scalar. Whether to show a barplot. @@ -88,51 +84,50 @@ setMethod("plotScree", signature = c(x = "SingleCellExperiment"), } # Get reducedDim reduced_dim <- reducedDim(x, dimred) - # Extract eigenvalues # Check if data is available ind <- names(attributes(reduced_dim)) %in% c("eig", "varExplained") - if( any(ind) ){ - # Add explained variance - eig <- attributes(reduced_dim)[ind][[1]] - } else{ - stop("No eigenvalues found in the specified reducedDim.", - call. = FALSE) + if( !any(ind) ){ + stop("No eigenvalues found in the specified reducedDim.", + call. = FALSE) } - + eig <- attributes(reduced_dim)[ind][[1]] # Call the vector method - plotScree(as.numeric(eig), names(eig), cumulative = cumulative, ...) + result <- plotScree(as.numeric(eig), names(eig), cumulative = cumulative, ...) + return(result) } ) - #' @rdname plotScree #' @export setMethod("plotScree", signature = c(x = "vector"), - function(x, names = NULL, cumulative = FALSE, ...) { + function(x, cumulative = FALSE, ...) { # Ensure 'x' is numeric if (!is.numeric(x)) { stop("'x' must be a numeric vector.", call. = FALSE) } - plot_data <- .prepare_data(x, names, cumulative) + if (anyNA(x)) { + warning("NA values found in eigenvalues; + they will be omitted from the plot.") + } + plot_data <- .prepare_data(x, cumulative) # plot vector - .scree_plotter(plot_data, cumulative = cumulative, ...) + result <- .scree_plotter(plot_data, cumulative = cumulative, ...) + return(result) } ) - -.prepare_data <- function(x, names = NULL, cumulative = FALSE) { +.prepare_data <- function(x, cumulative = FALSE) { + # drop NA values in eigenvalues + x <- x[!is.na(x)] df <- data.frame( - Component = if (!is.null(names)) names else seq_along(x), + component = if (!is.null(names(x))) names(x) else seq_along(x), Eigenvalue = x ) - # Calculate cumulative proportion if needed if (cumulative) { df$CumulativeProportion <- cumsum(df$Eigenvalue) / sum(df$Eigenvalue) } - return(df) } - .scree_plotter <- function(df, show.barplot = TRUE, show.points = TRUE, show.line = TRUE, show.labels = FALSE, @@ -140,7 +135,6 @@ setMethod("plotScree", signature = c(x = "vector"), # Create base plot p <- ggplot(df, aes(x = Component, y = if (cumulative) CumulativeProportion else Eigenvalue)) - # Add layers based on user preferences if (show.barplot) { p <- p + geom_col(fill = "lightblue", color = "black") @@ -156,14 +150,10 @@ setMethod("plotScree", signature = c(x = "vector"), CumulativeProportion else Eigenvalue, 2)), vjust = -0.5) } - # Customize appearance p <- p + theme_minimal() + - labs(x = "Component", - y = if (cumulative) "Cumulative Proportion of Variance" - else "Eigenvalue", - title = if (cumulative) "Cumulative Explained Variance" - else "Scree Plot") - + labs(x = "PC", + y = if (cumulative) "Cumulative Proportion of Variance" + else "Eigenvalue") return(p) } diff --git a/man/plotScree.Rd b/man/plotScree.Rd index 6a30609..8d4a3e8 100644 --- a/man/plotScree.Rd +++ b/man/plotScree.Rd @@ -10,7 +10,7 @@ plotScree(x, ...) \S4method{plotScree}{SingleCellExperiment}(x, dimred, cumulative = FALSE, ...) -\S4method{plotScree}{vector}(x, names = NULL, cumulative = FALSE, ...) +\S4method{plotScree}{vector}(x, cumulative = FALSE, ...) } \arguments{ \item{x}{a From c87ec552bb2144cbd61c18bcec62db9d49b35b22 Mon Sep 17 00:00:00 2001 From: Daena Rys Date: Thu, 7 Nov 2024 12:33:05 +0200 Subject: [PATCH 08/12] support indices Signed-off-by: Daena Rys --- R/plotScree.R | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/R/plotScree.R b/R/plotScree.R index b1c0a18..22556fa 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -93,7 +93,7 @@ setMethod("plotScree", signature = c(x = "SingleCellExperiment"), } eig <- attributes(reduced_dim)[ind][[1]] # Call the vector method - result <- plotScree(as.numeric(eig), names(eig), cumulative = cumulative, ...) + result <- plotScree(as.numeric(eig), cumulative = cumulative, ...) return(result) } ) @@ -109,15 +109,19 @@ setMethod("plotScree", signature = c(x = "vector"), warning("NA values found in eigenvalues; they will be omitted from the plot.") } - plot_data <- .prepare_data(x, cumulative) + plot_data <- .prepare_data(x, cumulative, ...) # plot vector - result <- .scree_plotter(plot_data, cumulative = cumulative, ...) + result <- .scree_plotter(plot_data, cumulative, ...) return(result) } ) -.prepare_data <- function(x, cumulative = FALSE) { +.prepare_data <- function(x, cumulative = FALSE, indices = NULL, ...) { # drop NA values in eigenvalues x <- x[!is.na(x)] + # Subset eigenvalues based on indices (if provided) + if (!is.null(indices)) { + x <- x[indices] + } df <- data.frame( component = if (!is.null(names(x))) names(x) else seq_along(x), Eigenvalue = x @@ -128,12 +132,13 @@ setMethod("plotScree", signature = c(x = "vector"), } return(df) } -.scree_plotter <- function(df, show.barplot = TRUE, +.scree_plotter <- function(df, cumulative = FALSE, + show.barplot = TRUE, show.points = TRUE, - show.line = TRUE, show.labels = FALSE, - cumulative = FALSE, ...) { + show.line = TRUE, + show.labels = FALSE, ...) { # Create base plot - p <- ggplot(df, aes(x = Component, y = if (cumulative) + p <- ggplot(df, aes(x = component, y = if (cumulative) CumulativeProportion else Eigenvalue)) # Add layers based on user preferences if (show.barplot) { From 41381c807bee431af97090075de771707226cd5a Mon Sep 17 00:00:00 2001 From: Daena Rys Date: Thu, 7 Nov 2024 12:50:31 +0200 Subject: [PATCH 09/12] up Signed-off-by: Daena Rys --- R/plotScree.R | 3 --- man/plotScree.Rd | 4 ---- 2 files changed, 7 deletions(-) diff --git a/R/plotScree.R b/R/plotScree.R index 22556fa..526a668 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -12,9 +12,6 @@ #' to extract the eigenvalues from \code{reducedDim(x, dimred)}. #' @param cumulative \code{Logical scalar}. Whether to show cumulative explained #' variance. (Default: \code{FALSE}). -#' @param names \code{Character vector}. Optional names for the components -#' that will be displayed on the x-axis. If not provided, the components -#' are labeled sequentially as 1, 2, 3, etc. #' @param ... additional parameters for plotting #' \describe{ #' \item{\code{show.barplot}}{Logical scalar. Whether to show a barplot. diff --git a/man/plotScree.Rd b/man/plotScree.Rd index 8d4a3e8..434e60d 100644 --- a/man/plotScree.Rd +++ b/man/plotScree.Rd @@ -35,10 +35,6 @@ to extract the eigenvalues from \code{reducedDim(x, dimred)}.} \item{cumulative}{\code{Logical scalar}. Whether to show cumulative explained variance. (Default: \code{FALSE}).} - -\item{names}{\code{Character vector}. Optional names for the components -that will be displayed on the x-axis. If not provided, the components -are labeled sequentially as 1, 2, 3, etc.} } \value{ A \code{ggplot2} object From 214582f8d1b9aab75a549757086f4f8b8c16f011 Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Tue, 19 Nov 2024 19:18:48 +0200 Subject: [PATCH 10/12] up --- R/plotScree.R | 275 +++++++++++++++++++++++++++++------------------ man/plotScree.Rd | 32 +++--- 2 files changed, 186 insertions(+), 121 deletions(-) diff --git a/R/plotScree.R b/R/plotScree.R index 526a668..209beae 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -1,29 +1,14 @@ -#' Plot Scree Plot or Eigenvalues -#' +#' @name +#' plotScree +#' +#' @title +#' Create a scree plot +#' +#' @description #' \code{plotScree} creates a scree plot or eigenvalues plot starting from a #' TreeSummarizedExperiment object or a vector of eigenvalues. This visualization #' shows how the eigenvalues decrease across components. -#' -#' @param x a -#' \code{\link[TreeSummarizedExperiment:TreeSummarizedExperiment-constructor]{TreeSummarizedExperiment}} -#' or a vector of eigenvalues. -#' @param dimred \code{Character scalar} or \code{integer scalar}. Determines -#' the reduced dimension to plot. This is used when x is a TreeSummarizedExperiment -#' to extract the eigenvalues from \code{reducedDim(x, dimred)}. -#' @param cumulative \code{Logical scalar}. Whether to show cumulative explained -#' variance. (Default: \code{FALSE}). -#' @param ... additional parameters for plotting -#' \describe{ -#' \item{\code{show.barplot}}{Logical scalar. Whether to show a barplot. -#' (Default: \code{TRUE}).} -#' \item{\code{show.points}}{Logical scalar. Whether to show points. -#' (Default: \code{TRUE}).} -#' \item{\code{show.line}}{Logical scalar. Whether to show a line connecting -#' points. (Default: \code{TRUE}).} -#' \item{\code{show.labels}}{Logical scalar. Whether to show labels for each -#' point. (Default: \code{FALSE}).} -#' } -#' +#' #' @details #' \code{plotScree} creates a scree plot or eigenvalues plot, which is useful #' for visualizing the relative importance of components in dimensionality @@ -40,29 +25,42 @@ #' #' @return #' A \code{ggplot2} object -#' -#' @name plotScree +#' +#' @param x a +#' \code{\link[TreeSummarizedExperiment:TreeSummarizedExperiment-constructor]{TreeSummarizedExperiment}} +#' or a vector of eigenvalues. +#' @param dimred \code{Character scalar} or \code{integer scalar}. Determines +#' the reduced dimension to plot. This is used when x is a TreeSummarizedExperiment +#' to extract the eigenvalues from \code{reducedDim(x, dimred)}. +#' @param cumulative \code{Logical scalar}. Whether to show cumulative explained +#' variance. (Default: \code{FALSE}). +#' @param ... additional parameters for plotting +#' \itemize{ +#' \item \code{show.barplot}: \code{Logical scalar}. Whether to show a +#' barplot. (Default: \code{TRUE}) +#' +#' \item \code{show.points}: \code{Logical scalar}. Whether to show a +#' points. (Default: \code{TRUE}) +#' +#' \item \code{show.line}: \code{Logical scalar}. Whether to show a +#' line. (Default: \code{TRUE}) +#' +#' \item \code{show.labels}: \code{Logical scalar}. Whether to show a +#' labels for each point. (Default: \code{FALSE}) +#' } #' #' @examples -#' # Load necessary libraries -#' library(ggplot2) #' -#' # Load dataset #' library(miaViz) +#' library(scater) #' data("enterotype", package = "mia") #' tse <- enterotype #' -#' # Run RDA and store results into TreeSE -#' tse <- addRDA( -#' tse, -#' formula = assay ~ ClinicalStatus + Gender + Age, -#' FUN = getDissimilarity, -#' distance = "bray", -#' na.action = na.exclude -#' ) +#' # Run PCA and store results into TreeSE +#' tse <- runPCA(tse, assay.type = "counts") #' #' # Plot scree plot -#' plotScree(tse, "RDA") +#' plotScree(tse, "PCA") #' NULL @@ -74,88 +72,155 @@ setGeneric("plotScree", signature = c("x"), #' @rdname plotScree #' @export setMethod("plotScree", signature = c(x = "SingleCellExperiment"), - function(x, dimred, cumulative = FALSE, ...) { - # Check if dimred exists - if (!dimred %in% reducedDimNames(x)) { - stop("'dimred' must specify a valid reducedDim.", call. = FALSE) - } - # Get reducedDim - reduced_dim <- reducedDim(x, dimred) - # Extract eigenvalues - # Check if data is available - ind <- names(attributes(reduced_dim)) %in% c("eig", "varExplained") - if( !any(ind) ){ - stop("No eigenvalues found in the specified reducedDim.", - call. = FALSE) - } - eig <- attributes(reduced_dim)[ind][[1]] - # Call the vector method - result <- plotScree(as.numeric(eig), cumulative = cumulative, ...) - return(result) + function(x, dimred, ...){ + eig <- .get_eigenvalues(x, dimred, ...) + p <- plotScree(eig, ...) + return(p) } ) + #' @rdname plotScree #' @export -setMethod("plotScree", signature = c(x = "vector"), - function(x, cumulative = FALSE, ...) { - # Ensure 'x' is numeric - if (!is.numeric(x)) { - stop("'x' must be a numeric vector.", call. = FALSE) - } - if (anyNA(x)) { - warning("NA values found in eigenvalues; - they will be omitted from the plot.") +setMethod("plotScree", signature = c(x = "ANY"), + function(x, ...){ + # Check that the the values are in correct format + is_correct <- length(x) > 0L && + ((is.vector(x) && is.numeric(x)) || is(x, "eigenvals")) + if( !is_correct ){ + stop("Eigenvalues must be either numeric vector or class ", + "'eigenvals'.", call. = FALSE) } - plot_data <- .prepare_data(x, cumulative, ...) - # plot vector - result <- .scree_plotter(plot_data, cumulative, ...) - return(result) + # Prepare data for plotting + plot_data <- .prepare_data(x, ...) + # Create a plot + p <- .scree_plotter(plot_data, ...) + return(p) } ) -.prepare_data <- function(x, cumulative = FALSE, indices = NULL, ...) { - # drop NA values in eigenvalues - x <- x[!is.na(x)] - # Subset eigenvalues based on indices (if provided) - if (!is.null(indices)) { - x <- x[indices] - } - df <- data.frame( - component = if (!is.null(names(x))) names(x) else seq_along(x), - Eigenvalue = x - ) - # Calculate cumulative proportion if needed - if (cumulative) { - df$CumulativeProportion <- cumsum(df$Eigenvalue) / sum(df$Eigenvalue) + +################################ HELP FUNCTIONS ################################ + +# This function retrieves the eigenvalues from reducedDim. The ordination must +# be calculated with +.get_eigenvalues <- function( + x, dimred, eig.name = c("eig", "varExplained"), ...){ + # Get reducedDim + if( !((.is_a_string(dimred) && dimred %in% reducedDimNames(x)) || + (.is_an_integer(dimred) && dimred > 0 && + dimred <= length(reducedDims(x)))) ){ + stop("'dimred' must specify a valid reducedDim.", call. = FALSE) + } + reduced_dim <- reducedDim(x, dimred) + # Get eigenvalues + eig.name <- eig.name[ eig.name %in% names(attributes(reduced_dim)) ] + if( length(eig.name) != 1L ){ + stop("'eig.name' must specify a name of attributes from ", + "reducedDim(x, dimred).", call. = FALSE) + } + eig <- attributes(reduced_dim)[[ eig.name ]] + return(eig) +} + +# This function creates a data.frame from the input vector. The output is ready +# for plotter. +.prepare_data <- function(x, add.proportion = TRUE, add.cumulative = FALSE, n = NULL, show.names = FALSE, ...){ + # Input check + if( !.is_a_bool(add.cumulative) ){ + stop("'add.cumulative' must be TRUE or FALSE.", call. = FALSE) + } + if( !(is.null(n) || .is_an_integer(n) ) ){ + stop("'n' must be NULL or integer.", call. = FALSE) + } + if( !.is_a_bool(show.names) ){ + stop("'show.names' must be TRUE or FALSE.", call. = FALSE) + } + # + # Create a data.frame + df <- data.frame(value = x) + df[["pc"]] <- factor(rownames(df), levels = unique(rownames(df))) + df[["type"]] <- "proportion" + + # Add to same df. New col8umn that shos if poportional or cumualtive. + # Calculate cumulative proportion + df_cum <- df + df_cum[["value"]] <- cumsum(df_cum[["value"]]) / sum(df_cum[["value"]], na.rm = TRUE) + df_cum[["type"]] <- "cumulative" + df <- rbind(df, df_cum) + + + if( !add.proportion ){ + df <- df[df[["type"]] != "proportion", ] + } + if( !add.cumulative ){ + df <- df[df[["type"]] != "cumulative", ] + } + + # If user has specified, take only n first eigenvalues + if( !is.null(n) ){ + n <- levels(df[["pc"]])[ seq_len(n) ] + df <- df[ df[["pc"]] %in% n, ] + } + # Replace names with numbers + if( !show.names ){ + df[["pc"]] <- as.integer(df[["pc"]]) } return(df) } -.scree_plotter <- function(df, cumulative = FALSE, - show.barplot = TRUE, - show.points = TRUE, - show.line = TRUE, - show.labels = FALSE, ...) { - # Create base plot - p <- ggplot(df, aes(x = component, y = if (cumulative) - CumulativeProportion else Eigenvalue)) - # Add layers based on user preferences - if (show.barplot) { - p <- p + geom_col(fill = "lightblue", color = "black") + +# This function creates a scree plot. The input is data.frame that includes +# 2 columns: one for eigenvalues and other for principal component name. +.scree_plotter <- function( + df, show.points = TRUE, show.line = TRUE, show.barplot = FALSE, + show.labels = FALSE, ...){ + + if( length(unique(df[["type"]])) > 1L && !(show.labels || show.barplot) ){ + ind <- df[["type"]] == "cumulative" + df[ind, "value"] <- df[ind, "value"] * max(df[!ind, "value"]) # Scale } - if (show.points) { - p <- p + geom_point(size = 3) + + + # Create base plot + p <- ggplot(df, aes( + x = pc, + y = value, + group = type, + colour = if( length(unique(.data[["type"]])) > 1L && + !(show.labels || show.barplot) ) type + )) + + if( show.points ){ + p <- p + geom_point() } - if (show.line) { + if( show.line ){ p <- p + geom_line() } - if (show.labels) { - p <- p + geom_text(aes(label = round(if (cumulative) - CumulativeProportion else Eigenvalue, 2)), - vjust = -0.5) + if( show.barplot ){ + p <- p + geom_col(width = 0.5) + } + if( show.labels ){ + p <- p + geom_label(aes(label = round(value, 2))) + } + + if( length(unique(df[["type"]])) > 1L && (show.labels || show.barplot) ){ + p <- p + facet_grid(rows = vars(type), scales = "free_y") + } + + if( length(unique(df[["type"]])) > 1L && !(show.labels || show.barplot) ){ + p <- p + scale_y_continuous( + name = "Proportion", + sec.axis = sec_axis( + ~ . / max(df[["value"]]), name = "Cumulative proportion")) + } + + if( length(unique(df[["type"]])) == 1L ){ + p <- p + labs(x = "PC", y = "Eigenvalue") + } + if( is.numeric(df[["pc"]]) ){ + p <- p + + scale_x_continuous(breaks = scales::pretty_breaks()) } - # Customize appearance - p <- p + theme_minimal() + - labs(x = "PC", - y = if (cumulative) "Cumulative Proportion of Variance" - else "Eigenvalue") + + p <- p + theme_classic() + + theme(legend.position = "none") return(p) } diff --git a/man/plotScree.Rd b/man/plotScree.Rd index 434e60d..943c46e 100644 --- a/man/plotScree.Rd +++ b/man/plotScree.Rd @@ -3,14 +3,14 @@ \name{plotScree} \alias{plotScree} \alias{plotScree,SingleCellExperiment-method} -\alias{plotScree,vector-method} -\title{Plot Scree Plot or Eigenvalues} +\alias{plotScree,ANY-method} +\title{Create a scree plot} \usage{ plotScree(x, ...) -\S4method{plotScree}{SingleCellExperiment}(x, dimred, cumulative = FALSE, ...) +\S4method{plotScree}{SingleCellExperiment}(x, dimred, ...) -\S4method{plotScree}{vector}(x, cumulative = FALSE, ...) +\S4method{plotScree}{ANY}(x, cumulative = FALSE, ...) } \arguments{ \item{x}{a @@ -18,15 +18,18 @@ plotScree(x, ...) or a vector of eigenvalues.} \item{...}{additional parameters for plotting -\describe{ -\item{\code{show.barplot}}{Logical scalar. Whether to show a barplot. -(Default: \code{TRUE}).} -\item{\code{show.points}}{Logical scalar. Whether to show points. -(Default: \code{TRUE}).} -\item{\code{show.line}}{Logical scalar. Whether to show a line connecting -points. (Default: \code{TRUE}).} -\item{\code{show.labels}}{Logical scalar. Whether to show labels for each -point. (Default: \code{FALSE}).} +\itemize{ +\item \code{show.barplot}: \code{Logical scalar}. Whether to show a +barplot. (Default: \code{TRUE}) + +\item \code{show.points}: \code{Logical scalar}. Whether to show a +points. (Default: \code{TRUE}) + +\item \code{show.line}: \code{Logical scalar}. Whether to show a +line. (Default: \code{TRUE}) + +\item \code{show.labels}: \code{Logical scalar}. Whether to show a +labels for each point. (Default: \code{FALSE}) }} \item{dimred}{\code{Character scalar} or \code{integer scalar}. Determines @@ -59,10 +62,7 @@ An option to show cumulative explained variance is also available by setting \code{cumulative = TRUE}. } \examples{ -# Load necessary libraries -library(ggplot2) -# Load dataset library(miaViz) data("enterotype", package = "mia") tse <- enterotype From 5c958f006f674d62e6a5f45fc2fabd9e00d281b4 Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Wed, 20 Nov 2024 08:06:49 +0200 Subject: [PATCH 11/12] up --- R/plotScree.R | 56 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/R/plotScree.R b/R/plotScree.R index 209beae..03f9734 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -123,8 +123,13 @@ setMethod("plotScree", signature = c(x = "ANY"), # This function creates a data.frame from the input vector. The output is ready # for plotter. -.prepare_data <- function(x, add.proportion = TRUE, add.cumulative = FALSE, n = NULL, show.names = FALSE, ...){ +.prepare_data <- function( + x, add.proportion = TRUE, add.cumulative = FALSE, n = NULL, + show.names = FALSE, ...){ # Input check + if( !.is_a_bool(add.proportion) ){ + stop("'add.proportion' must be TRUE or FALSE.", call. = FALSE) + } if( !.is_a_bool(add.cumulative) ){ stop("'add.cumulative' must be TRUE or FALSE.", call. = FALSE) } @@ -135,32 +140,30 @@ setMethod("plotScree", signature = c(x = "ANY"), stop("'show.names' must be TRUE or FALSE.", call. = FALSE) } # - # Create a data.frame + # Create a data.frame with eigenvalues df <- data.frame(value = x) df[["pc"]] <- factor(rownames(df), levels = unique(rownames(df))) df[["type"]] <- "proportion" - - # Add to same df. New col8umn that shos if poportional or cumualtive. # Calculate cumulative proportion df_cum <- df - df_cum[["value"]] <- cumsum(df_cum[["value"]]) / sum(df_cum[["value"]], na.rm = TRUE) + df_cum[["value"]] <- cumsum(df_cum[["value"]]) / + sum(df_cum[["value"]], na.rm = TRUE) df_cum[["type"]] <- "cumulative" df <- rbind(df, df_cum) - + # Based on user preference, keep proportion or/and cumulative values if( !add.proportion ){ df <- df[df[["type"]] != "proportion", ] } if( !add.cumulative ){ df <- df[df[["type"]] != "cumulative", ] } - # If user has specified, take only n first eigenvalues if( !is.null(n) ){ n <- levels(df[["pc"]])[ seq_len(n) ] df <- df[ df[["pc"]] %in% n, ] } - # Replace names with numbers + # Replace names with integers if( !show.names ){ df[["pc"]] <- as.integer(df[["pc"]]) } @@ -172,22 +175,36 @@ setMethod("plotScree", signature = c(x = "ANY"), .scree_plotter <- function( df, show.points = TRUE, show.line = TRUE, show.barplot = FALSE, show.labels = FALSE, ...){ - + # Input check + if( !.is_a_bool(show.points) ){ + stop("'show.points' must be TRUE or FALSE.", call. = FALSE) + } + if( !.is_a_bool(show.line) ){ + stop("'show.line' must be TRUE or FALSE.", call. = FALSE) + } + if( !.is_a_bool(show.barplot) ){ + stop("'show.barplot' must be TRUE or FALSE.", call. = FALSE) + } + if( !.is_a_bool(show.labels) ){ + stop("'show.labels' must be TRUE or FALSE.", call. = FALSE) + } + # + # If user wants to add proportion and cumulative values to same plot, we + # scale cumulative values into same scale as proportion. if( length(unique(df[["type"]])) > 1L && !(show.labels || show.barplot) ){ ind <- df[["type"]] == "cumulative" df[ind, "value"] <- df[ind, "value"] * max(df[!ind, "value"]) # Scale } - # Create base plot p <- ggplot(df, aes( x = pc, y = value, group = type, - colour = if( length(unique(.data[["type"]])) > 1L && - !(show.labels || show.barplot) ) type + colour = if(length(unique(.data[["type"]])) > 1L && + !(show.labels || show.barplot) ) type )) - + # Add layers based on user preference if( show.points ){ p <- p + geom_point() } @@ -201,25 +218,32 @@ setMethod("plotScree", signature = c(x = "ANY"), p <- p + geom_label(aes(label = round(value, 2))) } + # If user wants to add barplots or labels with both cumulative and + # propotion values, the plot is splitted into two facets. Otherwise the + # the plot would be too messy to read. if( length(unique(df[["type"]])) > 1L && (show.labels || show.barplot) ){ p <- p + facet_grid(rows = vars(type), scales = "free_y") } - + # If user wants to plot both cumulative and proportion, but with points + # and lines only, we can add tem to same plot. Now the plot has two y-axis; + # proportion at left and cumulative at right if( length(unique(df[["type"]])) > 1L && !(show.labels || show.barplot) ){ p <- p + scale_y_continuous( name = "Proportion", sec.axis = sec_axis( ~ . / max(df[["value"]]), name = "Cumulative proportion")) } - + # Adjust labels in a case where either proportion or cumulative was plotted if( length(unique(df[["type"]])) == 1L ){ p <- p + labs(x = "PC", y = "Eigenvalue") } + # Adjust the x-axis to display a subset of evenly spaced values for + # improved readability if( is.numeric(df[["pc"]]) ){ p <- p + scale_x_continuous(breaks = scales::pretty_breaks()) } - + # Adjust theme and remove legend p <- p + theme_classic() + theme(legend.position = "none") return(p) From ac07ba9dd387bb60730a5b164977cb08a024c695 Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Wed, 20 Nov 2024 19:28:06 +0200 Subject: [PATCH 12/12] up --- DESCRIPTION | 5 +- NAMESPACE | 1 + NEWS | 1 + R/plotScree.R | 103 ++++++++++++++++++++------------ man/plotScree.Rd | 71 ++++++++++++++-------- tests/testthat/test-plotScree.R | 66 +++++++++----------- 6 files changed, 144 insertions(+), 103 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 3987868..26ba84c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: miaViz Title: Microbiome Analysis Plotting and Visualization -Version: 1.15.2 +Version: 1.15.3 Authors@R: c(person(given = "Tuomas", family = "Borman", role = c("aut", "cre"), email = "tuomas.v.borman@utu.fi", @@ -52,8 +52,9 @@ Imports: ggtree, methods, rlang, - scater, S4Vectors, + scales, + scater, SingleCellExperiment, stats, tibble, diff --git a/NAMESPACE b/NAMESPACE index 4101ba2..12132f4 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -135,6 +135,7 @@ importFrom(mia,meltSE) importFrom(rlang,"!!") importFrom(rlang,":=") importFrom(rlang,sym) +importFrom(scales,pretty_breaks) importFrom(scater,plotReducedDim) importFrom(scater,retrieveCellInfo) importFrom(scater,retrieveFeatureInfo) diff --git a/NEWS b/NEWS index 36e02f4..74b4a4a 100644 --- a/NEWS +++ b/NEWS @@ -36,3 +36,4 @@ Changes in version 1.13.x Changes in version 1.15.x + plotAbundance: Improved visualization of sample metadata ++ plotScree: Method for creating scree plots diff --git a/R/plotScree.R b/R/plotScree.R index 03f9734..66bb329 100644 --- a/R/plotScree.R +++ b/R/plotScree.R @@ -5,35 +5,41 @@ #' Create a scree plot #' #' @description -#' \code{plotScree} creates a scree plot or eigenvalues plot starting from a -#' TreeSummarizedExperiment object or a vector of eigenvalues. This visualization -#' shows how the eigenvalues decrease across components. +#' \code{plotScree} generates a scree plot to visualize the eigenvalues. +#' The eigenvalues can be provided either as a part of a +#' \code{TreeSummarizedExperiment} object or as a separate \code{vector}. +#' This plot illustrates the decline in eigenvalues across components, +#' helping to assess the importance of each component. #' #' @details -#' \code{plotScree} creates a scree plot or eigenvalues plot, which is useful -#' for visualizing the relative importance of components in dimensionality -#' reduction techniques like PCA, RDA, or CCA. When the input is a -#' TreeSummarizedExperiment, the function extracts eigenvalues from the specified -#' reduced dimension slot. When the input is a vector, it directly uses these -#' values as eigenvalues. +#' \code{plotScree} generates a scree plot to visualize the relative importance +#' of components in dimensionality reduction techniques such as Principal +#' Component Analysis (PCA) or Principal Coordinate Analysis (PCoA). If the +#' input is a \code{TreeSummarizedExperiment} object, the function extracts +#' eigenvalues from the specified reduced dimension slot, which requires that +#' dimensionality reduction has been performed beforehand using a dedicated +#' function. Alternatively, if the input is a \code{vector} or an +#' \code{eigenvals} object, these values are directly used as eigenvalues for +#' the plot. #' #' The plot can include a combination of barplot, points, connecting lines, #' and labels, which can be controlled using the \code{show.*} parameters. #' #' An option to show cumulative explained variance is also available by setting -#' \code{cumulative = TRUE}. +#' \code{add.cumulative = TRUE}. #' #' @return #' A \code{ggplot2} object #' #' @param x a #' \code{\link[TreeSummarizedExperiment:TreeSummarizedExperiment-constructor]{TreeSummarizedExperiment}} -#' or a vector of eigenvalues. +#' \code{\link[vegan:eigenvals]{eigenvals}} or a vector. +#' #' @param dimred \code{Character scalar} or \code{integer scalar}. Determines -#' the reduced dimension to plot. This is used when x is a TreeSummarizedExperiment -#' to extract the eigenvalues from \code{reducedDim(x, dimred)}. -#' @param cumulative \code{Logical scalar}. Whether to show cumulative explained -#' variance. (Default: \code{FALSE}). +#' the reduced dimension to plot. This is used when \code{x} is a +#' \code{TreeSummarizedExperiment} to extract the eigenvalues from +#' \code{reducedDim(x, dimred)}. +#' #' @param ... additional parameters for plotting #' \itemize{ #' \item \code{show.barplot}: \code{Logical scalar}. Whether to show a @@ -47,20 +53,41 @@ #' #' \item \code{show.labels}: \code{Logical scalar}. Whether to show a #' labels for each point. (Default: \code{FALSE}) +#' +#' \item \code{add.proportion}: \code{Logical scalar}. Whether to show +#' proportion of explained variance, i.e., raw eigenvalues. +#' (Default: \code{TRUE}) +#' +#' \item \code{add.cumulative}: \code{Logical scalar}. Whether to show +#' cumulative explained variance calculated from eigenvalues. +#' (Default: \code{FALSE}) +#' +#' \item \code{n}: \code{Integer scalar}. Number of eigenvalues to plot. +#' If \code{NULL}, all eigenvalues are plotted. (Default: \code{NULL}) +#' +#' \item \code{show.names}: \code{Logical scalar}. Whether to show names of +#' components in x-axis. If \code{FALSE}, the index of component is shown +#' instead of names. (Default: \code{FALSE}) +#' +#' \item \code{eig.name}: \code{Character scalar}. The name of the attribute +#' in \code{reducedDim(x, dimred)} that contains the eigenvalues. +#' (Default: \code{c("eig", "varExplained")}) #' } #' #' @examples #' #' library(miaViz) #' library(scater) +#' #' data("enterotype", package = "mia") #' tse <- enterotype #' #' # Run PCA and store results into TreeSE -#' tse <- runPCA(tse, assay.type = "counts") +#' tse <- transformAssay(tse, method = "clr", pseudocount = TRUE) +#' tse <- runPCA(tse, assay.type = "clr") #' #' # Plot scree plot -#' plotScree(tse, "PCA") +#' plotScree(tse, "PCA", add.cumulative = TRUE) #' NULL @@ -87,8 +114,8 @@ setMethod("plotScree", signature = c(x = "ANY"), is_correct <- length(x) > 0L && ((is.vector(x) && is.numeric(x)) || is(x, "eigenvals")) if( !is_correct ){ - stop("Eigenvalues must be either numeric vector or class ", - "'eigenvals'.", call. = FALSE) + stop("'x' must be a numeric vector or class 'eigenvals'.", + call. = FALSE) } # Prepare data for plotting plot_data <- .prepare_data(x, ...) @@ -101,13 +128,14 @@ setMethod("plotScree", signature = c(x = "ANY"), ################################ HELP FUNCTIONS ################################ # This function retrieves the eigenvalues from reducedDim. The ordination must -# be calculated with +# be calculated with dedicaded function in mia or scater so that the eigenvalues +# are stored in correct place. .get_eigenvalues <- function( x, dimred, eig.name = c("eig", "varExplained"), ...){ # Get reducedDim if( !((.is_a_string(dimred) && dimred %in% reducedDimNames(x)) || - (.is_an_integer(dimred) && dimred > 0 && - dimred <= length(reducedDims(x)))) ){ + (.is_an_integer(dimred) && dimred > 0 && + dimred <= length(reducedDims(x)))) ){ stop("'dimred' must specify a valid reducedDim.", call. = FALSE) } reduced_dim <- reducedDim(x, dimred) @@ -141,13 +169,13 @@ setMethod("plotScree", signature = c(x = "ANY"), } # # Create a data.frame with eigenvalues - df <- data.frame(value = x) - df[["pc"]] <- factor(rownames(df), levels = unique(rownames(df))) + df <- data.frame(y = x) + df[["x"]] <- factor(rownames(df), levels = unique(rownames(df))) df[["type"]] <- "proportion" # Calculate cumulative proportion df_cum <- df - df_cum[["value"]] <- cumsum(df_cum[["value"]]) / - sum(df_cum[["value"]], na.rm = TRUE) + df_cum[["y"]] <- cumsum(df_cum[["y"]]) / + sum(df_cum[["y"]], na.rm = TRUE) df_cum[["type"]] <- "cumulative" df <- rbind(df, df_cum) @@ -160,18 +188,19 @@ setMethod("plotScree", signature = c(x = "ANY"), } # If user has specified, take only n first eigenvalues if( !is.null(n) ){ - n <- levels(df[["pc"]])[ seq_len(n) ] - df <- df[ df[["pc"]] %in% n, ] + n <- levels(df[["x"]])[ seq_len(n) ] + df <- df[ df[["x"]] %in% n, ] } - # Replace names with integers + # Replace names with integers to keep the x-axis of plot tidier if( !show.names ){ - df[["pc"]] <- as.integer(df[["pc"]]) + df[["x"]] <- as.integer(df[["x"]]) } return(df) } # This function creates a scree plot. The input is data.frame that includes # 2 columns: one for eigenvalues and other for principal component name. +#' @importFrom scales pretty_breaks .scree_plotter <- function( df, show.points = TRUE, show.line = TRUE, show.barplot = FALSE, show.labels = FALSE, ...){ @@ -193,13 +222,13 @@ setMethod("plotScree", signature = c(x = "ANY"), # scale cumulative values into same scale as proportion. if( length(unique(df[["type"]])) > 1L && !(show.labels || show.barplot) ){ ind <- df[["type"]] == "cumulative" - df[ind, "value"] <- df[ind, "value"] * max(df[!ind, "value"]) # Scale + df[ind, "y"] <- df[ind, "y"] * max(df[!ind, "y"]) # Scale } # Create base plot p <- ggplot(df, aes( - x = pc, - y = value, + x = x, + y = y, group = type, colour = if(length(unique(.data[["type"]])) > 1L && !(show.labels || show.barplot) ) type @@ -215,7 +244,7 @@ setMethod("plotScree", signature = c(x = "ANY"), p <- p + geom_col(width = 0.5) } if( show.labels ){ - p <- p + geom_label(aes(label = round(value, 2))) + p <- p + geom_label(aes(label = round(y, 2))) } # If user wants to add barplots or labels with both cumulative and @@ -231,7 +260,7 @@ setMethod("plotScree", signature = c(x = "ANY"), p <- p + scale_y_continuous( name = "Proportion", sec.axis = sec_axis( - ~ . / max(df[["value"]]), name = "Cumulative proportion")) + ~ . / max(df[["y"]]), name = "Cumulative proportion")) } # Adjust labels in a case where either proportion or cumulative was plotted if( length(unique(df[["type"]])) == 1L ){ @@ -239,9 +268,9 @@ setMethod("plotScree", signature = c(x = "ANY"), } # Adjust the x-axis to display a subset of evenly spaced values for # improved readability - if( is.numeric(df[["pc"]]) ){ + if( is.numeric(df[["x"]]) ){ p <- p + - scale_x_continuous(breaks = scales::pretty_breaks()) + scale_x_continuous(breaks = pretty_breaks()) } # Adjust theme and remove legend p <- p + theme_classic() + diff --git a/man/plotScree.Rd b/man/plotScree.Rd index 943c46e..d68d623 100644 --- a/man/plotScree.Rd +++ b/man/plotScree.Rd @@ -10,12 +10,12 @@ plotScree(x, ...) \S4method{plotScree}{SingleCellExperiment}(x, dimred, ...) -\S4method{plotScree}{ANY}(x, cumulative = FALSE, ...) +\S4method{plotScree}{ANY}(x, ...) } \arguments{ \item{x}{a \code{\link[TreeSummarizedExperiment:TreeSummarizedExperiment-constructor]{TreeSummarizedExperiment}} -or a vector of eigenvalues.} +\code{\link[vegan:eigenvals]{eigenvals}} or a vector.} \item{...}{additional parameters for plotting \itemize{ @@ -30,53 +30,72 @@ line. (Default: \code{TRUE}) \item \code{show.labels}: \code{Logical scalar}. Whether to show a labels for each point. (Default: \code{FALSE}) + +\item \code{add.proportion}: \code{Logical scalar}. Whether to show +proportion of explained variance, i.e., raw eigenvalues. +(Default: \code{TRUE}) + +\item \code{add.cumulative}: \code{Logical scalar}. Whether to show +cumulative explained variance calculated from eigenvalues. +(Default: \code{FALSE}) + +\item \code{n}: \code{Integer scalar}. Number of eigenvalues to plot. +If \code{NULL}, all eigenvalues are plotted. (Default: \code{NULL}) + +\item \code{show.names}: \code{Logical scalar}. Whether to show names of +components in x-axis. If \code{FALSE}, the index of component is shown +instead of names. (Default: \code{FALSE}) + +\item \code{eig.name}: \code{Character scalar}. The name of the attribute +in \code{reducedDim(x, dimred)} that contains the eigenvalues. +(Default: \code{c("eig", "varExplained")}) }} \item{dimred}{\code{Character scalar} or \code{integer scalar}. Determines -the reduced dimension to plot. This is used when x is a TreeSummarizedExperiment -to extract the eigenvalues from \code{reducedDim(x, dimred)}.} - -\item{cumulative}{\code{Logical scalar}. Whether to show cumulative explained -variance. (Default: \code{FALSE}).} +the reduced dimension to plot. This is used when \code{x} is a +\code{TreeSummarizedExperiment} to extract the eigenvalues from +\code{reducedDim(x, dimred)}.} } \value{ A \code{ggplot2} object } \description{ -\code{plotScree} creates a scree plot or eigenvalues plot starting from a -TreeSummarizedExperiment object or a vector of eigenvalues. This visualization -shows how the eigenvalues decrease across components. +\code{plotScree} generates a scree plot to visualize the eigenvalues. +The eigenvalues can be provided either as a part of a +\code{TreeSummarizedExperiment} object or as a separate \code{vector}. +This plot illustrates the decline in eigenvalues across components, +helping to assess the importance of each component. } \details{ -\code{plotScree} creates a scree plot or eigenvalues plot, which is useful -for visualizing the relative importance of components in dimensionality -reduction techniques like PCA, RDA, or CCA. When the input is a -TreeSummarizedExperiment, the function extracts eigenvalues from the specified -reduced dimension slot. When the input is a vector, it directly uses these -values as eigenvalues. +\code{plotScree} generates a scree plot to visualize the relative importance +of components in dimensionality reduction techniques such as Principal +Component Analysis (PCA) or Principal Coordinate Analysis (PCoA). If the +input is a \code{TreeSummarizedExperiment} object, the function extracts +eigenvalues from the specified reduced dimension slot, which requires that +dimensionality reduction has been performed beforehand using a dedicated +function. Alternatively, if the input is a \code{vector} or an +\code{eigenvals} object, these values are directly used as eigenvalues for +the plot. The plot can include a combination of barplot, points, connecting lines, and labels, which can be controlled using the \code{show.*} parameters. An option to show cumulative explained variance is also available by setting -\code{cumulative = TRUE}. +\code{add.cumulative = TRUE}. } \examples{ library(miaViz) +library(scater) + data("enterotype", package = "mia") tse <- enterotype -# Run RDA and store results into TreeSE -tse <- addRDA( - tse, - formula = assay ~ ClinicalStatus + Gender + Age, - FUN = getDissimilarity, - distance = "bray", - na.action = na.exclude - ) +# Run PCA and store results into TreeSE +tse <- transformAssay(tse, method = "clr", pseudocount = TRUE) +tse <- runPCA(tse, assay.type = "clr") # Plot scree plot -plotScree(tse, "RDA") +plotScree(tse, "PCA", add.cumulative = TRUE) } diff --git a/tests/testthat/test-plotScree.R b/tests/testthat/test-plotScree.R index f282849..872468d 100644 --- a/tests/testthat/test-plotScree.R +++ b/tests/testthat/test-plotScree.R @@ -1,44 +1,34 @@ test_that("plot Eigenvalues", { - data("enterotype", package = "mia") - tse <- enterotype - - tse <- addRDA( - tse, - formula = assay ~ ClinicalStatus + Gender + Age, - FUN = getDissimilarity, - distance = "bray", - na.action = na.exclude - ) - - # Define some eigenvalues for vector-based tests - eigenvalues <- sort(runif(10), decreasing = TRUE) - # plotScree handles non-numeric eigenvalues in vector - expect_error(plotScree(c("a", "b", "c")), - "'x' must be a numeric vector.") - - # missing eigenvalues in SingleCellExperiment - sce <- SingleCellExperiment(assays = list(counts = matrix(rpois(1000, 5), - ncol = 10))) - + expect_error( + plotScree(c("a", "b", "c")), + "'x' must be a numeric vector or class 'eigenvals'.") + # Missing eigenvalues in TreeSummarizedExperiment + tse <- TreeSummarizedExperiment( + assays = list(counts = matrix(rpois(1000, 5), ncol = 10))) # Add reducedDim without eigenvalues - reducedDim(sce, "PCA") <- matrix(rnorm(100), ncol = 10) - - expect_error(plotScree(sce, "PCA"), - "No eigenvalues found in the specified reducedDim.") - - # invalid dimred input in SingleCellExperiment - expect_error(plotScree(tse, "invalid_dimred"), - "'dimred' must specify a valid reducedDim.") - - p <- plotScree(eigenvalues) - - # Check if a ggplot object is returned - expect_s3_class(p, "ggplot") - - - p <- plotScree(tse, "RDA") + reducedDim(tse, "PCA") <- matrix(rnorm(100), ncol = 10) + expect_error(plotScree(tse, "PCA")) + # Invalid dimred input + expect_error( + plotScree(tse, "invalid_dimred"), + "'dimred' must specify a valid reducedDim.") + # Define some eigenvalues for vector-based tests + eigenvalues <- sort(runif(10), decreasing = TRUE) + # Check that eigenvalues are plotted from TreeSE or from vector + attr(reducedDim(tse, "PCA"), "test") <- eigenvalues + expect_error(plotScree(tse, "PCA")) + p1 <- plotScree(tse, "PCA", eig.name = "test") + p2 <- plotScree(eigenvalues) # Check if a ggplot object is returned + expect_s3_class(p1, "ggplot") + # Check if the plots are equal + df1 <- ggplot_build(p1)[[1]][[1]] + df2 <- ggplot_build(p2)[[1]][[1]] + expect_equal(df1, df2) + + # Test with different options + p <- plotScree(tse, 1, eig.name = "test", add.cumulative = TRUE, n = 10000) expect_s3_class(p, "ggplot") - }) \ No newline at end of file +})