From ee102d64d5bff91759fbe994d61a73355999b0c1 Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Mon, 7 Oct 2024 08:50:51 +0300 Subject: [PATCH 1/8] up --- R/plotLoadings.R | 55 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/R/plotLoadings.R b/R/plotLoadings.R index cee6be6..ab0ef3f 100644 --- a/R/plotLoadings.R +++ b/R/plotLoadings.R @@ -278,12 +278,22 @@ setMethod("plotLoadings", signature = c(x = "matrix"), # This functions plots a data.frame in barplot or heatmap layout. #' @importFrom tidytext scale_y_reordered reorder_within #' @importFrom ggplot2 geom_tile scale_fill_gradient2 geom_bar -.plot_loadings <- function(df, layout, absolute.scale = TRUE, ...) { +.plot_loadings <- function( + df, layout, absolute.scale = TRUE, show.color = TRUE, show.sign = FALSE, + ...) { # if( !.is_a_bool(absolute.scale) ){ stop("'absolute.scale' must be TRUE or FALSE.", call. = FALSE) } # + if( !.is_a_bool(show.color) ){ + stop("'show.color' must be TRUE or FALSE.", call. = FALSE) + } + # + if( !.is_a_bool(show.sign) ){ + stop("'show.sign' must be TRUE or FALSE.", call. = FALSE) + } + # # Initialize a plot plot_out <- ggplot(df) # Either create a heatmap or barplt @@ -318,21 +328,36 @@ setMethod("plotLoadings", signature = c(x = "matrix"), } else if( layout == "barplot" && absolute.scale ){ # This creates a barplot where bars are in absolute scale and the sing - # is denoted with +/- + # is denoted with +/- sign or color + + # Create an aesthetic based on whether to show sign with colors + if( show.color ){ + aesthetic <- aes( + x = Value_abs, + y = reorder_within(Feature, -Value_abs, PC), + fill = Sign + ) + } else{ + aesthetic <- aes( + x = Value_abs, y = reorder_within(Feature, -Value_abs, PC)) + } + # Create bars with absolute scale + plot_out <- plot_out + + + geom_bar(mapping = aesthetic, stat = "identity" + ) + # Add sign that tells whether the value is + or - + if( show.sign ){ + plot_out <- plot_out + + geom_text(aes( + x = max(Value_abs) + max(Value_abs)*0.1, + y = reorder_within(Feature, -Value_abs, PC), + label = Sign, + fontface = "bold" + )) + } + # Final wrangle, set facets and order the data plot_out <- plot_out + - # Create bars with absolute scale - geom_bar( - mapping = aes( - x = Value_abs, y = reorder_within(Feature, -Value_abs, PC)), - stat = "identity" - ) + - # Add sign that tells whether the value is + or - - geom_text(aes( - x = max(Value_abs) + max(Value_abs)*0.1, - y = reorder_within(Feature, Value_abs, PC), - label = Sign, - fontface = "bold" - )) + scale_y_reordered() + facet_wrap(~ PC, scales = "free") + labs(x = "Value", y = "Feature") From 63184e78f260be19d450184851e56c7ce5af2fd3 Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Mon, 7 Oct 2024 08:51:28 +0300 Subject: [PATCH 2/8] up --- R/plotLoadings.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/plotLoadings.R b/R/plotLoadings.R index ab0ef3f..3f26dc9 100644 --- a/R/plotLoadings.R +++ b/R/plotLoadings.R @@ -360,8 +360,7 @@ setMethod("plotLoadings", signature = c(x = "matrix"), plot_out <- plot_out + scale_y_reordered() + facet_wrap(~ PC, scales = "free") + - labs(x = "Value", y = "Feature") - + labs(x = "Value", y = "Feature") } # Adjust theme plot_out <- plot_out + From 5c15df9225d4a6a5fed6e668bf20de509f5b4a74 Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Mon, 7 Oct 2024 13:50:43 +0300 Subject: [PATCH 3/8] up --- R/plotLoadings.R | 178 ++++++++++++++++++++++++++++------------------- 1 file changed, 108 insertions(+), 70 deletions(-) diff --git a/R/plotLoadings.R b/R/plotLoadings.R index 3f26dc9..67eca56 100644 --- a/R/plotLoadings.R +++ b/R/plotLoadings.R @@ -11,7 +11,8 @@ #' plot. #' #' @param layout \code{Character scalar}. Determines the layout of plot. Must be -#' either \code{"barplot"} or \code{"heatmap"}. (Default: \code{"barplot"}) +#' either \code{"barplot"}, \code{"heatmap"}, or \code{"lollipop"}. +#' (Default: \code{"barplot"}) #' #' @param ncomponents \code{Numeric scalar}. Number of components must be lower #' or equal to the number of components chosen in the reduction method. @@ -203,7 +204,8 @@ setMethod("plotLoadings", signature = c(x = "matrix"), # This functions checks that loadings matrix is correct .check_loadings_matrix <- function(mat, layout, ncomponents, n = 10, ...) { # Check layout - if( !(.is_a_string(layout) && layout %in% c("barplot", "heatmap")) ){ + if( !(.is_a_string(layout) && layout %in% + c("barplot", "heatmap", "lollipop")) ){ stop("'layout' must be 'barplot' or 'heatmap',", call. = FALSE) } # Check n @@ -232,7 +234,7 @@ setMethod("plotLoadings", signature = c(x = "matrix"), # Keep only the number of components needed df <- df[ , seq_len(ncomponents), drop = FALSE] # If the layout is barplot, choose top features for each component - if( layout %in% c("barplot") ){ + if( layout %in% c("barplot", "lollipop") ){ res <- lapply(seq_len(ncomponents), .process_component, df = df, n = n) # Combine to single data.frame res <- do.call(rbind, res) @@ -253,6 +255,15 @@ setMethod("plotLoadings", signature = c(x = "matrix"), res[["Value_abs"]] <- abs(res[["Value"]]) res[["Sign"]] <- ifelse( res[["Value"]] > 0, "+", ifelse(res[["Value"]] < 0, "-", "")) + # Add maximum values. This is used in scaling and placement of +/- sign + # in barplot and lollipop plot. + temp <- max(res[["Value_abs"]], na.rm = TRUE) + res[["max_scale_abs"]] <- temp + 0.1*temp + res[["max_scale"]] <- NA + temp <- min(res[["Value"]], na.rm = TRUE) + res[res[["Value"]]<0, "max_scale"] <- temp + 0.1*temp + temp <- max(res[["Value"]], na.rm = TRUE) + res[res[["Value"]]>0, "max_scale"] <- temp + 0.1*temp return(res) } @@ -278,25 +289,10 @@ setMethod("plotLoadings", signature = c(x = "matrix"), # This functions plots a data.frame in barplot or heatmap layout. #' @importFrom tidytext scale_y_reordered reorder_within #' @importFrom ggplot2 geom_tile scale_fill_gradient2 geom_bar -.plot_loadings <- function( - df, layout, absolute.scale = TRUE, show.color = TRUE, show.sign = FALSE, - ...) { - # - if( !.is_a_bool(absolute.scale) ){ - stop("'absolute.scale' must be TRUE or FALSE.", call. = FALSE) - } - # - if( !.is_a_bool(show.color) ){ - stop("'show.color' must be TRUE or FALSE.", call. = FALSE) - } - # - if( !.is_a_bool(show.sign) ){ - stop("'show.sign' must be TRUE or FALSE.", call. = FALSE) - } - # +.plot_loadings <- function(df, layout, ...) { # Initialize a plot plot_out <- ggplot(df) - # Either create a heatmap or barplt + # Either create a heatmap or barplot/lollipop if( layout == "heatmap" ){ plot_out <- plot_out + # Create a heatmap @@ -310,64 +306,106 @@ setMethod("plotLoadings", signature = c(x = "matrix"), low = "darkslateblue", mid = "white", high = "darkred" ) - } else if( layout == "barplot" && !absolute.scale ){ - # This creates a barplot where values can be negative or positive - # (bars can be in negative and positive side) + } else if( layout %in% c("barplot", "lollipop") ){ + plot_out <- .plot_bar_or_lollipop(plot_out, df, layout, ...) + } + # Adjust theme + plot_out <- plot_out + + theme_minimal() + return(plot_out) +} + + +# This functions creates a barplot or lollipop plot. +.plot_bar_or_lollipop <- function( + plot_out, df, layout, absolute.scale = TRUE, show.color = TRUE, + show.sign = FALSE, ...){ + # + if( !.is_a_bool(absolute.scale) ){ + stop("'absolute.scale' must be TRUE or FALSE.", call. = FALSE) + } + # + if( !.is_a_bool(show.color) ){ + stop("'show.color' must be TRUE or FALSE.", call. = FALSE) + } + # + if( !.is_a_bool(show.sign) ){ + stop("'show.sign' must be TRUE or FALSE.", call. = FALSE) + } + # + # Set the variables to use for aesthetics + value_var <- if (absolute.scale) "Value_abs" else "Value" + # Set the y aesthetics with reorder_within, making sure 'df' is referenced + y_aes <- reorder_within( + df$Feature, + # Either get values in absolute scale or not + if(absolute.scale) -df$Value_abs else df$Value, + df$PC + ) + + # Plot barplot or lollipop + if (layout == "barplot") { + # This creates a barplot + aesthetic <- aes( + x = !!sym(value_var), + y = y_aes, + # User can decide whether the bars are colored based on +/- + fill = if(show.color) Sign else NULL + ) + plot_out <- plot_out + geom_bar(mapping = aesthetic, stat = "identity") + } else if (layout == "lollipop") { + # This creates a lollipop plot plot_out <- plot_out + - # Create a bar plot. Create unique facets for each PC. Each PC can - # have unique set of features. To reorder features by each facet, - # we use reorder_within() and scale_y_reordered(). - geom_bar( - mapping = aes( - x = Value, y = reorder_within(Feature, Value, PC)), - stat = "identity" - ) + - scale_y_reordered() + - facet_wrap(~ PC, scales = "free") + - labs(x = "Value", y = "Feature") - - } else if( layout == "barplot" && absolute.scale ){ - # This creates a barplot where bars are in absolute scale and the sing - # is denoted with +/- sign or color - - # Create an aesthetic based on whether to show sign with colors - if( show.color ){ - aesthetic <- aes( - x = Value_abs, - y = reorder_within(Feature, -Value_abs, PC), - fill = Sign - ) - } else{ - aesthetic <- aes( - x = Value_abs, y = reorder_within(Feature, -Value_abs, PC)) - } - # Create bars with absolute scale + # Add line + geom_segment(mapping = aes( + x = 0, xend = !!sym(value_var), + y = y_aes, yend = y_aes + )) + + # Add point at the end of the line to create "lollipop" + geom_point(mapping = aes( + x = !!sym(value_var), + y = y_aes, + # User can choose whether the point is colored based on sign + color = if (show.color) Sign else NULL + )) + } + + # Add sign labels if needed + if( show.sign ){ + plot_out <- plot_out + geom_text(aes( + # This determines where the sign is placed, absolute scale or not + x = if (absolute.scale) max_scale_abs else max_scale, + y = y_aes, + label = Sign, + fontface = "bold" + )) + } + + # Customize the legend for Sign as "Effect" + if( show.color ) { + # Get correct function, barplot uses fill, lollipop color + scale_FUN <- if( layout == "barplot" ) scale_fill_manual else + scale_color_manual + # Currently the legend has title that shows the function call and the + # values shows + or -. Make the legend nicer. plot_out <- plot_out + - - geom_bar(mapping = aesthetic, stat = "identity" + scale_FUN( + name = "Effect", + values = c("+" = "blue", "-" = "red"), + labels = c("+" = "positive", "-" = "negative") ) - # Add sign that tells whether the value is + or - - if( show.sign ){ - plot_out <- plot_out + - geom_text(aes( - x = max(Value_abs) + max(Value_abs)*0.1, - y = reorder_within(Feature, -Value_abs, PC), - label = Sign, - fontface = "bold" - )) - } - # Final wrangle, set facets and order the data - plot_out <- plot_out + - scale_y_reordered() + - facet_wrap(~ PC, scales = "free") + - labs(x = "Value", y = "Feature") } - # Adjust theme + + # Final wrangle, set facets and order the data plot_out <- plot_out + - theme_minimal() + scale_y_reordered() + + facet_wrap(~PC, scales = "free") + + labs(x = "Value", y = "Feature") + return(plot_out) } + # This function retrieves the data for tree + heatmap plotting. The output # is a list that includes tree and data.frame in wide format. #' @importFrom ggtree ggtree From a6908eda19a640dace979de4031ad426863e4813 Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Mon, 7 Oct 2024 14:00:54 +0300 Subject: [PATCH 4/8] up --- R/plotLoadings.R | 8 ++--- man/plotLoadings.Rd | 9 +++--- tests/testthat/test-plotLoadings.R | 48 ++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/R/plotLoadings.R b/R/plotLoadings.R index 67eca56..934a61b 100644 --- a/R/plotLoadings.R +++ b/R/plotLoadings.R @@ -30,9 +30,9 @@ #' \item \code{n}: \code{Integer scalar}. Number of features to be plotted. #' Applicable when \code{layout="barplot"}. (Default: \code{10})) #' -#' \item \code{absolute.scale}: ("barplot") \code{Logical scalar}. Specifies -#' whether a barplot should be visualized in absoltue scale. -#' (Default: \code{TRUE}) +#' \item \code{absolute.scale}: ("barplot", "lollipop") \code{Logical scalar}. +#' Specifies whether a barplot or a lollipop plot should be visualized in +#' absolute scale. (Default: \code{TRUE}) #' } #' #' @details @@ -315,7 +315,6 @@ setMethod("plotLoadings", signature = c(x = "matrix"), return(plot_out) } - # This functions creates a barplot or lollipop plot. .plot_bar_or_lollipop <- function( plot_out, df, layout, absolute.scale = TRUE, show.color = TRUE, @@ -405,7 +404,6 @@ setMethod("plotLoadings", signature = c(x = "matrix"), return(plot_out) } - # This function retrieves the data for tree + heatmap plotting. The output # is a list that includes tree and data.frame in wide format. #' @importFrom ggtree ggtree diff --git a/man/plotLoadings.Rd b/man/plotLoadings.Rd index f8f31a0..1250e42 100644 --- a/man/plotLoadings.Rd +++ b/man/plotLoadings.Rd @@ -35,16 +35,17 @@ x.} \item \code{n}: \code{Integer scalar}. Number of features to be plotted. Applicable when \code{layout="barplot"}. (Default: \code{10})) -\item \code{absolute.scale}: ("barplot") \code{Logical scalar}. Specifies -whether a barplot should be visualized in absoltue scale. -(Default: \code{TRUE}) +\item \code{absolute.scale}: ("barplot", "lollipop") \code{Logical scalar}. +Specifies whether a barplot or a lollipop plot should be visualized in +absolute scale. (Default: \code{TRUE}) }} \item{dimred}{\code{Character scalar}. Determines the reduced dimension to plot.} \item{layout}{\code{Character scalar}. Determines the layout of plot. Must be -either \code{"barplot"} or \code{"heatmap"}. (Default: \code{"barplot"})} +either \code{"barplot"}, \code{"heatmap"}, or \code{"lollipop"}. +(Default: \code{"barplot"})} \item{ncomponents}{\code{Numeric scalar}. Number of components must be lower or equal to the number of components chosen in the reduction method. diff --git a/tests/testthat/test-plotLoadings.R b/tests/testthat/test-plotLoadings.R index 246c597..3d7d573 100644 --- a/tests/testthat/test-plotLoadings.R +++ b/tests/testthat/test-plotLoadings.R @@ -33,4 +33,52 @@ test_that("plot Loadings", { expect_s3_class(p, "ggplot") p <- plotLoadings(tse, dimred = "PCA", layout = "heatmap", add.tree = TRUE) expect_s3_class(p, "ggplot") + + # Create a mock dataset + df <- data.frame( + Feature = rep(c("Feature1", "Feature2", "Feature3"), times = 2), + Value = c(2, 4, -1, -3, 5, 7), + Value_abs = abs(c(2, 4, -1, -3, 5, 7)), + Sign = c("+", "+", "-", "-", "+", "+"), + PC = rep(c("PC1", "PC2"), each = 3) + ) + + # Create an empty ggplot object for plot_out + plot_out <- ggplot(df) + ### 1). TEST: barplot with absolute scale and color + plot <- .plot_bar_or_lollipop(plot_out, df, layout = "barplot", absolute.scale = TRUE, show.color = TRUE) + expect_s3_class(plot, "ggplot") + ### 2). TEST: barplot without absolute scale but with color + plot <- .plot_bar_or_lollipop(plot_out, df, layout = "barplot", absolute.scale = FALSE, show.color = TRUE) + expect_s3_class(plot, "ggplot") + ### 3). TEST: barplot with absolute scale but no color + plot <- .plot_bar_or_lollipop(plot_out, df, layout = "barplot", absolute.scale = TRUE, show.color = FALSE) + expect_s3_class(plot, "ggplot") + ### 4). TEST: lollipop plot with absolute scale and color + plot <- .plot_bar_or_lollipop(plot_out, df, layout = "lollipop", absolute.scale = TRUE, show.color = TRUE) + expect_s3_class(plot, "ggplot") + ### 5). TEST: lollipop plot without absolute scale but with color + plot <- .plot_bar_or_lollipop(plot_out, df, layout = "lollipop", absolute.scale = FALSE, show.color = TRUE) + expect_s3_class(plot, "ggplot") + ### 6). TEST: lollipop plot with absolute scale but no color + plot <- .plot_bar_or_lollipop(plot_out, df, layout = "lollipop", absolute.scale = TRUE, show.color = FALSE) + expect_s3_class(plot, "ggplot") + ### 7). TEST: error when `absolute.scale` is not a boolean + expect_error( + .plot_bar_or_lollipop(plot_out, df, layout = "barplot", absolute.scale = "not boolean", show.color = TRUE), + "'absolute.scale' must be TRUE or FALSE." + ) + ### 8). TEST: error when `show.color` is not a boolean + expect_error( + .plot_bar_or_lollipop(plot_out, df, layout = "barplot", absolute.scale = TRUE, show.color = "not boolean"), + "'show.color' must be TRUE or FALSE." + ) + ### 9). TEST: correct labels in the legend + plot <- .plot_bar_or_lollipop(plot_out, df, layout = "barplot", absolute.scale = TRUE, show.color = TRUE) + expect_true("Effect" %in% ggplot_build(plot)$plot$scales$scales[[1]]$name) + expect_equal(ggplot_build(plot)$plot$scales$scales[[1]]$labels, c("+" = "positive", "-" = "negative")) + ### 10). TEST: adding sign labels + plot <- .plot_bar_or_lollipop(plot_out, df, layout = "barplot", absolute.scale = TRUE, show.color = TRUE, show.sign = TRUE) + expect_s3_class(plot, "ggplot") }) + From b9e6988599530396a879642245e0acfcf74f4629 Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Mon, 7 Oct 2024 14:16:10 +0300 Subject: [PATCH 5/8] up --- R/plotLoadings.R | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/R/plotLoadings.R b/R/plotLoadings.R index 934a61b..f2be530 100644 --- a/R/plotLoadings.R +++ b/R/plotLoadings.R @@ -250,6 +250,11 @@ setMethod("plotLoadings", signature = c(x = "matrix"), } # Convert into data.frame res <- as.data.frame(res) + # Check that values are numeric. This is the first time we test that the + # columns were numeric. Now all the values from columns are in this column. + if( !is.numeric(res[["Value"]]) ){ + stop("Values must be numeric.", call. = FALSE) + } # Add column that shows the values in absolute scale, and another column # showing sign res[["Value_abs"]] <- abs(res[["Value"]]) From 1c8fdf6b6ba75101fd85ceff8d158693f85e11b4 Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Mon, 7 Oct 2024 15:47:03 +0300 Subject: [PATCH 6/8] up --- R/plotLoadings.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/plotLoadings.R b/R/plotLoadings.R index f2be530..c1ce0dc 100644 --- a/R/plotLoadings.R +++ b/R/plotLoadings.R @@ -292,8 +292,7 @@ setMethod("plotLoadings", signature = c(x = "matrix"), } # This functions plots a data.frame in barplot or heatmap layout. -#' @importFrom tidytext scale_y_reordered reorder_within -#' @importFrom ggplot2 geom_tile scale_fill_gradient2 geom_bar +#' @importFrom ggplot2 geom_tile scale_fill_gradient2 .plot_loadings <- function(df, layout, ...) { # Initialize a plot plot_out <- ggplot(df) @@ -321,6 +320,8 @@ setMethod("plotLoadings", signature = c(x = "matrix"), } # This functions creates a barplot or lollipop plot. +#' @importFrom tidytext scale_y_reordered reorder_within +#' @importFrom ggplot2 geom_bar geom_segment geom_point geom_text .plot_bar_or_lollipop <- function( plot_out, df, layout, absolute.scale = TRUE, show.color = TRUE, show.sign = FALSE, ...){ From b505b6c47bd83f86a8f7a2d5ff98a679148aec71 Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Mon, 7 Oct 2024 15:47:20 +0300 Subject: [PATCH 7/8] up --- NAMESPACE | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NAMESPACE b/NAMESPACE index a888c0e..f7b7376 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -93,6 +93,8 @@ importFrom(ggplot2,geom_bar) importFrom(ggplot2,geom_line) importFrom(ggplot2,geom_point) importFrom(ggplot2,geom_raster) +importFrom(ggplot2,geom_segment) +importFrom(ggplot2,geom_text) importFrom(ggplot2,geom_tile) importFrom(ggplot2,ggplot) importFrom(ggplot2,labs) From 9fe88066e47a4fd248caa735fe393f2141f2fd9d Mon Sep 17 00:00:00 2001 From: TuomasBorman Date: Mon, 7 Oct 2024 18:28:29 +0300 Subject: [PATCH 8/8] up --- NAMESPACE | 1 + R/plotLoadings.R | 51 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index f7b7376..a0536b4 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -69,6 +69,7 @@ importFrom(ape,rotateConstr) importFrom(dplyr,"%>%") importFrom(dplyr,all_of) importFrom(dplyr,bind_cols) +importFrom(dplyr,case_when) importFrom(dplyr,filter) importFrom(dplyr,group_by) importFrom(dplyr,last_col) diff --git a/R/plotLoadings.R b/R/plotLoadings.R index c1ce0dc..fa47607 100644 --- a/R/plotLoadings.R +++ b/R/plotLoadings.R @@ -255,20 +255,8 @@ setMethod("plotLoadings", signature = c(x = "matrix"), if( !is.numeric(res[["Value"]]) ){ stop("Values must be numeric.", call. = FALSE) } - # Add column that shows the values in absolute scale, and another column - # showing sign - res[["Value_abs"]] <- abs(res[["Value"]]) - res[["Sign"]] <- ifelse( - res[["Value"]] > 0, "+", ifelse(res[["Value"]] < 0, "-", "")) - # Add maximum values. This is used in scaling and placement of +/- sign - # in barplot and lollipop plot. - temp <- max(res[["Value_abs"]], na.rm = TRUE) - res[["max_scale_abs"]] <- temp + 0.1*temp - res[["max_scale"]] <- NA - temp <- min(res[["Value"]], na.rm = TRUE) - res[res[["Value"]]<0, "max_scale"] <- temp + 0.1*temp - temp <- max(res[["Value"]], na.rm = TRUE) - res[res[["Value"]]>0, "max_scale"] <- temp + 0.1*temp + # Calculate max and min values along with maximum absolute value and sign + res <- .calculate_max_and_min_for_loadings(res) return(res) } @@ -291,6 +279,37 @@ setMethod("plotLoadings", signature = c(x = "matrix"), return(df) } +# This function calculates place for +/- sign in barplot/lollipop plot +#' @importFrom dplyr %>% group_by mutate case_when ungroup +.calculate_max_and_min_for_loadings <- function(df){ + # Add column that shows the values in absolute scale, and another column + # showing sign + df[["Value_abs"]] <- abs(df[["Value"]]) + df[["Sign"]] <- ifelse( + df[["Value"]] > 0, "+", ifelse(df[["Value"]] < 0, "-", "")) + # Add maximum values. This is used in scaling and placement of +/- sign + # in barplot and lollipop plot. In absolute scale, we use the maximum + # absolute value. In original scale, negative values gets minimum value + # and positive values maximum. These values are for each PC. + df <- df %>% + group_by(PC) %>% + mutate( + # Calculate max of abs(Value) and add 10% + max_scale_abs = max(abs(Value), na.rm = TRUE) + + 0.1 * max(abs(Value), na.rm = TRUE), + # Calculate max_scale based on the sign of the Value + max_scale = case_when( + Value < 0 ~ min(Value, na.rm = TRUE) + + 0.1 * min(Value, na.rm = TRUE), + Value > 0 ~ max(Value, na.rm = TRUE) + + 0.1 * max(Value, na.rm = TRUE), + TRUE ~ NA_real_ + ) + ) %>% + ungroup() + return(df) +} + # This functions plots a data.frame in barplot or heatmap layout. #' @importFrom ggplot2 geom_tile scale_fill_gradient2 .plot_loadings <- function(df, layout, ...) { @@ -306,8 +325,8 @@ setMethod("plotLoadings", signature = c(x = "matrix"), ) + # Adjust color scale scale_fill_gradient2( - limits = c(-1, 1), - low = "darkslateblue", mid = "white", high = "darkred" + limits = c(-max(abs(df$Value)), max(abs(df$Value))), + low = "darkblue", mid = "white", high = "darkred" ) } else if( layout %in% c("barplot", "lollipop") ){