AMR/R/plot.R

817 lines
29 KiB
R
Raw Normal View History

# ==================================================================== #
# TITLE #
2022-10-05 09:12:22 +02:00
# AMR: An R Package for Working with Antimicrobial Resistance Data #
# #
# SOURCE #
# https://github.com/msberends/AMR #
# #
2022-10-05 09:12:22 +02:00
# CITE AS #
# Berends MS, Luz CF, Friedrich AW, Sinha BNM, Albers CJ, Glasner C #
# (2022). AMR: An R Package for Working with Antimicrobial Resistance #
# Data. Journal of Statistical Software, 104(3), 1-31. #
# doi:10.18637/jss.v104.i03 #
# #
2022-12-27 15:16:15 +01:00
# Developed at the University of Groningen and the University Medical #
# Center Groningen in The Netherlands, in collaboration with many #
# colleagues from around the world, see our website. #
# #
# This R package is free software; you can freely use and distribute #
# it for both personal and commercial purposes under the terms of the #
# GNU General Public License version 2.0 (GNU GPL-2), as published by #
# the Free Software Foundation. #
# We created this package for both routine data analysis and academic #
# research and it was publicly released in the hope that it will be #
# useful, but it comes WITHOUT ANY WARRANTY OR LIABILITY. #
# #
# Visit our website for the full manual and a complete tutorial about #
# how to conduct AMR data analysis: https://msberends.github.io/AMR/ #
# ==================================================================== #
2023-01-21 23:47:20 +01:00
#' Plotting for Classes `sir`, `mic` and `disk`
2022-08-28 10:31:50 +02:00
#'
2023-01-21 23:47:20 +01:00
#' Functions to plot classes `sir`, `mic` and `disk`, with support for base \R and `ggplot2`.
2022-08-21 16:37:20 +02:00
2023-01-21 23:47:20 +01:00
#' @param x,object values created with [as.mic()], [as.disk()] or [as.sir()] (or their `random_*` variants, such as [random_mic()])
#' @param mo any (vector of) text that can be coerced to a valid microorganism code with [as.mo()]
2022-11-13 13:44:25 +01:00
#' @param ab any (vector of) text that can be coerced to a valid antimicrobial drug code with [as.ab()]
#' @param guideline interpretation guideline to use, defaults to the latest included EUCAST guideline, see *Details*
2021-07-12 20:24:49 +02:00
#' @param main,title title of the plot
#' @param xlab,ylab axis title
2023-01-21 23:47:20 +01:00
#' @param colours_SIR colours to use for filling in the bars, must be a vector of three values (in the order S, I and R). The default colours are colour-blind friendly.
2023-01-23 20:07:57 +01:00
#' @param language language to be used to translate 'Susceptible', 'Increased exposure'/'Intermediate' and 'Resistant', defaults to system language (see [get_AMR_locale()]) and can be overwritten by setting the option [`AMR_locale`][AMR-options], e.g. `options(AMR_locale = "de")`, see [translate]. Use `language = NULL` or `language = ""` to prevent translation.
2021-05-12 18:15:03 +02:00
#' @param expand a [logical] to indicate whether the range on the x axis should be expanded between the lowest and highest value. For MIC values, intermediate values will be factors of 2 starting from the highest MIC value. For disk diameters, the whole diameter range will be filled.
#' @details
#' The interpretation of "I" will be named "Increased exposure" for all EUCAST guidelines since 2019, and will be named "Intermediate" in all other cases.
2022-08-28 10:31:50 +02:00
#'
2023-01-21 23:47:20 +01:00
#' For interpreting MIC values as well as disk diffusion diameters, supported guidelines to be used as input for the `guideline` argument are: `r vector_and(AMR::clinical_breakpoints$guideline, quotes = TRUE, reverse = TRUE)`.
2022-08-28 10:31:50 +02:00
#'
#' Simply using `"CLSI"` or `"EUCAST"` as input will automatically select the latest version of that guideline.
#' @name plot
#' @rdname plot
2021-07-12 20:24:49 +02:00
#' @return The `autoplot()` functions return a [`ggplot`][ggplot2::ggplot()] model that is extendible with any `ggplot2` function.
2022-08-28 10:31:50 +02:00
#'
2021-11-01 13:51:13 +01:00
#' The `fortify()` functions return a [data.frame] as an extension for usage in the [ggplot2::ggplot()] function.
#' @param ... arguments passed on to methods
2022-08-28 10:31:50 +02:00
#' @examples
#' some_mic_values <- random_mic(size = 100)
#' some_disk_values <- random_disk(size = 100, mo = "Escherichia coli", ab = "cipro")
2023-01-21 23:47:20 +01:00
#' some_sir_values <- random_sir(50, prob_SIR = c(0.55, 0.05, 0.30))
2022-08-28 10:31:50 +02:00
#'
#' plot(some_mic_values)
#' plot(some_disk_values)
2023-01-21 23:47:20 +01:00
#' plot(some_sir_values)
2022-08-28 10:31:50 +02:00
#'
#' # when providing the microorganism and antibiotic, colours will show interpretations:
#' plot(some_mic_values, mo = "S. aureus", ab = "ampicillin")
#' plot(some_disk_values, mo = "Escherichia coli", ab = "cipro")
2022-08-21 17:22:34 +02:00
#' plot(some_disk_values, mo = "Escherichia coli", ab = "cipro", language = "uk")
2022-08-28 10:31:50 +02:00
#'
2021-05-24 09:00:11 +02:00
#' \donttest{
#' if (require("ggplot2")) {
2021-07-12 20:24:49 +02:00
#' autoplot(some_mic_values)
2022-08-29 09:35:36 +02:00
#' }
#' if (require("ggplot2")) {
2021-07-12 20:24:49 +02:00
#' autoplot(some_disk_values, mo = "Escherichia coli", ab = "cipro")
2022-08-29 09:35:36 +02:00
#' }
#' if (require("ggplot2")) {
2023-01-21 23:47:20 +01:00
#' autoplot(some_sir_values)
#' }
2021-05-24 09:00:11 +02:00
#' }
NULL
#' @method plot mic
#' @importFrom graphics barplot axis mtext legend
#' @export
#' @rdname plot
plot.mic <- function(x,
mo = NULL,
ab = NULL,
guideline = "EUCAST",
main = deparse(substitute(x)),
2021-07-12 20:24:49 +02:00
ylab = "Frequency",
xlab = "Minimum Inhibitory Concentration (mg/L)",
2023-01-21 23:47:20 +01:00
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
language = get_AMR_locale(),
expand = TRUE,
...) {
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = TRUE)
meet_criteria(ab, allow_class = c("ab", "character"), allow_NULL = TRUE)
meet_criteria(guideline, allow_class = "character", has_length = 1)
2021-07-12 20:24:49 +02:00
meet_criteria(main, allow_class = "character", has_length = 1, allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1)
2023-01-21 23:47:20 +01:00
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3))
2022-10-05 09:12:22 +02:00
language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1)
2022-08-28 10:31:50 +02:00
2021-04-07 08:37:42 +02:00
# translate if not specifically set
if (missing(ylab)) {
2022-08-19 12:33:14 +02:00
ylab <- translate_into_language(ylab, language = language)
2021-04-07 08:37:42 +02:00
}
if (missing(xlab)) {
2022-08-19 12:33:14 +02:00
xlab <- translate_into_language(xlab, language = language)
2021-04-07 08:37:42 +02:00
}
2022-08-28 10:31:50 +02:00
2023-01-21 23:47:20 +01:00
if (length(colours_SIR) == 1) {
colours_SIR <- rep(colours_SIR, 3)
}
main <- gsub(" +", " ", paste0(main, collapse = " "))
2022-08-28 10:31:50 +02:00
x <- plot_prepare_table(x, expand = expand)
2022-08-28 10:31:50 +02:00
cols_sub <- plot_colours_subtitle_guideline(
x = x,
mo = mo,
ab = ab,
guideline = guideline,
2023-01-21 23:47:20 +01:00
colours_SIR = colours_SIR,
2022-08-28 10:31:50 +02:00
fn = as.mic,
language = language,
...
)
barplot(x,
2022-08-28 10:31:50 +02:00
col = cols_sub$cols,
main = main,
2023-01-21 23:47:20 +01:00
ylim = c(0, max(x) * ifelse(any(colours_SIR %in% cols_sub$cols), 1.1, 1)),
2022-08-28 10:31:50 +02:00
ylab = ylab,
xlab = xlab,
axes = FALSE
)
axis(2, seq(0, max(x)))
if (!is.null(cols_sub$sub)) {
mtext(side = 3, line = 0.5, adj = 0.5, cex = 0.75, cols_sub$sub)
}
2022-08-28 10:31:50 +02:00
2023-01-21 23:47:20 +01:00
if (any(colours_SIR %in% cols_sub$cols)) {
legend_txt <- character(0)
legend_col <- character(0)
2023-01-21 23:47:20 +01:00
if (any(cols_sub$cols == colours_SIR[1] & cols_sub$count > 0)) {
legend_txt <- "Susceptible"
2023-01-21 23:47:20 +01:00
legend_col <- colours_SIR[1]
}
2023-01-21 23:47:20 +01:00
if (any(cols_sub$cols == colours_SIR[2] & cols_sub$count > 0)) {
legend_txt <- c(legend_txt, plot_name_of_I(cols_sub$guideline))
2023-01-21 23:47:20 +01:00
legend_col <- c(legend_col, colours_SIR[2])
}
2023-01-21 23:47:20 +01:00
if (any(cols_sub$cols == colours_SIR[3] & cols_sub$count > 0)) {
legend_txt <- c(legend_txt, "Resistant")
2023-01-21 23:47:20 +01:00
legend_col <- c(legend_col, colours_SIR[3])
}
2022-08-28 10:31:50 +02:00
2021-04-07 08:37:42 +02:00
legend("top",
2022-08-28 10:31:50 +02:00
x.intersp = 0.5,
legend = translate_into_language(legend_txt, language = language),
fill = legend_col,
horiz = TRUE,
cex = 0.75,
box.lwd = 0,
box.col = "#FFFFFF55",
bg = "#FFFFFF55"
)
}
}
#' @method barplot mic
#' @export
#' @noRd
barplot.mic <- function(height,
mo = NULL,
ab = NULL,
guideline = "EUCAST",
main = deparse(substitute(height)),
2021-07-12 20:24:49 +02:00
ylab = "Frequency",
xlab = "Minimum Inhibitory Concentration (mg/L)",
2023-01-21 23:47:20 +01:00
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
language = get_AMR_locale(),
expand = TRUE,
...) {
meet_criteria(main, allow_class = "character", has_length = 1, allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1)
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = TRUE)
meet_criteria(ab, allow_class = c("ab", "character"), allow_NULL = TRUE)
meet_criteria(guideline, allow_class = "character", has_length = 1)
2023-01-21 23:47:20 +01:00
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3))
2022-10-05 09:12:22 +02:00
language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1)
2022-08-28 10:31:50 +02:00
2021-04-07 08:37:42 +02:00
# translate if not specifically set
if (missing(ylab)) {
2022-08-19 12:33:14 +02:00
ylab <- translate_into_language(ylab, language = language)
2021-04-07 08:37:42 +02:00
}
if (missing(xlab)) {
2022-08-19 12:33:14 +02:00
xlab <- translate_into_language(xlab, language = language)
2021-04-07 08:37:42 +02:00
}
2022-08-28 10:31:50 +02:00
main <- gsub(" +", " ", paste0(main, collapse = " "))
2022-08-28 10:31:50 +02:00
plot(
x = height,
main = main,
ylab = ylab,
xlab = xlab,
mo = mo,
ab = ab,
guideline = guideline,
2023-01-21 23:47:20 +01:00
colours_SIR = colours_SIR,
2022-08-28 10:31:50 +02:00
...
)
}
2021-07-12 22:12:28 +02:00
#' @method autoplot mic
#' @rdname plot
# will be exported using s3_register() in R/zzz.R
2021-07-12 20:24:49 +02:00
autoplot.mic <- function(object,
mo = NULL,
ab = NULL,
guideline = "EUCAST",
2022-08-19 12:33:14 +02:00
title = deparse(substitute(object)),
2021-07-12 20:24:49 +02:00
ylab = "Frequency",
xlab = "Minimum Inhibitory Concentration (mg/L)",
2023-01-21 23:47:20 +01:00
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
language = get_AMR_locale(),
2021-07-12 20:24:49 +02:00
expand = TRUE,
...) {
stop_ifnot_installed("ggplot2")
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = TRUE)
meet_criteria(ab, allow_class = c("ab", "character"), allow_NULL = TRUE)
meet_criteria(guideline, allow_class = "character", has_length = 1)
2021-07-12 20:24:49 +02:00
meet_criteria(title, allow_class = "character", allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1)
2023-01-21 23:47:20 +01:00
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3))
2022-10-05 09:12:22 +02:00
language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1)
2022-08-28 10:31:50 +02:00
2021-04-07 08:37:42 +02:00
# translate if not specifically set
if (missing(ylab)) {
2022-08-19 12:33:14 +02:00
ylab <- translate_into_language(ylab, language = language)
2021-04-07 08:37:42 +02:00
}
if (missing(xlab)) {
2022-08-19 12:33:14 +02:00
xlab <- translate_into_language(xlab, language = language)
2021-04-07 08:37:42 +02:00
}
2022-08-28 10:31:50 +02:00
if ("main" %in% names(list(...))) {
title <- list(...)$main
}
if (!is.null(title)) {
title <- gsub(" +", " ", paste0(title, collapse = " "))
}
2022-08-28 10:31:50 +02:00
2021-07-12 20:24:49 +02:00
x <- plot_prepare_table(object, expand = expand)
2022-08-28 10:31:50 +02:00
cols_sub <- plot_colours_subtitle_guideline(
x = x,
mo = mo,
ab = ab,
guideline = guideline,
2023-01-21 23:47:20 +01:00
colours_SIR = colours_SIR,
2022-08-28 10:31:50 +02:00
fn = as.mic,
language = language,
...
)
df <- as.data.frame(x, stringsAsFactors = TRUE)
colnames(df) <- c("mic", "count")
df$cols <- cols_sub$cols
2023-01-21 23:47:20 +01:00
df$cols[df$cols == colours_SIR[1]] <- "Susceptible"
df$cols[df$cols == colours_SIR[2]] <- plot_name_of_I(cols_sub$guideline)
df$cols[df$cols == colours_SIR[3]] <- "Resistant"
2022-08-19 12:33:14 +02:00
df$cols <- factor(translate_into_language(df$cols, language = language),
2022-08-28 10:31:50 +02:00
levels = translate_into_language(c("Susceptible", plot_name_of_I(cols_sub$guideline), "Resistant"),
language = language
),
ordered = TRUE
)
2021-07-12 20:24:49 +02:00
p <- ggplot2::ggplot(df)
2022-08-28 10:31:50 +02:00
2023-01-21 23:47:20 +01:00
if (any(colours_SIR %in% cols_sub$cols)) {
2022-08-28 10:31:50 +02:00
vals <- c(
2023-01-21 23:47:20 +01:00
"Susceptible" = colours_SIR[1],
"Susceptible, incr. exp." = colours_SIR[2],
"Intermediate" = colours_SIR[2],
"Resistant" = colours_SIR[3]
2022-08-28 10:31:50 +02:00
)
2022-08-19 12:33:14 +02:00
names(vals) <- translate_into_language(names(vals), language = language)
p <- p +
2022-08-28 10:31:50 +02:00
ggplot2::geom_col(ggplot2::aes(x = mic, y = count, fill = cols)) +
# limits = force is needed because of a ggplot2 >= 3.3.4 bug (#4511)
2022-08-28 10:31:50 +02:00
ggplot2::scale_fill_manual(
values = vals,
name = NULL,
limits = force
)
} else {
p <- p +
2021-02-26 12:11:29 +01:00
ggplot2::geom_col(ggplot2::aes(x = mic, y = count))
}
2022-08-28 10:31:50 +02:00
p +
ggplot2::labs(title = title, x = xlab, y = ylab, subtitle = cols_sub$sub)
}
2021-11-01 13:51:13 +01:00
#' @method fortify mic
#' @rdname plot
# will be exported using s3_register() in R/zzz.R
fortify.mic <- function(object, ...) {
2022-08-28 10:31:50 +02:00
stats::setNames(
as.data.frame(plot_prepare_table(object, expand = FALSE)),
c("x", "y")
)
2021-11-01 13:51:13 +01:00
}
#' @method plot disk
#' @export
#' @importFrom graphics barplot axis mtext legend
#' @rdname plot
plot.disk <- function(x,
main = deparse(substitute(x)),
ylab = "Frequency",
xlab = "Disk diffusion diameter (mm)",
mo = NULL,
ab = NULL,
guideline = "EUCAST",
2023-01-21 23:47:20 +01:00
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
language = get_AMR_locale(),
expand = TRUE,
...) {
meet_criteria(main, allow_class = "character", has_length = 1, allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1)
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = TRUE)
meet_criteria(ab, allow_class = c("ab", "character"), allow_NULL = TRUE)
meet_criteria(guideline, allow_class = "character", has_length = 1)
2023-01-21 23:47:20 +01:00
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3))
2022-10-05 09:12:22 +02:00
language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1)
2022-08-28 10:31:50 +02:00
2021-04-07 08:37:42 +02:00
# translate if not specifically set
if (missing(ylab)) {
2022-08-19 12:33:14 +02:00
ylab <- translate_into_language(ylab, language = language)
2021-04-07 08:37:42 +02:00
}
if (missing(xlab)) {
2022-08-19 12:33:14 +02:00
xlab <- translate_into_language(xlab, language = language)
2021-04-07 08:37:42 +02:00
}
2022-08-28 10:31:50 +02:00
2023-01-21 23:47:20 +01:00
if (length(colours_SIR) == 1) {
colours_SIR <- rep(colours_SIR, 3)
}
main <- gsub(" +", " ", paste0(main, collapse = " "))
2022-08-28 10:31:50 +02:00
x <- plot_prepare_table(x, expand = expand)
2022-08-28 10:31:50 +02:00
cols_sub <- plot_colours_subtitle_guideline(
x = x,
mo = mo,
ab = ab,
guideline = guideline,
2023-01-21 23:47:20 +01:00
colours_SIR = colours_SIR,
2022-08-28 10:31:50 +02:00
fn = as.disk,
language = language,
...
)
barplot(x,
2022-08-28 10:31:50 +02:00
col = cols_sub$cols,
main = main,
2023-01-21 23:47:20 +01:00
ylim = c(0, max(x) * ifelse(any(colours_SIR %in% cols_sub$cols), 1.1, 1)),
2022-08-28 10:31:50 +02:00
ylab = ylab,
xlab = xlab,
axes = FALSE
)
axis(2, seq(0, max(x)))
if (!is.null(cols_sub$sub)) {
mtext(side = 3, line = 0.5, adj = 0.5, cex = 0.75, cols_sub$sub)
}
2022-08-28 10:31:50 +02:00
2023-01-21 23:47:20 +01:00
if (any(colours_SIR %in% cols_sub$cols)) {
legend_txt <- character(0)
legend_col <- character(0)
2023-01-21 23:47:20 +01:00
if (any(cols_sub$cols == colours_SIR[3] & cols_sub$count > 0)) {
legend_txt <- "Resistant"
2023-01-21 23:47:20 +01:00
legend_col <- colours_SIR[3]
}
2023-01-21 23:47:20 +01:00
if (any(cols_sub$cols == colours_SIR[2] & cols_sub$count > 0)) {
legend_txt <- c(legend_txt, plot_name_of_I(cols_sub$guideline))
2023-01-21 23:47:20 +01:00
legend_col <- c(legend_col, colours_SIR[2])
}
2023-01-21 23:47:20 +01:00
if (any(cols_sub$cols == colours_SIR[1] & cols_sub$count > 0)) {
legend_txt <- c(legend_txt, "Susceptible")
2023-01-21 23:47:20 +01:00
legend_col <- c(legend_col, colours_SIR[1])
}
2022-08-28 10:31:50 +02:00
legend("top",
x.intersp = 0.5,
legend = translate_into_language(legend_txt, language = language),
fill = legend_col,
horiz = TRUE,
cex = 0.75,
box.lwd = 0,
box.col = "#FFFFFF55",
bg = "#FFFFFF55"
)
}
}
#' @method barplot disk
#' @export
#' @noRd
barplot.disk <- function(height,
main = deparse(substitute(height)),
ylab = "Frequency",
xlab = "Disk diffusion diameter (mm)",
mo = NULL,
ab = NULL,
guideline = "EUCAST",
2023-01-21 23:47:20 +01:00
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
language = get_AMR_locale(),
expand = TRUE,
...) {
meet_criteria(main, allow_class = "character", has_length = 1, allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1)
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = TRUE)
meet_criteria(ab, allow_class = c("ab", "character"), allow_NULL = TRUE)
meet_criteria(guideline, allow_class = "character", has_length = 1)
2023-01-21 23:47:20 +01:00
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3))
2022-10-05 09:12:22 +02:00
language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1)
2022-08-28 10:31:50 +02:00
2021-04-07 08:37:42 +02:00
# translate if not specifically set
if (missing(ylab)) {
2022-08-19 12:33:14 +02:00
ylab <- translate_into_language(ylab, language = language)
2021-04-07 08:37:42 +02:00
}
if (missing(xlab)) {
2022-08-19 12:33:14 +02:00
xlab <- translate_into_language(xlab, language = language)
2021-04-07 08:37:42 +02:00
}
2022-08-28 10:31:50 +02:00
main <- gsub(" +", " ", paste0(main, collapse = " "))
2022-08-28 10:31:50 +02:00
plot(
x = height,
main = main,
ylab = ylab,
xlab = xlab,
mo = mo,
ab = ab,
guideline = guideline,
2023-01-21 23:47:20 +01:00
colours_SIR = colours_SIR,
2022-08-28 10:31:50 +02:00
...
)
}
2021-07-12 20:24:49 +02:00
#' @method autoplot disk
#' @rdname plot
# will be exported using s3_register() in R/zzz.R
2021-07-12 20:24:49 +02:00
autoplot.disk <- function(object,
mo = NULL,
ab = NULL,
2022-08-19 12:33:14 +02:00
title = deparse(substitute(object)),
2021-07-12 20:24:49 +02:00
ylab = "Frequency",
xlab = "Disk diffusion diameter (mm)",
guideline = "EUCAST",
2023-01-21 23:47:20 +01:00
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
language = get_AMR_locale(),
2021-07-12 20:24:49 +02:00
expand = TRUE,
...) {
stop_ifnot_installed("ggplot2")
meet_criteria(title, allow_class = "character", allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1)
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = TRUE)
meet_criteria(ab, allow_class = c("ab", "character"), allow_NULL = TRUE)
meet_criteria(guideline, allow_class = "character", has_length = 1)
2023-01-21 23:47:20 +01:00
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3))
2022-10-05 09:12:22 +02:00
language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1)
2022-08-28 10:31:50 +02:00
2021-04-07 08:37:42 +02:00
# translate if not specifically set
if (missing(ylab)) {
2022-08-19 12:33:14 +02:00
ylab <- translate_into_language(ylab, language = language)
2021-04-07 08:37:42 +02:00
}
if (missing(xlab)) {
2022-08-19 12:33:14 +02:00
xlab <- translate_into_language(xlab, language = language)
2021-04-07 08:37:42 +02:00
}
2022-08-28 10:31:50 +02:00
if ("main" %in% names(list(...))) {
title <- list(...)$main
}
if (!is.null(title)) {
title <- gsub(" +", " ", paste0(title, collapse = " "))
}
2022-08-28 10:31:50 +02:00
2021-07-12 20:24:49 +02:00
x <- plot_prepare_table(object, expand = expand)
2022-08-28 10:31:50 +02:00
cols_sub <- plot_colours_subtitle_guideline(
x = x,
mo = mo,
ab = ab,
guideline = guideline,
2023-01-21 23:47:20 +01:00
colours_SIR = colours_SIR,
2022-08-28 10:31:50 +02:00
fn = as.disk,
language = language,
...
)
df <- as.data.frame(x, stringsAsFactors = TRUE)
colnames(df) <- c("disk", "count")
df$cols <- cols_sub$cols
2022-08-28 10:31:50 +02:00
2023-01-21 23:47:20 +01:00
df$cols[df$cols == colours_SIR[1]] <- "Susceptible"
df$cols[df$cols == colours_SIR[2]] <- plot_name_of_I(cols_sub$guideline)
df$cols[df$cols == colours_SIR[3]] <- "Resistant"
2022-08-19 12:33:14 +02:00
df$cols <- factor(translate_into_language(df$cols, language = language),
2022-08-28 10:31:50 +02:00
levels = translate_into_language(c("Susceptible", plot_name_of_I(cols_sub$guideline), "Resistant"),
language = language
),
ordered = TRUE
)
2021-07-12 20:24:49 +02:00
p <- ggplot2::ggplot(df)
2022-08-28 10:31:50 +02:00
2023-01-21 23:47:20 +01:00
if (any(colours_SIR %in% cols_sub$cols)) {
2022-08-28 10:31:50 +02:00
vals <- c(
2023-01-21 23:47:20 +01:00
"Susceptible" = colours_SIR[1],
"Susceptible, incr. exp." = colours_SIR[2],
"Intermediate" = colours_SIR[2],
"Resistant" = colours_SIR[3]
2022-08-28 10:31:50 +02:00
)
2022-08-19 12:33:14 +02:00
names(vals) <- translate_into_language(names(vals), language = language)
p <- p +
2022-08-28 10:31:50 +02:00
ggplot2::geom_col(ggplot2::aes(x = disk, y = count, fill = cols)) +
# limits = force is needed because of a ggplot2 >= 3.3.4 bug (#4511)
2022-08-28 10:31:50 +02:00
ggplot2::scale_fill_manual(
values = vals,
name = NULL,
limits = force
)
} else {
p <- p +
2021-02-26 12:11:29 +01:00
ggplot2::geom_col(ggplot2::aes(x = disk, y = count))
}
2022-08-28 10:31:50 +02:00
p +
ggplot2::labs(title = title, x = xlab, y = ylab, subtitle = cols_sub$sub)
}
2021-11-01 13:51:13 +01:00
#' @method fortify disk
#' @rdname plot
# will be exported using s3_register() in R/zzz.R
fortify.disk <- function(object, ...) {
2022-08-28 10:31:50 +02:00
stats::setNames(
as.data.frame(plot_prepare_table(object, expand = FALSE)),
c("x", "y")
)
2021-11-01 13:51:13 +01:00
}
2023-01-21 23:47:20 +01:00
#' @method plot sir
#' @export
#' @importFrom graphics plot text axis
#' @rdname plot
2023-01-21 23:47:20 +01:00
plot.sir <- function(x,
ylab = "Percentage",
xlab = "Antimicrobial Interpretation",
main = deparse(substitute(x)),
2022-08-19 12:33:14 +02:00
language = get_AMR_locale(),
...) {
meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1)
meet_criteria(main, allow_class = "character", has_length = 1, allow_NULL = TRUE)
2022-08-28 10:31:50 +02:00
2022-08-19 12:33:14 +02:00
# translate if not specifically set
if (missing(ylab)) {
ylab <- translate_into_language(ylab, language = language)
}
if (missing(xlab)) {
xlab <- translate_into_language(xlab, language = language)
}
2022-08-28 10:31:50 +02:00
data <- as.data.frame(table(x), stringsAsFactors = FALSE)
colnames(data) <- c("x", "n")
data$s <- round((data$n / sum(data$n)) * 100, 1)
2022-08-28 10:31:50 +02:00
if (!"S" %in% data$x) {
data <- rbind(data, data.frame(x = "S", n = 0, s = 0, stringsAsFactors = FALSE),
2022-08-28 10:31:50 +02:00
stringsAsFactors = FALSE
)
}
if (!"I" %in% data$x) {
data <- rbind(data, data.frame(x = "I", n = 0, s = 0, stringsAsFactors = FALSE),
2022-08-28 10:31:50 +02:00
stringsAsFactors = FALSE
)
}
if (!"R" %in% data$x) {
data <- rbind(data, data.frame(x = "R", n = 0, s = 0, stringsAsFactors = FALSE),
2022-08-28 10:31:50 +02:00
stringsAsFactors = FALSE
)
}
2022-08-28 10:31:50 +02:00
2021-02-26 12:11:29 +01:00
data$x <- factor(data$x, levels = c("S", "I", "R"), ordered = TRUE)
2022-08-28 10:31:50 +02:00
2023-02-09 13:07:39 +01:00
ymax <- pm_if_else(max(data$s) > 95, 105, 100)
2022-08-28 10:31:50 +02:00
plot(
x = data$x,
y = data$s,
lwd = 2,
ylim = c(0, ymax),
ylab = ylab,
xlab = xlab,
main = main,
axes = FALSE
)
# x axis
2023-02-09 13:07:39 +01:00
axis(side = 1, at = 1:pm_n_distinct(data$x), labels = levels(data$x), lwd = 0)
# y axis, 0-100%
axis(side = 2, at = seq(0, 100, 5))
2022-08-28 10:31:50 +02:00
text(
x = data$x,
y = data$s + 4,
labels = paste0(data$s, "% (n = ", data$n, ")")
)
}
2023-01-21 23:47:20 +01:00
#' @method barplot sir
#' @importFrom graphics barplot axis
#' @export
#' @noRd
2023-01-21 23:47:20 +01:00
barplot.sir <- function(height,
main = deparse(substitute(height)),
xlab = "Antimicrobial Interpretation",
ylab = "Frequency",
2023-01-21 23:47:20 +01:00
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
language = get_AMR_locale(),
expand = TRUE,
...) {
meet_criteria(xlab, allow_class = "character", has_length = 1)
meet_criteria(main, allow_class = "character", has_length = 1, allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1)
2023-01-21 23:47:20 +01:00
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3))
2022-10-05 09:12:22 +02:00
language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1)
2022-08-28 10:31:50 +02:00
2021-04-07 08:37:42 +02:00
# translate if not specifically set
if (missing(ylab)) {
2022-08-19 12:33:14 +02:00
ylab <- translate_into_language(ylab, language = language)
2021-04-07 08:37:42 +02:00
}
if (missing(xlab)) {
2022-08-19 12:33:14 +02:00
xlab <- translate_into_language(xlab, language = language)
2021-04-07 08:37:42 +02:00
}
2022-08-28 10:31:50 +02:00
2023-01-21 23:47:20 +01:00
if (length(colours_SIR) == 1) {
colours_SIR <- rep(colours_SIR, 3)
}
main <- gsub(" +", " ", paste0(main, collapse = " "))
2022-08-28 10:31:50 +02:00
x <- table(height)
2021-02-26 12:11:29 +01:00
x <- x[c(1, 2, 3)]
barplot(x,
2023-01-21 23:47:20 +01:00
col = colours_SIR,
2022-08-28 10:31:50 +02:00
xlab = xlab,
main = main,
ylab = ylab,
axes = FALSE
)
axis(2, seq(0, max(x)))
}
2021-02-26 12:11:29 +01:00
2023-01-21 23:47:20 +01:00
#' @method autoplot sir
2021-02-26 12:11:29 +01:00
#' @rdname plot
# will be exported using s3_register() in R/zzz.R
2023-01-21 23:47:20 +01:00
autoplot.sir <- function(object,
2022-08-19 12:33:14 +02:00
title = deparse(substitute(object)),
2021-07-12 20:24:49 +02:00
xlab = "Antimicrobial Interpretation",
ylab = "Frequency",
2023-01-21 23:47:20 +01:00
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
language = get_AMR_locale(),
2021-07-12 20:24:49 +02:00
...) {
2021-02-26 12:11:29 +01:00
stop_ifnot_installed("ggplot2")
meet_criteria(title, allow_class = "character", allow_NULL = TRUE)
2021-02-26 12:11:29 +01:00
meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1)
2023-01-21 23:47:20 +01:00
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3))
2022-08-28 10:31:50 +02:00
2021-04-07 08:37:42 +02:00
# translate if not specifically set
if (missing(ylab)) {
2022-08-19 12:33:14 +02:00
ylab <- translate_into_language(ylab, language = language)
2021-04-07 08:37:42 +02:00
}
if (missing(xlab)) {
2022-08-19 12:33:14 +02:00
xlab <- translate_into_language(xlab, language = language)
2021-04-07 08:37:42 +02:00
}
2022-08-28 10:31:50 +02:00
if ("main" %in% names(list(...))) {
title <- list(...)$main
}
if (!is.null(title)) {
title <- gsub(" +", " ", paste0(title, collapse = " "))
}
2022-08-28 10:31:50 +02:00
2023-01-21 23:47:20 +01:00
if (length(colours_SIR) == 1) {
colours_SIR <- rep(colours_SIR, 3)
2021-02-26 12:11:29 +01:00
}
2022-08-28 10:31:50 +02:00
2021-07-12 20:24:49 +02:00
df <- as.data.frame(table(object), stringsAsFactors = TRUE)
2023-01-21 23:47:20 +01:00
colnames(df) <- c("sir", "count")
2021-07-12 20:24:49 +02:00
ggplot2::ggplot(df) +
2023-01-21 23:47:20 +01:00
ggplot2::geom_col(ggplot2::aes(x = sir, y = count, fill = sir)) +
# limits = force is needed because of a ggplot2 >= 3.3.4 bug (#4511)
2022-08-28 10:31:50 +02:00
ggplot2::scale_fill_manual(
values = c(
2023-01-21 23:47:20 +01:00
"S" = colours_SIR[1],
"I" = colours_SIR[2],
"R" = colours_SIR[3]
2022-08-28 10:31:50 +02:00
),
limits = force
) +
2021-02-26 12:11:29 +01:00
ggplot2::labs(title = title, x = xlab, y = ylab) +
ggplot2::theme(legend.position = "none")
}
2021-04-07 08:37:42 +02:00
2023-01-21 23:47:20 +01:00
#' @method fortify sir
2021-11-01 13:51:13 +01:00
#' @rdname plot
# will be exported using s3_register() in R/zzz.R
2023-01-21 23:47:20 +01:00
fortify.sir <- function(object, ...) {
2022-08-28 10:31:50 +02:00
stats::setNames(
as.data.frame(table(object)),
c("x", "y")
)
2021-11-01 13:51:13 +01:00
}
2021-04-07 08:37:42 +02:00
plot_prepare_table <- function(x, expand) {
2021-05-12 18:15:03 +02:00
x <- x[!is.na(x)]
stop_if(length(x) == 0, "no observations to plot", call = FALSE)
2021-04-07 08:37:42 +02:00
if (is.mic(x)) {
if (expand == TRUE) {
# expand range for MIC by adding factors of 2 from lowest to highest so all MICs in between also print
valid_lvls <- levels(x)
2021-04-07 08:37:42 +02:00
extra_range <- max(x) / 2
while (min(extra_range) / 2 > min(x)) {
extra_range <- c(min(extra_range) / 2, extra_range)
}
nms <- extra_range
extra_range <- rep(0, length(extra_range))
names(extra_range) <- nms
x <- table(droplevels(x, as.mic = FALSE))
extra_range <- extra_range[!names(extra_range) %in% names(x) & names(extra_range) %in% valid_lvls]
2021-04-07 08:37:42 +02:00
x <- as.table(c(x, extra_range))
} else {
x <- table(droplevels(x, as.mic = FALSE))
}
x <- x[order(as.double(as.mic(names(x))))]
} else if (is.disk(x)) {
if (expand == TRUE) {
# expand range for disks from lowest to highest so all mm's in between also print
extra_range <- rep(0, max(x) - min(x) - 1)
names(extra_range) <- seq(min(x) + 1, max(x) - 1)
x <- table(x)
extra_range <- extra_range[!names(extra_range) %in% names(x)]
x <- as.table(c(x, extra_range))
} else {
x <- table(x)
}
x <- x[order(as.double(names(x)))]
}
as.table(x)
}
plot_name_of_I <- function(guideline) {
if (guideline %unlike% "CLSI" && as.double(gsub("[^0-9]+", "", guideline)) >= 2019) {
2021-04-07 08:37:42 +02:00
# interpretation since 2019
"Susceptible, incr. exp."
2021-04-07 08:37:42 +02:00
} else {
# interpretation until 2019
"Intermediate"
}
}
2023-01-21 23:47:20 +01:00
plot_colours_subtitle_guideline <- function(x, mo, ab, guideline, colours_SIR, fn, language, ...) {
guideline <- get_guideline(guideline, AMR::clinical_breakpoints)
2021-04-07 08:37:42 +02:00
if (!is.null(mo) && !is.null(ab)) {
# interpret and give colour based on MIC values
mo <- as.mo(mo)
ab <- as.ab(ab)
2023-01-21 23:47:20 +01:00
sir <- suppressWarnings(suppressMessages(as.sir(fn(names(x)), mo = mo, ab = ab, guideline = guideline, ...)))
cols <- character(length = length(sir))
cols[is.na(sir)] <- "#BEBEBE"
cols[sir == "S"] <- colours_SIR[1]
cols[sir == "I"] <- colours_SIR[2]
cols[sir == "R"] <- colours_SIR[3]
2021-04-07 08:37:42 +02:00
moname <- mo_name(mo, language = language)
abname <- ab_name(ab, language = language)
if (all(cols == "#BEBEBE")) {
2022-08-28 10:31:50 +02:00
message_(
"No ", guideline, " interpretations found for ",
ab_name(ab, language = NULL, tolower = TRUE), " in ", moname
)
2021-04-07 08:37:42 +02:00
guideline_txt <- ""
} else {
guideline_txt <- guideline
if (isTRUE(list(...)$uti)) {
guideline_txt <- paste("UTIs,", guideline_txt)
}
guideline_txt <- paste0("(", guideline_txt, ")")
2021-04-07 08:37:42 +02:00
}
2022-08-28 10:31:50 +02:00
sub <- bquote(.(abname) ~ "-" ~ italic(.(moname)) ~ .(guideline_txt))
2021-04-07 08:37:42 +02:00
} else {
cols <- "#BEBEBE"
sub <- NULL
}
list(cols = cols, count = as.double(x), sub = sub, guideline = guideline)
}