Skip to content
Merged

Dev #106

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: ggExpress
Title: ggExpress is the fastest way to create, annotate and export plots
in R
Version: 1.0.0
Version: 1.0.1
Authors@R:
person("Abel", "Vertesy", , "av@imba.oeaw.ac.at", role = c("aut", "cre"))
Description: ggExpress is a set of R functions that allows you to generate
Expand Down
2 changes: 1 addition & 1 deletion Development/config.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

DESCRIPTION <- list(
package.name = "ggExpress",
version = "1.0.0",
version = "1.0.1",
title = "ggExpress is the fastest way to create, annotate and export plots in R",
description = "ggExpress is a set of R functions that allows you to generate precise figures easily,
and create clean markdown reports about what you just discovered with your analysis script. It is ggplot-based smaller brother of vertesy/MarkdownReports. It helps you to:
Expand Down
123 changes: 103 additions & 20 deletions R/ggExpress.R
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,12 @@ qbarplot.df <- function(
#' @param label Point labels. Default: NULL.
#' @param repel Repel labels from each other. Default: TRUE.
#' @param legend.position Character indicating the position of the legend. Default is is 'none' to hide the legend.
#' @param col Color of the plot.
#' @param col Color of the points, passed directly to `ggpubr::ggscatter(color = )`.
#' Either a literal color (`"red"`, `"#FF0000"`), or the name of a *discrete* column to
#' color by, or a number. Note that a number here is a base R color code (the default `3`
#' is green), NOT an index into `palette_use` as in `qbarplot()` and `qhistogram()`.
#' Coloring by a numeric column fails, because `palette_use` is a discrete scale.
#' Default: 3.
#' @param palette_use Color palette to use. Either a `ggpubr::get_palette` palette or a custom vector of colors. Default: 'jco'.
#'
#' @param xlab X-axis label. Default: NULL.
Expand Down Expand Up @@ -1343,7 +1348,11 @@ qscatter <- function(
save.obj = getOption("gg.save.obj", FALSE),
label = NULL, repel = TRUE,
legend.position = "none",
col = c(NULL, 3)[1],
## NOTE: `col` is passed straight to ggpubr::ggscatter(color = ), so a number here is a
## base R colour code (3 = green), NOT a palette_use index as in qbarplot/qhistogram.
## Previously written as c(NULL, 3)[1], which always evaluates to 3 because c() drops
## NULL - it only looked as though NULL were a selectable alternative.
col = 3,
# fill = NULL,
palette_use = getOption("gg.palette_use", "jco"),
xlab = NULL, ylab = NULL,
Expand Down Expand Up @@ -1473,7 +1482,11 @@ qscatter <- function(
#' @param df_XYcol_or_list Data as a two-column data frame, where column 1 is the X axis, alternatively a uniquely named list of values.
#' @param x The index or name of the column to be plotted on the X axis. Default: `1`.
#' @param y The index or name of the column to be plotted on the Y axis. Default: `2`.
#' @param col The index or name of the column to be used for coloring the plot. Default: `NULL`.
#' @param col How to color the plot. Either (1) the *name* of a column to color (group) by,
#' colored through `palette_use`; (2) a single palette index - a positive whole number, or a
#' digit-only string such as `"2"` - looked up in `palette_use`; or (3) a literal color such
#' as `"red"` or `"#FF0000"`. A number is always a *palette* index, never a column index,
#' consistent with `qbarplot()` and `qhistogram()`. Default: `NULL`, which uses `fill`.
#' @param fill Fill color of the plot. Default: `gold`.
#'
#' @param plotname The title of the plot and the name of the file (unless specified in `filename`).
Expand Down Expand Up @@ -1608,9 +1621,10 @@ qboxplot <- function(


if (!is.null(col)) {
if (is.numeric(col) & col < length(vars)) col <- col
if (col %in% vars) col <- vars[col]
fill <- col # if col (color as a column name) is provided, fill is set to col
# `col` is either a column name to colour by, a palette index, or a literal colour.
# Resolve against palette_use_bac: by this point palette_use has been overwritten
# with the recycled `fill` colour above, and is no longer the requested palette.
fill <- .resolveColToFill(col, vars, palette_use_bac)
palette_use <- palette_use_bac
}

Expand Down Expand Up @@ -1666,7 +1680,11 @@ qboxplot <- function(
#' @param df_XYcol_or_list Data as a two-column data frame, where column 1 is the X axis, alternatively a uniquely named list of values.
#' @param x The index or name of the column to be plotted on the X axis. Default: `1`.
#' @param y The index or name of the column to be plotted on the Y axis. Default: `2`.
#' @param col The index or name of the column to be used for coloring the plot. Default: `NULL`.
#' @param col How to color the plot. Either (1) the *name* of a column to color (group) by,
#' colored through `palette_use`; (2) a single palette index - a positive whole number, or a
#' digit-only string such as `"2"` - looked up in `palette_use`; or (3) a literal color such
#' as `"red"` or `"#FF0000"`. A number is always a *palette* index, never a column index,
#' consistent with `qbarplot()` and `qhistogram()`. Default: `NULL`, which uses `fill`.
#' @param fill Fill color of the plot. Default: `gold`.
#' @param plotname Name of the plot
#' @param subtitle Optional subtitle text added below the title. Default is NULL.
Expand Down Expand Up @@ -1748,9 +1766,8 @@ qviolin <- function(
is.numeric(df_XYcol[[vars[y]]])
)
if (!is.null(col)) {
if (is.numeric(col) & col < length(vars)) col <- col
if (col %in% vars) col <- vars[col]
fill <- col # if col (color as a column name) is provided, fill is set to col
# `col` is either a column name to colour by, a palette index, or a literal colour.
fill <- .resolveColToFill(col, vars, palette_use)
}

pobj <- ggpubr::ggviolin(
Expand Down Expand Up @@ -1798,7 +1815,11 @@ qviolin <- function(
#' @param df_XYcol_or_list Data as a two-column data frame, where column 1 is the X axis, alternatively a uniquely named list of values.
#' @param x The index or name of the column to be plotted on the X axis. Default: `1`.
#' @param y The index or name of the column to be plotted on the Y axis. Default: `2`.
#' @param col The index or name of the column to be used for coloring the plot. Default: `NULL`.
#' @param col How to color the plot. Either (1) the *name* of a column to color (group) by,
#' colored through `palette_use`; (2) a single palette index - a positive whole number, or a
#' digit-only string such as `"2"` - looked up in `palette_use`; or (3) a literal color such
#' as `"red"` or `"#FF0000"`. A number is always a *palette* index, never a column index,
#' consistent with `qbarplot()` and `qhistogram()`. Default: `NULL`, which uses `fill`.
#' @param fill Fill color of the plot. Default: `gold`.
#'
#' @param plotname Name of the plot
Expand Down Expand Up @@ -1906,9 +1927,8 @@ qstripchart <- function(
)

if (!is.null(col)) {
if (is.numeric(col) & col < length(vars)) col <- col
if (col %in% vars) col <- vars[col]
fill <- col # if col (color as a column name) is provided, fill is set to col
# `col` is either a column name to colour by, a palette index, or a literal colour.
fill <- .resolveColToFill(col, vars, palette_use)
}

pobj <- ggpubr::ggstripchart(
Expand Down Expand Up @@ -2464,8 +2484,8 @@ qmosaic <- function(
#' @param nrow number of rows for panels on the page. Default: 2
#' @param ncol number of columns for panels on the page. Default: 2
#' @param scale Scaling factor of the canvas. Default: 1
#' @param h Height of the plot. Default: wA4 * scale
#' @param w Width of the plot. Default: hA4 * scale
#' @param h Height of the plot, in inches. Default: get0("hA4", ifnotfound = 11.69) * scale
#' @param w Width of the plot, in inches. Default: get0("wA4", ifnotfound = 8.27) * scale
#' @param ... Pass any other parameter to the internally called functions (most of them should work).
#' @param extension file extension
#' @importFrom cowplot plot_grid save_plot
Expand All @@ -2479,7 +2499,7 @@ q32vA4_grid_plot <- function(
plot = FALSE,
nrow = 3, ncol = 2, extension = c("pdf", "png")[2],
scale = 1,
h = hA4 * scale, w = wA4 * scale,
h = get0("hA4", ifnotfound = 11.69) * scale, w = get0("wA4", ifnotfound = 8.27) * scale,
...
) { # Save 4 umaps on an A4 page.
print("Plot panels on 3-by-2 vertical A4 page.")
Expand Down Expand Up @@ -2508,8 +2528,8 @@ q32vA4_grid_plot <- function(
#' @param max.list.length Max number of panels (per page). Default: 16
#' @param extension file extension
#' @param scale Scaling factor of the canvas. Default: 1
#' @param h Height of the plot. Default: wA4 * scale
#' @param w Width of the plot. Default: hA4 * scale
#' @param h Height of the plot, in inches. Default: get0("hA4", ifnotfound = 11.69) * scale
#' @param w Width of the plot, in inches. Default: get0("wA4", ifnotfound = 8.27) * scale
#' @param ... Pass any other parameter to the internally called functions (most of them should work).
#'
#' @importFrom cowplot plot_grid save_plot
Expand All @@ -2526,7 +2546,7 @@ qA4_grid_plot <- function(
max.list.length = 16,
extension = c("pdf", "png")[2],
scale = 1,
h = hA4 * scale, w = wA4 * scale,
h = get0("hA4", ifnotfound = 11.69) * scale, w = get0("wA4", ifnotfound = 8.27) * scale,
...
) { # Save 4 umaps on an A4 page.
stopifnot(length(plot_list) < max.list.length)
Expand Down Expand Up @@ -2714,6 +2734,69 @@ qqqAnnotateTopLabels <- function(df, x, y, labels = NULL, fun = mean, digits = 2
}


# _________________________________________________________________________________________________
#' @title Resolve the col argument to a ggpubr fill value
#'
#' @description Shared `col` resolution for the data frame / list based plotting functions
#' (`qboxplot`, `qviolin`, `qstripchart`). `col` may be:
#' (1) the name of a column to color (group) by, which is returned unchanged so ggpubr maps
#' it through `palette_use`;
#' (2) a single palette index - a positive whole number, or a digit-only string such as
#' `"2"` - which is looked up in `palette_use` and returned as a literal color;
#' (3) any other value, returned unchanged and used by ggpubr as a literal color.
#' A numeric `col` is always a *palette* index, never a column index, which keeps these
#' functions consistent with `qbarplot()` and `qhistogram()`.
#' A named palette (e.g. `"jco"`) is regenerated to cover any requested index; a custom
#' color vector cannot be extended, so an out-of-range index throws an informative error
#' instead of silently resolving to `NA`.
#'
#' @param col The `col` argument as supplied by the caller. Must not be NULL.
#' @param vars Column names of the data frame being plotted.
#' @param palette_use The palette in use, passed through from the caller.
#' @return A single string: either a column name for ggpubr to map, or a literal color.
#'
#' @examples
#' ggExpress:::.resolveColToFill("dose", c("dose", "len"), "jco") # -> "dose"
#' ggExpress:::.resolveColToFill(2, c("dose", "len"), "jco") # -> 2nd palette color
#' ggExpress:::.resolveColToFill("red", c("dose", "len"), "jco") # -> "red"
.resolveColToFill <- function(col, vars, palette_use) {
stopifnot(
"`col` must not be NULL." = !is.null(col),
"`vars` must be a character vector." = is.character(vars),
"`palette_use` must not be NULL." = !is.null(palette_use)
)

# (1) A column name colors by that column; ggpubr maps it through the palette.
if (is.character(col) && length(col) == 1L && col %in% vars) return(col)

# (2) A single positive whole number (or digit-only string) is a palette index.
col_i <- suppressWarnings(as.integer(col))
col.is.index <- length(col) == 1L &&
!is.na(col_i) && col_i >= 1L &&
(
(is.numeric(col) && col == col_i) || # whole-number numeric
(is.character(col) && grepl("^[0-9]+$", col)) # digit-only string
)

if (isTRUE(col.is.index)) {
if (length(palette_use) == 1) {
# Named palette (e.g. "jco"): regenerate it to cover the requested index.
pal <- ggpubr::get_palette(palette_use, max(2L, col_i))
} else {
# Custom color vector: it cannot be extended, so the index must fall within it.
stopifnot(
"`col` index exceeds the number of colors in the custom `palette_use`." = col_i <= length(palette_use)
)
pal <- palette_use
}
return(pal[col_i])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate custom palette indexes before returning a color

Problem: .resolveColToFill() returns NA when col exceeds the length of a custom palette_use, so the plot can lose its fill or fail inside ggpubr. Trigger: This happens with calls such as qviolin(data, col = 3, palette_use = c("red", "blue")), even though the documentation accepts any positive palette index. Fix: Add the required compact input assertion and either reject out-of-range indexes or define how custom palettes should be extended.

AGENTS.md reference: AGENTS.md:L13-L13

Useful? React with 👍 / 👎.

}

# (3) Anything else is used as a literal color.
col
}


# _________________________________________________________________________________________________

#' @title Summarize Mean and Median per Group
Expand Down
37 changes: 37 additions & 0 deletions man/dot-resolveColToFill.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions man/q32vA4_grid_plot.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions man/qA4_grid_plot.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion man/qboxplot.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions man/qscatter.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion man/qstripchart.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion man/qviolin.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.