diff --git a/DESCRIPTION b/DESCRIPTION index f4280d4ef..1ec15635c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,5 +1,5 @@ Package: AMR -Version: 3.1.0.9019 +Version: 3.1.0.9020 Date: 2026-11-09 Title: Antimicrobial Resistance Data Analysis Description: Functions to simplify and standardise antimicrobial resistance (AMR) diff --git a/NEWS.md b/NEWS.md index 384d878e6..4f2728e22 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# AMR 3.1.0.9019 +# AMR 3.1.0.9020 This version fixes a critical bug in WISCA that biased all coverage estimates of `wisca()` and `antibiogram(..., wisca = TRUE)` downwards since AMR 3.0.0. Users are strongly advised to re-run their WISCA analyses. @@ -44,6 +44,8 @@ It also adds a `site` argument to `as.sir()`, stores EUCAST MIC breakpoints exac * Fixed punctuation being italicised along with taxonomic names, e.g., `"(S. aureus)"` now gives `"(*S. aureus*)"` instead of `"(S. *aureus)*"` * `NA` values now return `NA` instead of `"NA"` * Taxonomic names are now looked up once per session, making the function considerably faster for long vectors +* `labels_sir_count()` and `ggplot_sir()` + * Fixed the data labels being placed on the wrong bars with `position = "dodge"` or `position = "stack"`. They are now grouped like the bars, using the new `fill` argument of `labels_sir_count()`, which `ggplot_sir()` sets automatically * `ggplot_pca()` * Fixed an error when setting `groups` together with `labels`, and setting `groups` without `labels` now colours the points by these groups instead of using them as labels, as documented * *Morganella* is interpreted as reported, with the breakpoints of Enterobacterales or Morganellaceae and not of *M. morganii*, which is now tested (#330) diff --git a/R/ggplot_sir.R b/R/ggplot_sir.R index 153af875f..7452bf9bf 100755 --- a/R/ggplot_sir.R +++ b/R/ggplot_sir.R @@ -33,7 +33,7 @@ #' @param data A [data.frame] with column(s) of class [`sir`] (see [as.sir()]). #' @param position Position adjustment of bars, either `"fill"`, `"stack"` or `"dodge"`. #' @param x Variable to show on x axis, either `"antibiotic"` (default) or `"interpretation"` or a grouping variable. -#' @param fill Variable to categorise using the plots legend, either `"antibiotic"` (default) or `"interpretation"` or a grouping variable. +#' @param fill Variable to categorise using the plots legend, either `"interpretation"` (default) or `"antibiotic"` or a grouping variable. For [labels_sir_count()], this must be the same as the `fill` of [geom_sir()], so that the labels are placed on the right bars. #' @param breaks A [numeric] vector of positions. #' @param limits A [numeric] vector of length two providing limits of the scale, use `NA` to refer to the existing minimum or maximum. #' @param facet Variable to split plots by, either `"interpretation"` (default) or `"antibiotic"` or a grouping variable. @@ -261,6 +261,7 @@ ggplot_sir <- function(data, p <- p + labels_sir_count( position = position, x = x, + fill = fill, translate_ab = translate_ab, minimum = minimum, language = language, diff --git a/R/plotting.R b/R/plotting.R index a8fec12bf..3e0387928 100755 --- a/R/plotting.R +++ b/R/plotting.R @@ -1454,6 +1454,7 @@ labeller_taxonomy <- structure( #' @export labels_sir_count <- function(position = NULL, x = "antibiotic", + fill = "interpretation", translate_ab = "name", minimum = 30, language = get_AMR_locale(), @@ -1464,6 +1465,7 @@ labels_sir_count <- function(position = NULL, stop_ifnot_installed("ggplot2") meet_criteria(position, allow_class = "character", has_length = 1, is_in = c("fill", "stack", "dodge"), allow_NULL = TRUE) meet_criteria(x, allow_class = "character", has_length = 1) + meet_criteria(fill, allow_class = "character", has_length = 1) meet_criteria(translate_ab, allow_class = c("character", "logical"), has_length = 1, allow_NA = TRUE) meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_positive_or_zero = TRUE, is_finite = TRUE) language <- validate_language(language) @@ -1474,18 +1476,29 @@ labels_sir_count <- function(position = NULL, if (is.null(position)) { position <- "fill" } + # labels are grouped like the bars of geom_sir(), so that they are placed on the right bar + vjust <- 0.5 if (identical(position, "fill")) { + # centred in the bar segments position <- ggplot2::position_fill(vjust = 0.5, reverse = TRUE) + } else if (identical(position, "stack")) { + # centred in the bar segments + position <- ggplot2::position_stack(vjust = 0.5) + } else if (identical(position, "dodge")) { + # on top of the bars, with the default width of geom_col() + position <- ggplot2::position_dodge(width = 0.9) + vjust <- -0.5 } x_name <- x ggplot2::geom_text( - mapping = utils::modifyList(ggplot2::aes(), list(label = str2lang("lbl"), x = str2lang(x), y = str2lang("value"))), + mapping = utils::modifyList(ggplot2::aes(), list(label = str2lang("lbl"), x = str2lang(x), y = str2lang("value"), group = str2lang(fill))), position = position, inherit.aes = FALSE, size = datalabels.size, colour = datalabels.colour, lineheight = 0.75, + vjust = vjust, data = function(x) { transformed <- sir_df( data = x, diff --git a/man/ggplot_sir.Rd b/man/ggplot_sir.Rd index 214ca277c..cefb35c4c 100644 --- a/man/ggplot_sir.Rd +++ b/man/ggplot_sir.Rd @@ -48,6 +48,7 @@ geom_sir( labels_sir_count( position = NULL, x = "antibiotic", + fill = "interpretation", translate_ab = "name", minimum = 30, language = get_AMR_locale(), @@ -64,7 +65,7 @@ labels_sir_count( \item{x}{Variable to show on x axis, either \code{"antibiotic"} (default) or \code{"interpretation"} or a grouping variable.} -\item{fill}{Variable to categorise using the plots legend, either \code{"antibiotic"} (default) or \code{"interpretation"} or a grouping variable.} +\item{fill}{Variable to categorise using the plots legend, either \code{"interpretation"} (default) or \code{"antibiotic"} or a grouping variable. For \code{\link[=labels_sir_count]{labels_sir_count()}}, this must be the same as the \code{fill} of \code{\link[=geom_sir]{geom_sir()}}, so that the labels are placed on the right bars.} \item{facet}{Variable to split plots by, either \code{"interpretation"} (default) or \code{"antibiotic"} or a grouping variable.} diff --git a/tests/testthat/test-ggplot_sir.R b/tests/testthat/test-ggplot_sir.R index 387ef841a..32d34b740 100644 --- a/tests/testthat/test-ggplot_sir.R +++ b/tests/testthat/test-ggplot_sir.R @@ -160,5 +160,20 @@ test_that("test-ggplot_sir.R", { scale_sir_colours(aesthetics = "fill", Value4 = "S", Value5 = "I", Value6 = "R"))$data), "data.frame" ) + + # datalabels are placed on their own bar, also when dodged or stacked + for (pos in c("fill", "stack", "dodge")) { + built <- ggplot_build(ggplot_sir(example_isolates[, c("AMX", "CIP")], position = pos, guideline = NULL)) + bars <- built$data[[1]] + labels <- built$data[[2]] + bars <- bars[order(bars$x, bars$group), , drop = FALSE] + labels <- labels[order(labels$x, labels$group), , drop = FALSE] + expect_equal(labels$x, bars$x) + if (pos == "dodge") { + expect_equal(labels$y, bars$ymax) + } else { + expect_equal(labels$y, (bars$ymin + bars$ymax) / 2) + } + } } })