1
0
mirror of https://github.com/msberends/AMR.git synced 2025-09-02 20:24:07 +02:00

12 Commits

45 changed files with 856 additions and 563 deletions

View File

@@ -68,35 +68,41 @@ echo ""
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
echo "Updating semantic versioning and date..." echo "Updating semantic versioning and date..."
# Get tags from remote and remove tags not on remote current_branch=$(git rev-parse --abbrev-ref HEAD)
git fetch origin --prune --prune-tags --quiet if [ "$current_branch" != "main" ]; then
currenttagfull=$(git describe --tags --abbrev=0) echo "- Current branch is '$current_branch'; skipping version/date update (only runs on 'main')"
currenttag=$(git describe --tags --abbrev=0 | sed 's/v//') else
# Version update logic begins here
# Assume main branch to be 'main' or 'master' # Get tags from remote and remove tags not on remote
defaultbranch=$(git branch | cut -c 3- | grep -E '^master$|^main$') git fetch origin --prune --prune-tags --quiet
if [ "$currenttag" = "" ]; then currenttagfull=$(git describe --tags --abbrev=0)
currenttag=$(git describe --tags --abbrev=0 | sed 's/v//')
# Assume main branch to be 'main' or 'master'
defaultbranch=$(git branch | cut -c 3- | grep -E '^master$|^main$')
if [ "$currenttag" = "" ]; then
currenttag="0.0.1" currenttag="0.0.1"
currentcommit=$(git rev-list --count ${defaultbranch}) currentcommit=$(git rev-list --count ${defaultbranch})
echo "- No git tags found, creating one in format 'v(x).(y).(z)' - currently ${currentcommit} previous commits in '${defaultbranch}'" echo "- No git tags found, creating one in format 'v(x).(y).(z)' - currently ${currentcommit} previous commits in '${defaultbranch}'"
else else
currentcommit=$(git rev-list --count ${currenttagfull}..${defaultbranch}) currentcommit=$(git rev-list --count ${currenttagfull}..${defaultbranch})
echo "- Latest tag is '${currenttagfull}', with ${currentcommit} previous commits in '${defaultbranch}'" echo "- Latest tag is '${currenttagfull}', with ${currentcommit} previous commits in '${defaultbranch}'"
fi fi
# Combine tag and commit number # Combine tag and commit number
currentversion="$currenttag.$((currentcommit + 9001))" currentversion="$currenttag.$((currentcommit + 9001))"
echo "- ${currentpkg} pkg version set to ${currentversion}" echo "- ${currentpkg} pkg version set to ${currentversion}"
# Update version number and date in DESCRIPTION # Update version number and date in DESCRIPTION
sed -i -- "s/^Version: .*/Version: ${currentversion}/" DESCRIPTION sed -i -- "s/^Version: .*/Version: ${currentversion}/" DESCRIPTION
sed -i -- "s/^Date: .*/Date: $(date '+%Y-%m-%d')/" DESCRIPTION sed -i -- "s/^Date: .*/Date: $(date '+%Y-%m-%d')/" DESCRIPTION
echo "- Updated version number and date in ./DESCRIPTION" echo "- Updated version number and date in ./DESCRIPTION"
rm -f DESCRIPTION-- rm -f DESCRIPTION--
git add DESCRIPTION git add DESCRIPTION
# Update version number in NEWS.md # Update version number in NEWS.md
if [ -e "NEWS.md" ]; then if [ -e "NEWS.md" ]; then
if [ "$currentpkg" = "your" ]; then if [ "$currentpkg" = "your" ]; then
currentpkg="" currentpkg=""
fi fi
@@ -104,13 +110,14 @@ if [ -e "NEWS.md" ]; then
echo "- Updated version number in ./NEWS.md" echo "- Updated version number in ./NEWS.md"
rm -f NEWS.md-- rm -f NEWS.md--
git add NEWS.md git add NEWS.md
else else
echo "- No NEWS.md found!" echo "- No NEWS.md found!"
fi fi
echo "" echo ""
# Save the version number for use in the commit-msg hook # Save the version number for use in the commit-msg hook
echo "${currentversion}" > .git/commit_version.tmp echo "${currentversion}" > .git/commit_version.tmp
fi
git add data-raw/* git add data-raw/*
git add data/* git add data/*

View File

@@ -59,8 +59,15 @@ jobs:
env: env:
R_REMOTES_NO_ERRORS_FROM_WARNINGS: true R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
steps: steps:
- name: Set up locales
run: |
sudo locale-gen en_US.UTF-8
sudo update-locale LANG=en_US.UTF-8
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2 - uses: r-lib/actions/setup-r@v2

View File

@@ -1,6 +1,6 @@
Package: AMR Package: AMR
Version: 3.0.0.9004 Version: 3.0.0.9017
Date: 2025-06-13 Date: 2025-07-28
Title: Antimicrobial Resistance Data Analysis Title: Antimicrobial Resistance Data Analysis
Description: Functions to simplify and standardise antimicrobial resistance (AMR) Description: Functions to simplify and standardise antimicrobial resistance (AMR)
data analysis and to work with microbial and antimicrobial properties by data analysis and to work with microbial and antimicrobial properties by

View File

@@ -12,6 +12,7 @@ S3method("[",deprecated_amr_dataset)
S3method("[",disk) S3method("[",disk)
S3method("[",mic) S3method("[",mic)
S3method("[",mo) S3method("[",mo)
S3method("[",sir)
S3method("[<-",ab) S3method("[<-",ab)
S3method("[<-",av) S3method("[<-",av)
S3method("[<-",disk) S3method("[<-",disk)
@@ -24,6 +25,7 @@ S3method("[[",deprecated_amr_dataset)
S3method("[[",disk) S3method("[[",disk)
S3method("[[",mic) S3method("[[",mic)
S3method("[[",mo) S3method("[[",mo)
S3method("[[",sir)
S3method("[[<-",ab) S3method("[[<-",ab)
S3method("[[<-",av) S3method("[[<-",av)
S3method("[[<-",disk) S3method("[[<-",disk)
@@ -99,6 +101,7 @@ S3method(print,custom_eucast_rules)
S3method(print,custom_mdro_guideline) S3method(print,custom_mdro_guideline)
S3method(print,deprecated_amr_dataset) S3method(print,deprecated_amr_dataset)
S3method(print,disk) S3method(print,disk)
S3method(print,interpreted_sir)
S3method(print,mic) S3method(print,mic)
S3method(print,mo) S3method(print,mo)
S3method(print,mo_renamed) S3method(print,mo_renamed)

14
NEWS.md
View File

@@ -1,16 +1,24 @@
# AMR 3.0.0.9004 # AMR 3.0.0.9017
This is primarily a bugfix release, though we added one nice feature too.
### New ### New
* Integration with the **tidymodels** framework to allow seamless use of MIC and SIR data in modelling pipelines via `recipes` * Integration with the **tidymodels** framework to allow seamless use of MIC and SIR data in modelling pipelines via `recipes`
- `step_mic_log2()` to transform `<mic>` columns with log2, and `step_sir_numeric()` to convert `<sir>` columns to numeric - `step_mic_log2()` to transform `<mic>` columns with log2, and `step_sir_numeric()` to convert `<sir>` columns to numeric
- `tidyselect` helpers: `all_mic()`, `all_mic_predictors()`, `all_sir()`, `all_sir_predictors()` - New `tidyselect` helpers: `all_mic()`, `all_mic_predictors()`, `all_sir()`, `all_sir_predictors()`
- Enables seamless use of MIC and SIR data in modelling pipelines via `recipes`
### Changed ### Changed
* Fixed a bug in `antibiogram()` for when no antimicrobials are set * Fixed a bug in `antibiogram()` for when no antimicrobials are set
* Fixed a bug in `antibiogram()` to allow column names containing the `+` character (#222)
* Fixed a bug in `as.ab()` for antimicrobial codes with a number in it if they are preceded by a space * Fixed a bug in `as.ab()` for antimicrobial codes with a number in it if they are preceded by a space
* Fixed a bug in `eucast_rules()` for using specific custom rules * Fixed a bug in `eucast_rules()` for using specific custom rules
* Fixed a bug in `as.sir()` to allow any tidyselect language (#220)
* Fixed a bug in `as.sir()` to pick right breakpoint when `uti = FALSE` (#216)
* Fixed a bug in `ggplot_sir()` when using `combine_SI = FALSE` (#213)
* Fixed all plotting to contain a separate colour for SDD (susceptible dose-dependent) (#223)
* Fixed some specific Dutch translations for antimicrobials * Fixed some specific Dutch translations for antimicrobials
* Added `names` to `age_groups()` so that custom names can be given (#215)
* Added note to `as.sir()` to make it explicit when higher-level taxonomic breakpoints are used (#218)
* Updated `random_mic()` and `random_disk()` to set skewedness of the distribution and allow multiple microorganisms * Updated `random_mic()` and `random_disk()` to set skewedness of the distribution and allow multiple microorganisms

View File

@@ -63,31 +63,6 @@ pm_left_join <- function(x, y, by = NULL, suffix = c(".x", ".y")) {
merged merged
} }
# support where() like tidyverse (this function will also be used when running `antibiogram()`):
where <- function(fn) {
# based on https://github.com/nathaneastwood/poorman/blob/52eb6947e0b4430cd588976ed8820013eddf955f/R/where.R#L17-L32
if (!is.function(fn)) {
stop_("`", deparse(substitute(fn)), "()` is not a valid predicate function.")
}
df <- pm_select_env$.data
cols <- pm_select_env$get_colnames()
if (is.null(df)) {
df <- get_current_data("where", call = FALSE)
cols <- colnames(df)
}
preds <- unlist(lapply(
df,
function(x, fn) {
do.call("fn", list(x))
},
fn
))
if (!is.logical(preds)) stop_("`where()` must be used with functions that return `TRUE` or `FALSE`.")
data_cols <- cols
cols <- data_cols[preds]
which(data_cols %in% cols)
}
# copied and slightly rewritten from {poorman} under permissive license (2021-10-15) # copied and slightly rewritten from {poorman} under permissive license (2021-10-15)
# https://github.com/nathaneastwood/poorman, MIT licensed, Nathan Eastwood, 2020 # https://github.com/nathaneastwood/poorman, MIT licensed, Nathan Eastwood, 2020
case_when_AMR <- function(...) { case_when_AMR <- function(...) {
@@ -544,7 +519,7 @@ word_wrap <- function(...,
) )
msg <- paste0(parts, collapse = "`") msg <- paste0(parts, collapse = "`")
} }
msg <- gsub("`(.+?)`", font_grey_bg("\\1"), msg) msg <- gsub("`(.+?)`", font_grey_bg("`\\1`"), msg)
# clean introduced whitespace in between fullstops # clean introduced whitespace in between fullstops
msg <- gsub("[.] +[.]", "..", msg) msg <- gsub("[.] +[.]", "..", msg)
@@ -814,7 +789,7 @@ meet_criteria <- function(object, # can be literally `list(...)` for `allow_argu
# if object is missing, or another error: # if object is missing, or another error:
tryCatch(invisible(object), tryCatch(invisible(object),
error = function(e) AMR_env$meet_criteria_error_txt <- e$message error = function(e) AMR_env$meet_criteria_error_txt <- conditionMessage(e)
) )
if (!is.null(AMR_env$meet_criteria_error_txt)) { if (!is.null(AMR_env$meet_criteria_error_txt)) {
error_txt <- AMR_env$meet_criteria_error_txt error_txt <- AMR_env$meet_criteria_error_txt
@@ -1319,6 +1294,10 @@ font_green_bg <- function(..., collapse = " ") {
# this is #3caea3 (picked to be colourblind-safe with other SIR colours) # this is #3caea3 (picked to be colourblind-safe with other SIR colours)
try_colour(font_black(..., collapse = collapse, adapt = FALSE), before = "\033[48;5;79m", after = "\033[49m", collapse = collapse) try_colour(font_black(..., collapse = collapse, adapt = FALSE), before = "\033[48;5;79m", after = "\033[49m", collapse = collapse)
} }
font_green_lighter_bg <- function(..., collapse = " ") {
# this is #8FD6C4 (picked to be colourblind-safe with other SIR colours)
try_colour(font_black(..., collapse = collapse, adapt = FALSE), before = "\033[48;5;158m", after = "\033[49m", collapse = collapse)
}
font_purple_bg <- function(..., collapse = " ") { font_purple_bg <- function(..., collapse = " ") {
try_colour(font_black(..., collapse = collapse, adapt = FALSE), before = "\033[48;5;89m", after = "\033[49m", collapse = collapse) try_colour(font_black(..., collapse = collapse, adapt = FALSE), before = "\033[48;5;89m", after = "\033[49m", collapse = collapse)
} }
@@ -1636,6 +1615,36 @@ get_n_cores <- function(max_cores = Inf) {
n_cores n_cores
} }
# Support `where()` if tidyselect not installed ----
if (!is.null(import_fn("where", "tidyselect", error_on_fail = FALSE))) {
# tidyselect::where() exists, load the namespace to make `where()`s work across the package in default arguments
loadNamespace("tidyselect")
} else {
where <- function(fn) {
# based on https://github.com/nathaneastwood/poorman/blob/52eb6947e0b4430cd588976ed8820013eddf955f/R/where.R#L17-L32
if (!is.function(fn)) {
stop_("`", deparse(substitute(fn)), "()` is not a valid predicate function.")
}
df <- pm_select_env$.data
cols <- pm_select_env$get_colnames()
if (is.null(df)) {
df <- get_current_data("where", call = FALSE)
cols <- colnames(df)
}
preds <- unlist(lapply(
df,
function(x, fn) {
do.call("fn", list(x))
},
fn
))
if (!is.logical(preds)) stop_("`where()` must be used with functions that return `TRUE` or `FALSE`.")
data_cols <- cols
cols <- data_cols[preds]
which(data_cols %in% cols)
}
}
# Faster data.table implementations ---- # Faster data.table implementations ----
match <- function(x, table, ...) { match <- function(x, table, ...) {
@@ -1655,52 +1664,6 @@ match <- function(x, table, ...) {
} }
} }
# nolint start
# Register S3 methods ----
# copied from vctrs::s3_register by their permission:
# https://github.com/r-lib/vctrs/blob/05968ce8e669f73213e3e894b5f4424af4f46316/R/register-s3.R
s3_register <- function(generic, class, method = NULL) {
stopifnot(is.character(generic), length(generic) == 1)
stopifnot(is.character(class), length(class) == 1)
pieces <- strsplit(generic, "::")[[1]]
stopifnot(length(pieces) == 2)
package <- pieces[[1]]
generic <- pieces[[2]]
caller <- parent.frame()
get_method_env <- function() {
top <- topenv(caller)
if (isNamespace(top)) {
asNamespace(environmentName(top))
} else {
caller
}
}
get_method <- function(method, env) {
if (is.null(method)) {
get(paste0(generic, ".", class), envir = get_method_env())
} else {
method
}
}
method_fn <- get_method(method)
stopifnot(is.function(method_fn))
setHook(packageEvent(package, "onLoad"), function(...) {
ns <- asNamespace(package)
method_fn <- get_method(method)
registerS3method(generic, class, method_fn, envir = ns)
})
if (!isNamespaceLoaded(package)) {
return(invisible())
}
envir <- asNamespace(package)
if (exists(generic, envir)) {
registerS3method(generic, class, method_fn, envir = envir)
}
invisible()
}
# Support old R versions ---- # Support old R versions ----
# these functions were not available in previous versions of R # these functions were not available in previous versions of R
# see here for the full list: https://github.com/r-lib/backports # see here for the full list: https://github.com/r-lib/backports

View File

@@ -952,7 +952,19 @@ pm_select_env$get_nrow <- function() nrow(pm_select_env$.data)
pm_select_env$get_ncol <- function() ncol(pm_select_env$.data) pm_select_env$get_ncol <- function() ncol(pm_select_env$.data)
pm_select <- function(.data, ...) { pm_select <- function(.data, ...) {
# col_pos <- pm_select_positions(.data, ..., .group_pos = TRUE),
col_pos <- tryCatch(pm_select_positions(.data, ..., .group_pos = TRUE), error = function(e) NULL)
if (is.null(col_pos)) {
# try with tidyverse
select_dplyr <- import_fn("select", "dplyr", error_on_fail = FALSE)
if (!is.null(select_dplyr)) {
col_pos <- which(colnames(.data) %in% colnames(select_dplyr(.data, ...)))
} else {
# this will throw an error as it did, but dplyr is not available, so no other option
col_pos <- pm_select_positions(.data, ..., .group_pos = TRUE) col_pos <- pm_select_positions(.data, ..., .group_pos = TRUE)
}
}
map_names <- names(col_pos) map_names <- names(col_pos)
map_names_length <- nchar(map_names) map_names_length <- nchar(map_names)
if (any(map_names_length == 0L)) { if (any(map_names_length == 0L)) {

3
R/ab.R
View File

@@ -184,7 +184,8 @@ as.ab <- function(x, flag_multiple_results = TRUE, language = get_AMR_locale(),
x_new[known_codes_cid] <- AMR_env$AB_lookup$ab[match(x[known_codes_cid], AMR_env$AB_lookup$cid)] x_new[known_codes_cid] <- AMR_env$AB_lookup$ab[match(x[known_codes_cid], AMR_env$AB_lookup$cid)]
previously_coerced <- x %in% AMR_env$ab_previously_coerced$x previously_coerced <- x %in% AMR_env$ab_previously_coerced$x
x_new[previously_coerced & is.na(x_new)] <- AMR_env$ab_previously_coerced$ab[match(x[is.na(x_new) & x %in% AMR_env$ab_previously_coerced$x], AMR_env$ab_previously_coerced$x)] x_new[previously_coerced & is.na(x_new)] <- AMR_env$ab_previously_coerced$ab[match(x[is.na(x_new) & x %in% AMR_env$ab_previously_coerced$x], AMR_env$ab_previously_coerced$x)]
if (any(previously_coerced) && isTRUE(info) && message_not_thrown_before("as.ab", entire_session = TRUE)) { previously_coerced_mention <- x %in% AMR_env$ab_previously_coerced$x & !x %in% AMR_env$AB_lookup$ab & !x %in% AMR_env$AB_lookup$generalised_name
if (any(previously_coerced_mention) && isTRUE(info) && message_not_thrown_before("as.ab", entire_session = TRUE)) {
message_( message_(
"Returning previously coerced ", "Returning previously coerced ",
ifelse(length(unique(which(x[which(previously_coerced)] %in% x_bak_clean))) > 1, "value for an antimicrobial", "values for various antimicrobials"), ifelse(length(unique(which(x[which(previously_coerced)] %in% x_bak_clean))) > 1, "value for an antimicrobial", "values for various antimicrobials"),

View File

@@ -445,7 +445,7 @@ ab_validate <- function(x, property, ...) {
# try to catch an error when inputting an invalid argument # try to catch an error when inputting an invalid argument
# so the 'call.' can be set to FALSE # so the 'call.' can be set to FALSE
tryCatch(x[1L] %in% AMR_env$AB_lookup[1, property, drop = TRUE], tryCatch(x[1L] %in% AMR_env$AB_lookup[1, property, drop = TRUE],
error = function(e) stop(e$message, call. = FALSE) error = function(e) stop(conditionMessage(e), call. = FALSE)
) )
if (!all(x %in% AMR_env$AB_lookup[, property, drop = TRUE])) { if (!all(x %in% AMR_env$AB_lookup[, property, drop = TRUE])) {

12
R/age.R
View File

@@ -128,9 +128,10 @@ age <- function(x, reference = Sys.Date(), exact = FALSE, na.rm = FALSE, ...) {
#' Split Ages into Age Groups #' Split Ages into Age Groups
#' #'
#' Split ages into age groups defined by the `split` argument. This allows for easier demographic (antimicrobial resistance) analysis. #' Split ages into age groups defined by the `split` argument. This allows for easier demographic (antimicrobial resistance) analysis. The function returns an ordered [factor].
#' @param x Age, e.g. calculated with [age()]. #' @param x Age, e.g. calculated with [age()].
#' @param split_at Values to split `x` at - the default is age groups 0-11, 12-24, 25-54, 55-74 and 75+. See *Details*. #' @param split_at Values to split `x` at - the default is age groups 0-11, 12-24, 25-54, 55-74 and 75+. See *Details*.
#' @param names Optional names to be given to the various age groups.
#' @param na.rm A [logical] to indicate whether missing values should be removed. #' @param na.rm A [logical] to indicate whether missing values should be removed.
#' @details To split ages, the input for the `split_at` argument can be: #' @details To split ages, the input for the `split_at` argument can be:
#' #'
@@ -152,6 +153,7 @@ age <- function(x, reference = Sys.Date(), exact = FALSE, na.rm = FALSE, ...) {
#' #'
#' # split into 0-19, 20-49 and 50+ #' # split into 0-19, 20-49 and 50+
#' age_groups(ages, c(20, 50)) #' age_groups(ages, c(20, 50))
#' age_groups(ages, c(20, 50), names = c("Under 20 years", "20 to 50 years", "Over 50 years"))
#' #'
#' # split into groups of ten years #' # split into groups of ten years
#' age_groups(ages, 1:10 * 10) #' age_groups(ages, 1:10 * 10)
@@ -181,9 +183,10 @@ age <- function(x, reference = Sys.Date(), exact = FALSE, na.rm = FALSE, ...) {
#' ) #' )
#' } #' }
#' } #' }
age_groups <- function(x, split_at = c(12, 25, 55, 75), na.rm = FALSE) { age_groups <- function(x, split_at = c(0, 12, 25, 55, 75), names = NULL, na.rm = FALSE) {
meet_criteria(x, allow_class = c("numeric", "integer"), is_positive_or_zero = TRUE, is_finite = TRUE) meet_criteria(x, allow_class = c("numeric", "integer"), is_positive_or_zero = TRUE, is_finite = TRUE)
meet_criteria(split_at, allow_class = c("numeric", "integer", "character"), is_positive_or_zero = TRUE, is_finite = TRUE) meet_criteria(split_at, allow_class = c("numeric", "integer", "character"), is_positive_or_zero = TRUE, is_finite = TRUE)
meet_criteria(names, allow_class = "character", allow_NULL = TRUE)
meet_criteria(na.rm, allow_class = "logical", has_length = 1) meet_criteria(na.rm, allow_class = "logical", has_length = 1)
if (any(x < 0, na.rm = TRUE)) { if (any(x < 0, na.rm = TRUE)) {
@@ -224,6 +227,11 @@ age_groups <- function(x, split_at = c(12, 25, 55, 75), na.rm = FALSE) {
agegroups <- factor(lbls[y], levels = lbls, ordered = TRUE) agegroups <- factor(lbls[y], levels = lbls, ordered = TRUE)
if (!is.null(names)) {
stop_ifnot(length(names) == length(levels(agegroups)), "`names` must have the same length as the number of age groups (", length(levels(agegroups)), ").")
levels(agegroups) <- names
}
if (isTRUE(na.rm)) { if (isTRUE(na.rm)) {
agegroups <- agegroups[!is.na(agegroups)] agegroups <- agegroups[!is.na(agegroups)]
} }

View File

@@ -527,7 +527,7 @@ amr_selector <- function(filter,
) )
call <- substitute(filter) call <- substitute(filter)
agents <- tryCatch(AMR_env$AB_lookup[which(eval(call, envir = AMR_env$AB_lookup)), "ab", drop = TRUE], agents <- tryCatch(AMR_env$AB_lookup[which(eval(call, envir = AMR_env$AB_lookup)), "ab", drop = TRUE],
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(conditionMessage(e), call = -5)
) )
agents <- ab_in_data[ab_in_data %in% agents] agents <- ab_in_data[ab_in_data %in% agents]
message_agent_names( message_agent_names(
@@ -640,7 +640,7 @@ not_intrinsic_resistant <- function(only_sir_columns = FALSE, col_mo = NULL, ver
) )
} }
), ),
error = function(e) stop_("in not_intrinsic_resistant(): ", e$message, call = FALSE) error = function(e) stop_("in not_intrinsic_resistant(): ", conditionMessage(e), call = FALSE)
) )
agents <- ab_in_data[ab_in_data %in% names(vars_df_R[which(vars_df_R)])] agents <- ab_in_data[ab_in_data %in% names(vars_df_R[which(vars_df_R)])]

View File

@@ -576,6 +576,15 @@ antibiogram.default <- function(x,
} }
antimicrobials <- unlist(antimicrobials) antimicrobials <- unlist(antimicrobials)
} else { } else {
existing_ab_combined_cols <- ab_trycatch[ab_trycatch %like% "[+]" & ab_trycatch %in% colnames(x)]
if (length(existing_ab_combined_cols) > 0 && !is.null(ab_transform)) {
ab_transform <- NULL
warning_(
"Detected column name(s) containing the '+' character, which conflicts with the expected syntax in `antibiogram()`: the '+' is used to combine separate antimicrobial agent columns (e.g., \"AMP+GEN\").\n\n",
"To avoid incorrectly guessing which antimicrobials this represents, `ab_transform` was automatically set to `NULL`.\n\n",
"If this is unintended, please rename the column(s) to avoid using '+' in the name, or set `ab_transform = NULL` explicitly to suppress this message."
)
}
antimicrobials <- ab_trycatch antimicrobials <- ab_trycatch
} }

View File

@@ -264,7 +264,7 @@ av_validate <- function(x, property, ...) {
# try to catch an error when inputting an invalid argument # try to catch an error when inputting an invalid argument
# so the 'call.' can be set to FALSE # so the 'call.' can be set to FALSE
tryCatch(x[1L] %in% AMR_env$AV_lookup[1, property, drop = TRUE], tryCatch(x[1L] %in% AMR_env$AV_lookup[1, property, drop = TRUE],
error = function(e) stop(e$message, call. = FALSE) error = function(e) stop(conditionMessage(e), call. = FALSE)
) )
if (!all(x %in% AMR_env$AV_lookup[, property, drop = TRUE])) { if (!all(x %in% AMR_env$AV_lookup[, property, drop = TRUE])) {

View File

@@ -126,7 +126,7 @@ count_resistant <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -139,7 +139,7 @@ count_susceptible <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -152,7 +152,7 @@ count_S <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -165,7 +165,7 @@ count_SI <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -178,7 +178,7 @@ count_I <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -191,7 +191,7 @@ count_IR <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -204,7 +204,7 @@ count_R <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -217,7 +217,7 @@ count_all <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -240,6 +240,6 @@ count_df <- function(data,
combine_SI = combine_SI, combine_SI = combine_SI,
confidence_level = 0.95 # doesn't matter, will be removed confidence_level = 0.95 # doesn't matter, will be removed
), ),
error = function(e) stop_(gsub("in sir_calc_df(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc_df(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }

View File

@@ -175,7 +175,7 @@ custom_mdro_guideline <- function(..., as_factor = TRUE) {
# Value # Value
val <- tryCatch(eval(dots[[i]][[3]]), error = function(e) NULL) val <- tryCatch(eval(dots[[i]][[3]]), error = function(e) NULL)
stop_if(is.null(val), "rule ", i, " must return a valid value, it now returns an error: ", tryCatch(eval(dots[[i]][[3]]), error = function(e) e$message)) stop_if(is.null(val), "rule ", i, " must return a valid value, it now returns an error: ", tryCatch(eval(dots[[i]][[3]]), error = function(e) conditionMessage(e)))
stop_if(length(val) > 1, "rule ", i, " must return a value of length 1, not ", length(val)) stop_if(length(val) > 1, "rule ", i, " must return a value of length 1, not ", length(val))
out[[i]]$value <- as.character(val) out[[i]]$value <- as.character(val)
} }
@@ -254,7 +254,7 @@ run_custom_mdro_guideline <- function(df, guideline, info) {
for (i in seq_len(n_dots)) { for (i in seq_len(n_dots)) {
qry <- tryCatch(eval(parse(text = guideline[[i]]$query), envir = df, enclos = parent.frame()), qry <- tryCatch(eval(parse(text = guideline[[i]]$query), envir = df, enclos = parent.frame()),
error = function(e) { error = function(e) {
AMR_env$err_msg <- e$message AMR_env$err_msg <- conditionMessage(e)
return("error") return("error")
} }
) )

View File

@@ -1178,7 +1178,7 @@ edit_sir <- function(x,
ifelse(length(rows) > 10, "...", ""), ifelse(length(rows) > 10, "...", ""),
" while writing value '", to, " while writing value '", to,
"' to column(s) `", paste(cols, collapse = "`, `"), "' to column(s) `", paste(cols, collapse = "`, `"),
"`:\n", e$message "`:\n", conditionMessage(e)
), ),
call. = FALSE call. = FALSE
) )

View File

@@ -177,6 +177,7 @@ ggplot_sir <- function(data,
nrow = NULL, nrow = NULL,
colours = c( colours = c(
S = "#3CAEA3", S = "#3CAEA3",
SDD = "#8FD6C4",
SI = "#3CAEA3", SI = "#3CAEA3",
I = "#F6D55C", I = "#F6D55C",
IR = "#ED553B", IR = "#ED553B",
@@ -205,7 +206,7 @@ ggplot_sir <- function(data,
meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_positive_or_zero = TRUE, is_finite = TRUE) meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_positive_or_zero = TRUE, is_finite = TRUE)
language <- validate_language(language) language <- validate_language(language)
meet_criteria(nrow, allow_class = c("numeric", "integer"), has_length = 1, allow_NULL = TRUE, is_positive = TRUE, is_finite = TRUE) meet_criteria(nrow, allow_class = c("numeric", "integer"), has_length = 1, allow_NULL = TRUE, is_positive = TRUE, is_finite = TRUE)
meet_criteria(colours, allow_class = c("character", "logical")) meet_criteria(colours, allow_class = c("character", "logical"), allow_NULL = TRUE)
meet_criteria(datalabels, allow_class = "logical", has_length = 1) meet_criteria(datalabels, allow_class = "logical", has_length = 1)
meet_criteria(datalabels.size, allow_class = c("numeric", "integer"), has_length = 1, is_positive = TRUE, is_finite = TRUE) meet_criteria(datalabels.size, allow_class = c("numeric", "integer"), has_length = 1, is_positive = TRUE, is_finite = TRUE)
meet_criteria(datalabels.colour, allow_class = "character", has_length = 1) meet_criteria(datalabels.colour, allow_class = "character", has_length = 1)
@@ -245,7 +246,7 @@ ggplot_sir <- function(data,
) + ) +
theme_sir() theme_sir()
if (fill == "interpretation") { if (fill == "interpretation" && !is.null(colours) && !isFALSE(colours)) {
p <- suppressWarnings(p + scale_sir_colours(aesthetics = "fill", colours = colours)) p <- suppressWarnings(p + scale_sir_colours(aesthetics = "fill", colours = colours))
} }

View File

@@ -31,7 +31,7 @@
#' #'
#' Calculates a normalised mean for antimicrobial resistance between multiple observations, to help to identify similar isolates without comparing antibiograms by hand. #' Calculates a normalised mean for antimicrobial resistance between multiple observations, to help to identify similar isolates without comparing antibiograms by hand.
#' @param x A vector of class [sir][as.sir()], [mic][as.mic()] or [disk][as.disk()], or a [data.frame] containing columns of any of these classes. #' @param x A vector of class [sir][as.sir()], [mic][as.mic()] or [disk][as.disk()], or a [data.frame] containing columns of any of these classes.
#' @param ... Variables to select. Supports [tidyselect language][tidyselect::language] (such as `column1:column4` and `where(is.mic)`), and can thus also be [antimicrobial selectors][amr_selector()]. #' @param ... Variables to select. Supports [tidyselect language][tidyselect::starts_with()] such as `where(is.mic)`, `starts_with(...)`, or `column1:column4`, and can thus also be [antimicrobial selectors][amr_selector()].
#' @param combine_SI A [logical] to indicate whether all values of S, SDD, and I must be merged into one, so the input only consists of S+I vs. R (susceptible vs. resistant) - the default is `TRUE`. #' @param combine_SI A [logical] to indicate whether all values of S, SDD, and I must be merged into one, so the input only consists of S+I vs. R (susceptible vs. resistant) - the default is `TRUE`.
#' @details The mean AMR distance is effectively [the Z-score](https://en.wikipedia.org/wiki/Standard_score); a normalised numeric value to compare AMR test results which can help to identify similar isolates, without comparing antibiograms by hand. #' @details The mean AMR distance is effectively [the Z-score](https://en.wikipedia.org/wiki/Standard_score); a normalised numeric value to compare AMR test results which can help to identify similar isolates, without comparing antibiograms by hand.
#' #'

2
R/mo.R
View File

@@ -1186,7 +1186,7 @@ parse_and_convert <- function(x) {
parsed <- gsub('"', "", parsed, fixed = TRUE) parsed <- gsub('"', "", parsed, fixed = TRUE)
parsed parsed
}, },
error = function(e) stop(e$message, call. = FALSE) error = function(e) stop(conditionMessage(e), call. = FALSE)
) # this will also be thrown when running `as.mo(no_existing_object)` ) # this will also be thrown when running `as.mo(no_existing_object)`
} }
out <- trimws2(out) out <- trimws2(out)

View File

@@ -974,7 +974,7 @@ mo_validate <- function(x, property, language, keep_synonyms = keep_synonyms, ..
# try to catch an error when inputting an invalid argument # try to catch an error when inputting an invalid argument
# so the 'call.' can be set to FALSE # so the 'call.' can be set to FALSE
tryCatch(x[1L] %in% unlist(AMR_env$MO_lookup[1, property, drop = TRUE]), tryCatch(x[1L] %in% unlist(AMR_env$MO_lookup[1, property, drop = TRUE]),
error = function(e) stop(e$message, call. = FALSE) error = function(e) stop(conditionMessage(e), call. = FALSE)
) )
dots <- list(...) dots <- list(...)

View File

@@ -99,7 +99,7 @@ pca <- function(x,
new_list <- list(0) new_list <- list(0)
for (i in seq_len(length(dots) - 1)) { for (i in seq_len(length(dots) - 1)) {
new_list[[i]] <- tryCatch(eval(dots[[i + 1]], envir = x), new_list[[i]] <- tryCatch(eval(dots[[i + 1]], envir = x),
error = function(e) stop(e$message, call. = FALSE) error = function(e) stop(conditionMessage(e), call. = FALSE)
) )
if (length(new_list[[i]]) == 1) { if (length(new_list[[i]]) == 1) {
if (is.character(new_list[[i]]) && new_list[[i]] %in% colnames(x)) { if (is.character(new_list[[i]]) && new_list[[i]] %in% colnames(x)) {

View File

@@ -90,6 +90,10 @@
#' autoplot(some_mic_values, mo = "Escherichia coli", ab = "cipro") #' autoplot(some_mic_values, mo = "Escherichia coli", ab = "cipro")
#' } #' }
#' if (require("ggplot2")) { #' if (require("ggplot2")) {
#' autoplot(some_mic_values, mo = "Staph aureus", ab = "Ceftaroline", guideline = "CLSI")
#' }
#'
#' if (require("ggplot2")) {
#' # support for 27 languages, various guidelines, and many options #' # support for 27 languages, various guidelines, and many options
#' autoplot(some_disk_values, #' autoplot(some_disk_values,
#' mo = "Escherichia coli", ab = "cipro", #' mo = "Escherichia coli", ab = "cipro",
@@ -146,7 +150,7 @@
#' aes(group, mic) #' aes(group, mic)
#' ) + #' ) +
#' geom_boxplot() + #' geom_boxplot() +
#' geom_violin(linetype = 2, colour = "grey", fill = NA) + #' geom_violin(linetype = 2, colour = "grey30", fill = NA) +
#' scale_y_mic() #' scale_y_mic()
#' } #' }
#' if (require("ggplot2")) { #' if (require("ggplot2")) {
@@ -158,7 +162,7 @@
#' aes(group, mic) #' aes(group, mic)
#' ) + #' ) +
#' geom_boxplot() + #' geom_boxplot() +
#' geom_violin(linetype = 2, colour = "grey", fill = NA) + #' geom_violin(linetype = 2, colour = "grey30", fill = NA) +
#' scale_y_mic(mic_range = c(NA, 0.25)) #' scale_y_mic(mic_range = c(NA, 0.25))
#' } #' }
#' #'
@@ -191,7 +195,7 @@
#' aes(x = group, y = mic, colour = sir) #' aes(x = group, y = mic, colour = sir)
#' ) + #' ) +
#' theme_minimal() + #' theme_minimal() +
#' geom_boxplot(fill = NA, colour = "grey") + #' geom_boxplot(fill = NA, colour = "grey30") +
#' geom_jitter(width = 0.25) #' geom_jitter(width = 0.25)
#' #'
#' plain #' plain
@@ -377,6 +381,8 @@ create_scale_sir <- function(aesthetics, colours_SIR, language, eucast_I, ...) {
args <- list(...) args <- list(...)
args[c("value", "labels", "limits")] <- NULL args[c("value", "labels", "limits")] <- NULL
colours_SIR <- expand_SIR_colours(colours_SIR, unname = FALSE)
if (identical(aesthetics, "x")) { if (identical(aesthetics, "x")) {
ggplot_fn <- ggplot2::scale_x_discrete ggplot_fn <- ggplot2::scale_x_discrete
} else { } else {
@@ -385,24 +391,19 @@ create_scale_sir <- function(aesthetics, colours_SIR, language, eucast_I, ...) {
args, args,
list( list(
aesthetics = aesthetics, aesthetics = aesthetics,
values = c( values = c(colours_SIR, NI = "grey30")
S = colours_SIR[1],
SDD = colours_SIR[2],
I = colours_SIR[2],
R = colours_SIR[3],
NI = "grey30"
)
) )
) )
} }
scale <- do.call(ggplot_fn, args) scale <- do.call(ggplot_fn, args)
scale$labels <- function(x) { scale$labels <- function(x) {
stop_ifnot(all(x %in% c(levels(NA_sir_), NA)), stop_ifnot(all(x %in% c(levels(NA_sir_), "SI", "IR", NA)),
"Apply `scale_", aesthetics[1], "_sir()` to a variable of class 'sir', see `?as.sir`.", "Apply `scale_", aesthetics[1], "_sir()` to a variable of class 'sir', see `?as.sir`.",
call = FALSE call = FALSE
) )
x <- as.character(as.sir(x)) x <- as.character(x)
x[!x %in% c("SI", "IR")] <- as.character(as.sir(x[!x %in% c("SI", "IR")]))
if (!is.null(language)) { if (!is.null(language)) {
x[x == "S"] <- "(S) Susceptible" x[x == "S"] <- "(S) Susceptible"
x[x == "SDD"] <- "(SDD) Susceptible dose-dependent" x[x == "SDD"] <- "(SDD) Susceptible dose-dependent"
@@ -412,6 +413,8 @@ create_scale_sir <- function(aesthetics, colours_SIR, language, eucast_I, ...) {
x[x == "I"] <- "(I) Intermediate" x[x == "I"] <- "(I) Intermediate"
} }
x[x == "R"] <- "(R) Resistant" x[x == "R"] <- "(R) Resistant"
x[x == "SI"] <- "(S/I) Susceptible"
x[x == "IR"] <- "(I/R) Non-susceptible"
x[x == "NI"] <- "(NI) Non-interpretable" x[x == "NI"] <- "(NI) Non-interpretable"
x <- translate_AMR(x, language = language) x <- translate_AMR(x, language = language)
} }
@@ -419,7 +422,7 @@ create_scale_sir <- function(aesthetics, colours_SIR, language, eucast_I, ...) {
} }
scale$limits <- function(x, ...) { scale$limits <- function(x, ...) {
# force SIR in the right order # force SIR in the right order
as.character(sort(factor(x, levels = levels(NA_sir_)))) as.character(sort(factor(x, levels = c(levels(NA_sir_), "SI", "IR"))))
} }
scale scale
@@ -427,11 +430,16 @@ create_scale_sir <- function(aesthetics, colours_SIR, language, eucast_I, ...) {
#' @rdname plot #' @rdname plot
#' @export #' @export
scale_x_sir <- function(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), scale_x_sir <- function(colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
eucast_I = getOption("AMR_guideline", "EUCAST") == "EUCAST", eucast_I = getOption("AMR_guideline", "EUCAST") == "EUCAST",
...) { ...) {
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
language <- validate_language(language) language <- validate_language(language)
meet_criteria(eucast_I, allow_class = "logical", has_length = 1) meet_criteria(eucast_I, allow_class = "logical", has_length = 1)
create_scale_sir(aesthetics = "x", colours_SIR = colours_SIR, language = language, eucast_I = eucast_I) create_scale_sir(aesthetics = "x", colours_SIR = colours_SIR, language = language, eucast_I = eucast_I)
@@ -439,11 +447,16 @@ scale_x_sir <- function(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
#' @rdname plot #' @rdname plot
#' @export #' @export
scale_colour_sir <- function(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), scale_colour_sir <- function(colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
eucast_I = getOption("AMR_guideline", "EUCAST") == "EUCAST", eucast_I = getOption("AMR_guideline", "EUCAST") == "EUCAST",
...) { ...) {
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
language <- validate_language(language) language <- validate_language(language)
meet_criteria(eucast_I, allow_class = "logical", has_length = 1) meet_criteria(eucast_I, allow_class = "logical", has_length = 1)
args <- list(...) args <- list(...)
@@ -463,11 +476,16 @@ scale_color_sir <- scale_colour_sir
#' @rdname plot #' @rdname plot
#' @export #' @export
scale_fill_sir <- function(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), scale_fill_sir <- function(colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
eucast_I = getOption("AMR_guideline", "EUCAST") == "EUCAST", eucast_I = getOption("AMR_guideline", "EUCAST") == "EUCAST",
...) { ...) {
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
language <- validate_language(language) language <- validate_language(language)
meet_criteria(eucast_I, allow_class = "logical", has_length = 1) meet_criteria(eucast_I, allow_class = "logical", has_length = 1)
args <- list(...) args <- list(...)
@@ -491,7 +509,12 @@ plot.mic <- function(x,
main = deparse(substitute(x)), main = deparse(substitute(x)),
ylab = translate_AMR("Frequency", language = language), ylab = translate_AMR("Frequency", language = language),
xlab = translate_AMR("Minimum Inhibitory Concentration (mg/L)", language = language), xlab = translate_AMR("Minimum Inhibitory Concentration (mg/L)", language = language),
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
expand = TRUE, expand = TRUE,
include_PKPD = getOption("AMR_include_PKPD", TRUE), include_PKPD = getOption("AMR_include_PKPD", TRUE),
@@ -503,16 +526,13 @@ plot.mic <- function(x,
meet_criteria(main, allow_class = "character", has_length = 1, allow_NULL = TRUE) meet_criteria(main, allow_class = "character", has_length = 1, allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1) meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1) meet_criteria(xlab, allow_class = "character", has_length = 1)
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
language <- validate_language(language) language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1) meet_criteria(expand, allow_class = "logical", has_length = 1)
x <- as.mic(x) # make sure that currently implemented MIC levels are used x <- as.mic(x) # make sure that currently implemented MIC levels are used
if (length(colours_SIR) == 1) {
colours_SIR <- rep(colours_SIR, 3)
}
main <- gsub(" +", " ", paste0(main, collapse = " ")) main <- gsub(" +", " ", paste0(main, collapse = " "))
colours_SIR <- expand_SIR_colours(colours_SIR)
x <- plotrange_as_table(x, expand = expand) x <- plotrange_as_table(x, expand = expand)
cols_sub <- plot_colours_subtitle_guideline( cols_sub <- plot_colours_subtitle_guideline(
@@ -549,13 +569,17 @@ plot.mic <- function(x,
legend_col <- colours_SIR[1] legend_col <- colours_SIR[1]
} }
if (any(cols_sub$cols == colours_SIR[2] & cols_sub$count > 0)) { if (any(cols_sub$cols == colours_SIR[2] & cols_sub$count > 0)) {
legend_txt <- c(legend_txt, paste("(I)", plot_name_of_I(cols_sub$guideline))) legend_txt <- c(legend_txt, "(SDD) Susceptible dose-dependent")
legend_col <- c(legend_col, colours_SIR[2]) legend_col <- c(legend_col, colours_SIR[2])
} }
if (any(cols_sub$cols == colours_SIR[3] & cols_sub$count > 0)) { if (any(cols_sub$cols == colours_SIR[3] & cols_sub$count > 0)) {
legend_txt <- c(legend_txt, "(R) Resistant") legend_txt <- c(legend_txt, paste("(I)", plot_name_of_I(cols_sub$guideline)))
legend_col <- c(legend_col, colours_SIR[3]) legend_col <- c(legend_col, colours_SIR[3])
} }
if (any(cols_sub$cols == colours_SIR[4] & cols_sub$count > 0)) {
legend_txt <- c(legend_txt, "(R) Resistant")
legend_col <- c(legend_col, colours_SIR[4])
}
legend("top", legend("top",
x.intersp = 0.5, x.intersp = 0.5,
@@ -580,7 +604,12 @@ barplot.mic <- function(height,
main = deparse(substitute(height)), main = deparse(substitute(height)),
ylab = translate_AMR("Frequency", language = language), ylab = translate_AMR("Frequency", language = language),
xlab = translate_AMR("Minimum Inhibitory Concentration (mg/L)", language = language), xlab = translate_AMR("Minimum Inhibitory Concentration (mg/L)", language = language),
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
expand = TRUE, expand = TRUE,
...) { ...) {
@@ -590,7 +619,7 @@ barplot.mic <- function(height,
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = 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(ab, allow_class = c("ab", "character"), allow_NULL = TRUE)
meet_criteria(guideline, allow_class = "character", has_length = 1) meet_criteria(guideline, allow_class = "character", has_length = 1)
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
language <- validate_language(language) language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1) meet_criteria(expand, allow_class = "logical", has_length = 1)
@@ -622,7 +651,12 @@ autoplot.mic <- function(object,
title = deparse(substitute(object)), title = deparse(substitute(object)),
ylab = translate_AMR("Frequency", language = language), ylab = translate_AMR("Frequency", language = language),
xlab = translate_AMR("Minimum Inhibitory Concentration (mg/L)", language = language), xlab = translate_AMR("Minimum Inhibitory Concentration (mg/L)", language = language),
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
expand = TRUE, expand = TRUE,
include_PKPD = getOption("AMR_include_PKPD", TRUE), include_PKPD = getOption("AMR_include_PKPD", TRUE),
@@ -635,7 +669,7 @@ autoplot.mic <- function(object,
meet_criteria(title, allow_class = "character", allow_NULL = TRUE) meet_criteria(title, allow_class = "character", allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1) meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1) meet_criteria(xlab, allow_class = "character", has_length = 1)
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
language <- validate_language(language) language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1) meet_criteria(expand, allow_class = "logical", has_length = 1)
@@ -646,6 +680,8 @@ autoplot.mic <- function(object,
title <- gsub(" +", " ", paste0(title, collapse = " ")) title <- gsub(" +", " ", paste0(title, collapse = " "))
} }
colours_SIR <- expand_SIR_colours(colours_SIR)
object <- as.mic(object) # make sure that currently implemented MIC levels are used object <- as.mic(object) # make sure that currently implemented MIC levels are used
x <- plotrange_as_table(object, expand = expand) x <- plotrange_as_table(object, expand = expand)
cols_sub <- plot_colours_subtitle_guideline( cols_sub <- plot_colours_subtitle_guideline(
@@ -665,12 +701,14 @@ autoplot.mic <- function(object,
colnames(df) <- c("mic", "count") colnames(df) <- c("mic", "count")
df$cols <- cols_sub$cols df$cols <- cols_sub$cols
df$cols[df$cols == colours_SIR[1]] <- "(S) Susceptible" df$cols[df$cols == colours_SIR[1]] <- "(S) Susceptible"
df$cols[df$cols == colours_SIR[2]] <- paste("(I)", plot_name_of_I(cols_sub$guideline)) df$cols[df$cols == colours_SIR[2]] <- "(SDD) Susceptible dose-dependent"
df$cols[df$cols == colours_SIR[3]] <- "(R) Resistant" df$cols[df$cols == colours_SIR[3]] <- paste("(I)", plot_name_of_I(cols_sub$guideline))
df$cols[df$cols == colours_SIR[4]] <- "(R) Resistant"
df$cols <- factor(translate_into_language(df$cols, language = language), df$cols <- factor(translate_into_language(df$cols, language = language),
levels = translate_into_language( levels = translate_into_language(
c( c(
"(S) Susceptible", "(S) Susceptible",
"(SDD) Susceptible dose-dependent",
paste("(I)", plot_name_of_I(cols_sub$guideline)), paste("(I)", plot_name_of_I(cols_sub$guideline)),
"(R) Resistant" "(R) Resistant"
), ),
@@ -684,10 +722,10 @@ autoplot.mic <- function(object,
vals <- c( vals <- c(
"(S) Susceptible" = colours_SIR[1], "(S) Susceptible" = colours_SIR[1],
"(SDD) Susceptible dose-dependent" = colours_SIR[2], "(SDD) Susceptible dose-dependent" = colours_SIR[2],
"(I) Susceptible, incr. exp." = colours_SIR[2], "(I) Susceptible, incr. exp." = colours_SIR[3],
"(I) Intermediate" = colours_SIR[2], "(I) Intermediate" = colours_SIR[3],
"(R) Resistant" = colours_SIR[3], "(R) Resistant" = colours_SIR[4],
"(NI) Non-interpretable" = "grey" "(NI) Non-interpretable" = "grey30"
) )
names(vals) <- translate_into_language(names(vals), language = language) names(vals) <- translate_into_language(names(vals), language = language)
p <- p + p <- p +
@@ -731,7 +769,12 @@ plot.disk <- function(x,
mo = NULL, mo = NULL,
ab = NULL, ab = NULL,
guideline = getOption("AMR_guideline", "EUCAST"), guideline = getOption("AMR_guideline", "EUCAST"),
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
expand = TRUE, expand = TRUE,
include_PKPD = getOption("AMR_include_PKPD", TRUE), include_PKPD = getOption("AMR_include_PKPD", TRUE),
@@ -743,14 +786,12 @@ plot.disk <- function(x,
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = 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(ab, allow_class = c("ab", "character"), allow_NULL = TRUE)
meet_criteria(guideline, allow_class = "character", has_length = 1) meet_criteria(guideline, allow_class = "character", has_length = 1)
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
language <- validate_language(language) language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1) meet_criteria(expand, allow_class = "logical", has_length = 1)
if (length(colours_SIR) == 1) {
colours_SIR <- rep(colours_SIR, 3)
}
main <- gsub(" +", " ", paste0(main, collapse = " ")) main <- gsub(" +", " ", paste0(main, collapse = " "))
colours_SIR <- expand_SIR_colours(colours_SIR)
x <- plotrange_as_table(x, expand = expand) x <- plotrange_as_table(x, expand = expand)
cols_sub <- plot_colours_subtitle_guideline( cols_sub <- plot_colours_subtitle_guideline(
@@ -783,12 +824,16 @@ plot.disk <- function(x,
if (any(colours_SIR %in% cols_sub$cols)) { if (any(colours_SIR %in% cols_sub$cols)) {
legend_txt <- character(0) legend_txt <- character(0)
legend_col <- character(0) legend_col <- character(0)
if (any(cols_sub$cols == colours_SIR[3] & cols_sub$count > 0)) { if (any(cols_sub$cols == colours_SIR[4] & cols_sub$count > 0)) {
legend_txt <- "(R) Resistant" legend_txt <- "(R) Resistant"
legend_col <- colours_SIR[3] legend_col <- colours_SIR[4]
}
if (any(cols_sub$cols == colours_SIR[3] & cols_sub$count > 0)) {
legend_txt <- c(legend_txt, paste("(I)", plot_name_of_I(cols_sub$guideline)))
legend_col <- c(legend_col, colours_SIR[3])
} }
if (any(cols_sub$cols == colours_SIR[2] & cols_sub$count > 0)) { if (any(cols_sub$cols == colours_SIR[2] & cols_sub$count > 0)) {
legend_txt <- c(legend_txt, paste("(I)", plot_name_of_I(cols_sub$guideline))) legend_txt <- c(legend_txt, "(SDD) Susceptible dose-dependent")
legend_col <- c(legend_col, colours_SIR[2]) legend_col <- c(legend_col, colours_SIR[2])
} }
if (any(cols_sub$cols == colours_SIR[1] & cols_sub$count > 0)) { if (any(cols_sub$cols == colours_SIR[1] & cols_sub$count > 0)) {
@@ -818,7 +863,12 @@ barplot.disk <- function(height,
mo = NULL, mo = NULL,
ab = NULL, ab = NULL,
guideline = getOption("AMR_guideline", "EUCAST"), guideline = getOption("AMR_guideline", "EUCAST"),
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
expand = TRUE, expand = TRUE,
...) { ...) {
@@ -828,7 +878,7 @@ barplot.disk <- function(height,
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = 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(ab, allow_class = c("ab", "character"), allow_NULL = TRUE)
meet_criteria(guideline, allow_class = "character", has_length = 1) meet_criteria(guideline, allow_class = "character", has_length = 1)
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
language <- validate_language(language) language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1) meet_criteria(expand, allow_class = "logical", has_length = 1)
@@ -858,7 +908,12 @@ autoplot.disk <- function(object,
ylab = translate_AMR("Frequency", language = language), ylab = translate_AMR("Frequency", language = language),
xlab = translate_AMR("Disk diffusion diameter (mm)", language = language), xlab = translate_AMR("Disk diffusion diameter (mm)", language = language),
guideline = getOption("AMR_guideline", "EUCAST"), guideline = getOption("AMR_guideline", "EUCAST"),
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
expand = TRUE, expand = TRUE,
include_PKPD = getOption("AMR_include_PKPD", TRUE), include_PKPD = getOption("AMR_include_PKPD", TRUE),
@@ -871,7 +926,7 @@ autoplot.disk <- function(object,
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = 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(ab, allow_class = c("ab", "character"), allow_NULL = TRUE)
meet_criteria(guideline, allow_class = "character", has_length = 1) meet_criteria(guideline, allow_class = "character", has_length = 1)
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
language <- validate_language(language) language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1) meet_criteria(expand, allow_class = "logical", has_length = 1)
@@ -882,6 +937,8 @@ autoplot.disk <- function(object,
title <- gsub(" +", " ", paste0(title, collapse = " ")) title <- gsub(" +", " ", paste0(title, collapse = " "))
} }
colours_SIR <- expand_SIR_colours(colours_SIR)
x <- plotrange_as_table(object, expand = expand) x <- plotrange_as_table(object, expand = expand)
cols_sub <- plot_colours_subtitle_guideline( cols_sub <- plot_colours_subtitle_guideline(
x = x, x = x,
@@ -899,10 +956,10 @@ autoplot.disk <- function(object,
df <- as.data.frame(x, stringsAsFactors = TRUE) df <- as.data.frame(x, stringsAsFactors = TRUE)
colnames(df) <- c("disk", "count") colnames(df) <- c("disk", "count")
df$cols <- cols_sub$cols df$cols <- cols_sub$cols
df$cols[df$cols == colours_SIR[1]] <- "(S) Susceptible" df$cols[df$cols == colours_SIR[1]] <- "(S) Susceptible"
df$cols[df$cols == colours_SIR[2]] <- paste("(I)", plot_name_of_I(cols_sub$guideline)) df$cols[df$cols == colours_SIR[2]] <- "(SDD) Susceptible dose-dependent"
df$cols[df$cols == colours_SIR[3]] <- "(R) Resistant" df$cols[df$cols == colours_SIR[3]] <- paste("(I)", plot_name_of_I(cols_sub$guideline))
df$cols[df$cols == colours_SIR[4]] <- "(R) Resistant"
df$cols <- factor(translate_into_language(df$cols, language = language), df$cols <- factor(translate_into_language(df$cols, language = language),
levels = translate_into_language( levels = translate_into_language(
c( c(
@@ -920,10 +977,10 @@ autoplot.disk <- function(object,
vals <- c( vals <- c(
"(S) Susceptible" = colours_SIR[1], "(S) Susceptible" = colours_SIR[1],
"(SDD) Susceptible dose-dependent" = colours_SIR[2], "(SDD) Susceptible dose-dependent" = colours_SIR[2],
"(I) Susceptible, incr. exp." = colours_SIR[2], "(I) Susceptible, incr. exp." = colours_SIR[3],
"(I) Intermediate" = colours_SIR[2], "(I) Intermediate" = colours_SIR[3],
"(R) Resistant" = colours_SIR[3], "(R) Resistant" = colours_SIR[4],
"(NI) Non-interpretable" = "grey" "(NI) Non-interpretable" = "grey30"
) )
names(vals) <- translate_into_language(names(vals), language = language) names(vals) <- translate_into_language(names(vals), language = language)
p <- p + p <- p +
@@ -1024,22 +1081,26 @@ barplot.sir <- function(height,
main = deparse(substitute(height)), main = deparse(substitute(height)),
xlab = translate_AMR("Antimicrobial Interpretation", language = language), xlab = translate_AMR("Antimicrobial Interpretation", language = language),
ylab = translate_AMR("Frequency", language = language), ylab = translate_AMR("Frequency", language = language),
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
expand = TRUE, expand = TRUE,
...) { ...) {
meet_criteria(xlab, 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) meet_criteria(main, allow_class = "character", has_length = 1, allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1) meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
language <- validate_language(language) language <- validate_language(language)
meet_criteria(expand, allow_class = "logical", has_length = 1) meet_criteria(expand, allow_class = "logical", has_length = 1)
if (length(colours_SIR) == 1) { colours_SIR <- expand_SIR_colours(colours_SIR)
colours_SIR <- rep(colours_SIR, 3)
}
# add SDD and N to colours # add SDD and N to colours
colours_SIR <- c(colours_SIR[1:2], colours_SIR[2], colours_SIR[3], "#888888") colours_SIR <- c(colours_SIR, "grey30")
main <- gsub(" +", " ", paste0(main, collapse = " ")) main <- gsub(" +", " ", paste0(main, collapse = " "))
x <- table(height) x <- table(height)
@@ -1065,14 +1126,19 @@ autoplot.sir <- function(object,
title = deparse(substitute(object)), title = deparse(substitute(object)),
xlab = translate_AMR("Antimicrobial Interpretation", language = language), xlab = translate_AMR("Antimicrobial Interpretation", language = language),
ylab = translate_AMR("Frequency", language = language), ylab = translate_AMR("Frequency", language = language),
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
),
language = get_AMR_locale(), language = get_AMR_locale(),
...) { ...) {
stop_ifnot_installed("ggplot2") stop_ifnot_installed("ggplot2")
meet_criteria(title, allow_class = "character", allow_NULL = TRUE) meet_criteria(title, allow_class = "character", allow_NULL = TRUE)
meet_criteria(ylab, allow_class = "character", has_length = 1) meet_criteria(ylab, allow_class = "character", has_length = 1)
meet_criteria(xlab, allow_class = "character", has_length = 1) meet_criteria(xlab, allow_class = "character", has_length = 1)
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
if ("main" %in% names(list(...))) { if ("main" %in% names(list(...))) {
title <- list(...)$main title <- list(...)$main
@@ -1081,9 +1147,7 @@ autoplot.sir <- function(object,
title <- gsub(" +", " ", paste0(title, collapse = " ")) title <- gsub(" +", " ", paste0(title, collapse = " "))
} }
if (length(colours_SIR) == 1) { colours_SIR <- expand_SIR_colours(colours_SIR)
colours_SIR <- rep(colours_SIR, 3)
}
df <- as.data.frame(table(object), stringsAsFactors = TRUE) df <- as.data.frame(table(object), stringsAsFactors = TRUE)
colnames(df) <- c("x", "n") colnames(df) <- c("x", "n")
@@ -1095,9 +1159,9 @@ autoplot.sir <- function(object,
values = c( values = c(
"S" = colours_SIR[1], "S" = colours_SIR[1],
"SDD" = colours_SIR[2], "SDD" = colours_SIR[2],
"I" = colours_SIR[2], "I" = colours_SIR[3],
"R" = colours_SIR[3], "R" = colours_SIR[4],
"NI" = "#888888" "NI" = "grey30"
), ),
limits = force limits = force
) + ) +
@@ -1223,9 +1287,9 @@ plot_colours_subtitle_guideline <- function(x, mo, ab, guideline, colours_SIR, f
cols[is.na(sir)] <- "#BEBEBE" cols[is.na(sir)] <- "#BEBEBE"
cols[sir == "S"] <- colours_SIR[1] cols[sir == "S"] <- colours_SIR[1]
cols[sir == "SDD"] <- colours_SIR[2] cols[sir == "SDD"] <- colours_SIR[2]
cols[sir == "I"] <- colours_SIR[2] cols[sir == "I"] <- colours_SIR[3]
cols[sir == "R"] <- colours_SIR[3] cols[sir == "R"] <- colours_SIR[4]
cols[sir == "NI"] <- "#888888" cols[sir == "NI"] <- "grey30"
sub <- bquote(.(abname) ~ "-" ~ italic(.(moname)) ~ .(guideline_txt)) sub <- bquote(.(abname) ~ "-" ~ italic(.(moname)) ~ .(guideline_txt))
} else { } else {
cols <- "#BEBEBE" cols <- "#BEBEBE"
@@ -1284,10 +1348,15 @@ scale_y_percent <- function(breaks = function(x) seq(0, max(x, na.rm = TRUE), 0.
#' @export #' @export
scale_sir_colours <- function(..., scale_sir_colours <- function(...,
aesthetics, aesthetics,
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B")) { colours_SIR = c(
S = "#3CAEA3",
SDD = "#8FD6C4",
I = "#F6D55C",
R = "#ED553B"
)) {
stop_ifnot_installed("ggplot2") stop_ifnot_installed("ggplot2")
meet_criteria(aesthetics, allow_class = "character", is_in = c("alpha", "colour", "color", "fill", "linetype", "shape", "size")) meet_criteria(aesthetics, allow_class = "character", is_in = c("alpha", "colour", "color", "fill", "linetype", "shape", "size"))
meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3)) meet_criteria(colours_SIR, allow_class = "character", has_length = c(1, 3, 4))
if ("fill" %in% aesthetics && message_not_thrown_before("scale_sir_colours", "fill", entire_session = TRUE)) { if ("fill" %in% aesthetics && message_not_thrown_before("scale_sir_colours", "fill", entire_session = TRUE)) {
warning_("Using `scale_sir_colours()` for the `fill` aesthetic has been superseded by `scale_fill_sir()`, please use that instead. This warning will be shown once per session.") warning_("Using `scale_sir_colours()` for the `fill` aesthetic has been superseded by `scale_fill_sir()`, please use that instead. This warning will be shown once per session.")
@@ -1296,67 +1365,48 @@ scale_sir_colours <- function(...,
warning_("Using `scale_sir_colours()` for the `colour` aesthetic has been superseded by `scale_colour_sir()`, please use that instead. This warning will be shown once per session.") warning_("Using `scale_sir_colours()` for the `colour` aesthetic has been superseded by `scale_colour_sir()`, please use that instead. This warning will be shown once per session.")
} }
if (length(colours_SIR) == 1) {
colours_SIR <- rep(colours_SIR, 3)
}
# behaviour until AMR pkg v1.5.0 and also when coming from ggplot_sir()
if ("colours" %in% names(list(...))) { if ("colours" %in% names(list(...))) {
original_cols <- c( colours_SIR <- list(...)$colours
S = colours_SIR[1], }
SI = colours_SIR[1],
I = colours_SIR[2], colours_SIR <- expand_SIR_colours(colours_SIR, unname = FALSE)
IR = colours_SIR[3],
R = colours_SIR[3] # behaviour when coming from ggplot_sir()
) if ("colours" %in% names(list(...))) {
colours <- replace(original_cols, names(list(...)$colours), list(...)$colours)
# limits = force is needed in ggplot2 3.3.4 and 3.3.5, see here; # limits = force is needed in ggplot2 3.3.4 and 3.3.5, see here;
# https://github.com/tidyverse/ggplot2/issues/4511#issuecomment-866185530 # https://github.com/tidyverse/ggplot2/issues/4511#issuecomment-866185530
return(ggplot2::scale_fill_manual(values = colours, limits = force, aesthetics = aesthetics)) return(ggplot2::scale_fill_manual(values = colours_SIR, limits = force, aesthetics = aesthetics))
} }
if (identical(unlist(list(...)), FALSE)) { if (identical(unlist(list(...)), FALSE)) {
return(invisible()) return(invisible())
} }
names_susceptible <- c( colours_SIR <- unname(colours_SIR)
"S", "SI", "IS", "S+I", "I+S", "susceptible", "Susceptible",
unique(TRANSLATIONS[which(TRANSLATIONS$pattern == "Susceptible"), names_susceptible <- c("S", "SI", "IS", "S+I", "I+S", "susceptible", "Susceptible")
"replacement", names_susceptible_dose_dep <- c("SDD", "susceptible dose-dependent", "Susceptible dose-dependent")
drop = TRUE
])
)
names_incr_exposure <- c( names_incr_exposure <- c(
"I", "intermediate", "increased exposure", "incr. exposure", "I", "intermediate", "increased exposure", "incr. exposure",
"Increased exposure", "Incr. exposure", "Susceptible, incr. exp.", "Increased exposure", "Incr. exposure", "Susceptible, incr. exp."
unique(TRANSLATIONS[which(TRANSLATIONS$pattern == "Intermediate"),
"replacement",
drop = TRUE
]),
unique(TRANSLATIONS[which(TRANSLATIONS$pattern == "Susceptible, incr. exp."),
"replacement",
drop = TRUE
])
)
names_resistant <- c(
"R", "IR", "RI", "R+I", "I+R", "resistant", "Resistant",
unique(TRANSLATIONS[which(TRANSLATIONS$pattern == "Resistant"),
"replacement",
drop = TRUE
])
) )
names_resistant <- c("R", "IR", "RI", "R+I", "I+R", "resistant", "Resistant")
susceptible <- rep(colours_SIR[1], length(names_susceptible)) susceptible <- rep(colours_SIR[1], length(names_susceptible))
names(susceptible) <- names_susceptible names(susceptible) <- names_susceptible
incr_exposure <- rep(colours_SIR[2], length(names_incr_exposure)) susceptible_dose_dep <- rep(colours_SIR[2], length(names_susceptible_dose_dep))
names(susceptible_dose_dep) <- names_susceptible_dose_dep
incr_exposure <- rep(colours_SIR[3], length(names_incr_exposure))
names(incr_exposure) <- names_incr_exposure names(incr_exposure) <- names_incr_exposure
resistant <- rep(colours_SIR[3], length(names_resistant)) resistant <- rep(colours_SIR[4], length(names_resistant))
names(resistant) <- names_resistant names(resistant) <- names_resistant
original_cols <- c(susceptible, incr_exposure, resistant) original_cols <- c(susceptible, susceptible_dose_dep, incr_exposure, resistant)
dots <- c(...) dots <- c(...)
# replace S, I, R as colours: scale_sir_colours(mydatavalue = "S") # replace S, SDD, I, R as colours: scale_sir_colours(mydatavalue = "S")
dots[dots == "S"] <- colours_SIR[1] dots[dots == "S"] <- colours_SIR[1]
dots[dots == "I"] <- colours_SIR[2] dots[dots == "SDD"] <- colours_SIR[2]
dots[dots == "R"] <- colours_SIR[3] dots[dots == "I"] <- colours_SIR[3]
dots[dots == "R"] <- colours_SIR[4]
cols <- replace(original_cols, names(dots), dots) cols <- replace(original_cols, names(dots), dots)
# limits = force is needed in ggplot2 3.3.4 and 3.3.5, see here; # limits = force is needed in ggplot2 3.3.4 and 3.3.5, see here;
# https://github.com/tidyverse/ggplot2/issues/4511#issuecomment-866185530 # https://github.com/tidyverse/ggplot2/issues/4511#issuecomment-866185530
@@ -1435,3 +1485,39 @@ labels_sir_count <- function(position = NULL,
} }
) )
} }
expand_SIR_colours <- function(colours_SIR, unname = TRUE) {
sir_order <- c("S", "SDD", "I", "R", "SI", "IR")
if (is.null(names(colours_SIR))) {
if (length(colours_SIR) == 1) {
colours_SIR <- rep(colours_SIR, 4)
} else if (length(colours_SIR) == 3) {
# old method for AMR < 3.0.1 which allowed for 3 colours
# fill in green for SDD as extra colour
colours_SIR <- c(colours_SIR[1], colours_SIR[1], colours_SIR[2], colours_SIR[3])
}
if (length(colours_SIR) == 4) {
# add colours for SI (same as S) and IR (same as R)
colours_SIR <- c(colours_SIR[1:4], colours_SIR[1], colours_SIR[4])
}
names(colours_SIR) <- sir_order
} else {
# named input: match and reorder
stop_ifnot(
all(names(colours_SIR) %in% sir_order),
"Unknown names in `colours_SIR`. Expected any of: ", vector_or(levels(NA_sir_), quotes = FALSE, sort = FALSE), "."
)
if (length(colours_SIR) == 4) {
# add colours for SI (same as S) and IR (same as R)
colours_SIR <- c(colours_SIR[1:4], SI = unname(colours_SIR[1]), IR = unname(colours_SIR[4]))
}
colours_SIR <- colours_SIR[sir_order]
}
if (unname) {
colours_SIR <- unname(colours_SIR)
}
return(colours_SIR)
}

View File

@@ -237,7 +237,7 @@ resistance <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -255,7 +255,7 @@ susceptibility <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -283,7 +283,7 @@ sir_confidence_interval <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
n <- tryCatch( n <- tryCatch(
sir_calc(..., sir_calc(...,
@@ -291,7 +291,7 @@ sir_confidence_interval <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
if (x == 0) { if (x == 0) {
@@ -347,7 +347,7 @@ proportion_R <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -365,7 +365,7 @@ proportion_IR <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -383,7 +383,7 @@ proportion_I <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -401,7 +401,7 @@ proportion_SI <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -419,7 +419,7 @@ proportion_S <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }
@@ -443,6 +443,6 @@ proportion_df <- function(data,
combine_SI = combine_SI, combine_SI = combine_SI,
confidence_level = confidence_level confidence_level = confidence_level
), ),
error = function(e) stop_(gsub("in sir_calc_df(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc_df(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }

333
R/sir.R
View File

@@ -69,7 +69,9 @@
#' @param reference_data A [data.frame] to be used for interpretation, which defaults to the [clinical_breakpoints] data set. Changing this argument allows for using own interpretation guidelines. This argument must contain a data set that is equal in structure to the [clinical_breakpoints] data set (same column names and column types). Please note that the `guideline` argument will be ignored when `reference_data` is manually set. #' @param reference_data A [data.frame] to be used for interpretation, which defaults to the [clinical_breakpoints] data set. Changing this argument allows for using own interpretation guidelines. This argument must contain a data set that is equal in structure to the [clinical_breakpoints] data set (same column names and column types). Please note that the `guideline` argument will be ignored when `reference_data` is manually set.
#' @param threshold Maximum fraction of invalid antimicrobial interpretations of `x`, see *Examples*. #' @param threshold Maximum fraction of invalid antimicrobial interpretations of `x`, see *Examples*.
#' @param conserve_capped_values Deprecated, use `capped_mic_handling` instead. #' @param conserve_capped_values Deprecated, use `capped_mic_handling` instead.
#' @param ... For using on a [data.frame]: names of columns to apply [as.sir()] on (supports tidy selection such as `column1:column4`). Otherwise: arguments passed on to methods. #' @param ... For using on a [data.frame]: selection of columns to apply `as.sir()` to. Supports [tidyselect language][tidyselect::starts_with()] such as `where(is.mic)`, `starts_with(...)`, or `column1:column4`, and can thus also be [antimicrobial selectors][amr_selector()] such as `as.sir(df, penicillins())`.
#'
#' Otherwise: arguments passed on to methods.
#' @details #' @details
#' *Note: The clinical breakpoints in this package were validated through, and imported from, [WHONET](https://whonet.org). The public use of this `AMR` package has been endorsed by both CLSI and EUCAST. See [clinical_breakpoints] for more information.* #' *Note: The clinical breakpoints in this package were validated through, and imported from, [WHONET](https://whonet.org). The public use of this `AMR` package has been endorsed by both CLSI and EUCAST. See [clinical_breakpoints] for more information.*
#' #'
@@ -225,9 +227,12 @@
#' df_wide %>% mutate_if(is.mic, as.sir) #' df_wide %>% mutate_if(is.mic, as.sir)
#' df_wide %>% mutate_if(function(x) is.mic(x) | is.disk(x), as.sir) #' df_wide %>% mutate_if(function(x) is.mic(x) | is.disk(x), as.sir)
#' df_wide %>% mutate(across(where(is.mic), as.sir)) #' df_wide %>% mutate(across(where(is.mic), as.sir))
#'
#' df_wide %>% mutate_at(vars(amoxicillin:tobra), as.sir) #' df_wide %>% mutate_at(vars(amoxicillin:tobra), as.sir)
#' df_wide %>% mutate(across(amoxicillin:tobra, as.sir)) #' df_wide %>% mutate(across(amoxicillin:tobra, as.sir))
#' #'
#' df_wide %>% mutate(across(aminopenicillins(), as.sir))
#'
#' # approaches that all work with additional arguments: #' # approaches that all work with additional arguments:
#' df_long %>% #' df_long %>%
#' # given a certain data type, e.g. MIC values #' # given a certain data type, e.g. MIC values
@@ -380,26 +385,15 @@ as.sir <- function(x, ...) {
UseMethod("as.sir") UseMethod("as.sir")
} }
as_sir_structure <- function(x, as_sir_structure <- function(x) {
guideline = NULL, int <- attr(x, "interpretation_details")
mo = NULL,
ab = NULL,
method = NULL,
ref_tbl = NULL,
ref_breakpoints = NULL) {
structure( structure(
factor(as.character(unlist(unname(x))), factor(as.character(unlist(unname(x))),
levels = c("S", "SDD", "I", "R", "NI"), levels = c("S", "SDD", "I", "R", "NI"),
ordered = TRUE ordered = TRUE
), ),
# TODO for #170 interpretation_details = int,
# guideline = guideline, class = c(if (!is.null(int)) "interpreted_sir" else NULL, "sir", "ordered", "factor")
# mo = mo,
# ab = ab,
# method = method,
# ref_tbl = ref_tbl,
# ref_breakpoints = ref_breakpoints,
class = c("sir", "ordered", "factor")
) )
} }
@@ -722,8 +716,17 @@ as.sir.data.frame <- function(x,
meet_criteria(info, allow_class = "logical", has_length = 1) meet_criteria(info, allow_class = "logical", has_length = 1)
meet_criteria(parallel, allow_class = "logical", has_length = 1) meet_criteria(parallel, allow_class = "logical", has_length = 1)
meet_criteria(max_cores, allow_class = c("numeric", "integer"), has_length = 1) meet_criteria(max_cores, allow_class = c("numeric", "integer"), has_length = 1)
x.bak <- x x.bak <- x
if (tryCatch(length(list(...)) > 0, error = function(e) TRUE)) {
sel <- colnames(pm_select(x, ...))
} else {
sel <- colnames(x)
}
if (!is.null(col_mo)) {
sel <- sel[sel != col_mo]
}
for (i in seq_len(ncol(x))) { for (i in seq_len(ncol(x))) {
# don't keep factors, overwriting them is hard # don't keep factors, overwriting them is hard
if (is.factor(x[, i, drop = TRUE])) { if (is.factor(x[, i, drop = TRUE])) {
@@ -803,15 +806,6 @@ as.sir.data.frame <- function(x,
} }
i <- 0 i <- 0
if (tryCatch(length(list(...)) > 0, error = function(e) TRUE)) {
sel <- colnames(pm_select(x, ...))
} else {
sel <- colnames(x)
}
if (!is.null(col_mo)) {
sel <- sel[sel != col_mo]
}
ab_cols <- colnames(x)[vapply(FUN.VALUE = logical(1), x, function(y) { ab_cols <- colnames(x)[vapply(FUN.VALUE = logical(1), x, function(y) {
i <<- i + 1 i <<- i + 1
check <- is.mic(y) | is.disk(y) check <- is.mic(y) | is.disk(y)
@@ -863,7 +857,7 @@ as.sir.data.frame <- function(x,
cl <- tryCatch(parallel::makeCluster(n_cores, type = "PSOCK"), cl <- tryCatch(parallel::makeCluster(n_cores, type = "PSOCK"),
error = function(e) { error = function(e) {
if (isTRUE(info)) { if (isTRUE(info)) {
message_("Could not create parallel cluster, using single-core computation. Error message: ", e$message, add_fn = font_red) message_("Could not create parallel cluster, using single-core computation. Error message: ", conditionMessage(e), add_fn = font_red)
} }
return(NULL) return(NULL)
} }
@@ -1135,7 +1129,6 @@ as_sir_method <- function(method_short,
current_sir_interpretation_history <- NROW(AMR_env$sir_interpretation_history) current_sir_interpretation_history <- NROW(AMR_env$sir_interpretation_history)
if (isTRUE(info) && message_not_thrown_before("as.sir", "sir_interpretation_history")) { if (isTRUE(info) && message_not_thrown_before("as.sir", "sir_interpretation_history")) {
message()
message_("Run `sir_interpretation_history()` afterwards to retrieve a logbook with all details of the breakpoint interpretations.\n\n", add_fn = font_green) message_("Run `sir_interpretation_history()` afterwards to retrieve a logbook with all details of the breakpoint interpretations.\n\n", add_fn = font_green)
} }
@@ -1553,7 +1546,7 @@ as_sir_method <- function(method_short,
)) ))
if (breakpoint_type == "animal") { if (breakpoint_type == "animal") {
# 2025-03-13 for now, only strictly follow guideline for current host, no extrapolation # 2025-03-13/ for now, only strictly follow guideline for current host, no extrapolation
breakpoints_current <- breakpoints_current[which(breakpoints_current$host == host_current), , drop = FALSE] breakpoints_current <- breakpoints_current[which(breakpoints_current$host == host_current), , drop = FALSE]
} }
@@ -1645,32 +1638,31 @@ as_sir_method <- function(method_short,
breakpoint_S_R = vectorise_log_entry(NA_character_, length(rows)), breakpoint_S_R = vectorise_log_entry(NA_character_, length(rows)),
stringsAsFactors = FALSE stringsAsFactors = FALSE
) )
attr(new_sir, "interpretation_details") <- out
out <- subset(out, !is.na(input_given)) out <- subset(out, !is.na(input_given))
AMR_env$sir_interpretation_history <- rbind_AMR(AMR_env$sir_interpretation_history, out) AMR_env$sir_interpretation_history <- rbind_AMR(AMR_env$sir_interpretation_history, out)
notes <- c(notes, notes_current) notes <- c(notes, notes_current)
df[rows, "result"] <- new_sir
next next
} }
# sort on host and taxonomic rank # if the user explicitly set uti, keep only those rows
# (this will e.g. prefer 'species' breakpoints over 'order' breakpoints) if (!is.na(uti_current)) {
if (is.na(uti_current)) { breakpoints_current <- breakpoints_current[breakpoints_current$uti == uti_current, , drop = FALSE]
breakpoints_current <- breakpoints_current %pm>%
# `uti` is a column in the data set
# this will put UTI = FALSE first, then UTI = NA, then UTI = TRUE
pm_mutate(uti_index = ifelse(!is.na(uti) & uti == FALSE, 1,
ifelse(is.na(uti), 2,
3
)
)) %pm>%
# be as specific as possible (i.e. prefer species over genus):
pm_arrange(rank_index, uti_index)
} else if (uti_current == TRUE) {
breakpoints_current <- breakpoints_current %pm>%
subset(uti == TRUE) %pm>%
# be as specific as possible (i.e. prefer species over genus):
pm_arrange(rank_index)
} }
# build a helper factor so FALSE < NA < TRUE
uti_index <- factor(
ifelse(is.na(breakpoints_current$uti), "NA",
as.character(breakpoints_current$uti)
),
levels = c("FALSE", "NA", "TRUE")
)
# sort on host and taxonomic rank first, then by UTI
# (this will e.g. prefer 'species' breakpoints over 'order' breakpoints)
breakpoints_current <- breakpoints_current[order(breakpoints_current$rank_index, uti_index), , drop = FALSE]
# throw messages for different body sites # throw messages for different body sites
site <- breakpoints_current[1L, "site", drop = FALSE] # this is the one we'll take site <- breakpoints_current[1L, "site", drop = FALSE] # this is the one we'll take
if (is.na(site)) { if (is.na(site)) {
@@ -1682,7 +1674,7 @@ as_sir_method <- function(method_short,
# only UTI breakpoints available # only UTI breakpoints available
notes_current <- paste0( notes_current <- paste0(
notes_current, "\n", notes_current, "\n",
paste0("Breakpoints for ", font_bold(ab_formatted), " in ", mo_formatted, " are only available for (uncomplicated) urinary tract infections (UTI); assuming `uti = TRUE`.") paste0("Breakpoints for ", font_bold(ab_formatted), " in ", mo_formatted, " are only available for (uncomplicated) urinary tract infections (UTI) - assuming `uti = TRUE`.")
) )
} else if (nrow(breakpoints_current) > 1 && length(unique(breakpoints_current$site)) > 1 && any(is.na(uti_current)) && all(c(TRUE, FALSE) %in% breakpoints_current$uti, na.rm = TRUE) && message_not_thrown_before("as.sir", "siteUTI", mo_current, ab_current)) { } else if (nrow(breakpoints_current) > 1 && length(unique(breakpoints_current$site)) > 1 && any(is.na(uti_current)) && all(c(TRUE, FALSE) %in% breakpoints_current$uti, na.rm = TRUE) && message_not_thrown_before("as.sir", "siteUTI", mo_current, ab_current)) {
# both UTI and Non-UTI breakpoints available # both UTI and Non-UTI breakpoints available
@@ -1705,7 +1697,7 @@ as_sir_method <- function(method_short,
new_sir <- rep(as.sir("R"), length(rows)) new_sir <- rep(as.sir("R"), length(rows))
notes_current <- paste0( notes_current <- paste0(
notes_current, "\n", notes_current, "\n",
paste0("Intrinsic resistance applied for ", ab_formatted, " in ", mo_formatted, "") paste0("Intrinsic resistance applied for ", ab_formatted, " in ", mo_formatted, ".")
) )
} else if (nrow(breakpoints_current) == 0) { } else if (nrow(breakpoints_current) == 0) {
# no rules available # no rules available
@@ -1713,41 +1705,48 @@ as_sir_method <- function(method_short,
} else { } else {
# then run the rules # then run the rules
breakpoints_current <- breakpoints_current[1L, , drop = FALSE] breakpoints_current <- breakpoints_current[1L, , drop = FALSE]
if (breakpoints_current$rank_index > 3) {
# we resort to a high-level taxonomic record since there are no breakpoint on genus (rank_index = 3) or lower, so note this
notes_current <- paste0(
"No genus- or species-level breakpoint available - applying higher taxonomic level instead.\n",
notes_current
)
}
notes_current <- paste0( notes_current <- paste0(
notes_current, "\n", notes_current, "\n",
ifelse(breakpoints_current$mo == "UNKNOWN" | breakpoints_current$ref_tbl %like% "PK.*PD", ifelse(breakpoints_current$mo == "UNKNOWN" | breakpoints_current$ref_tbl %like% "PK.*PD",
"Some PK/PD breakpoints were applied - use `include_PKPD = FALSE` to prevent this", "Some PK/PD breakpoints were applied - use `include_PKPD = FALSE` to prevent this.",
"" ""
), ),
"\n", "\n",
ifelse(breakpoints_current$site %like% "screen" | breakpoints_current$ref_tbl %like% "screen", ifelse(breakpoints_current$site %like% "screen" | breakpoints_current$ref_tbl %like% "screen",
"Some screening breakpoints were applied - use `include_screening = FALSE` to prevent this", "Some screening breakpoints were applied - use `include_screening = FALSE` to prevent this.",
"" ""
), ),
"\n", "\n",
ifelse(method == "mic" & capped_mic_handling %in% c("conservative", "inverse") & as.character(values_bak) %like% "^[<][0-9]", ifelse(method == "mic" & capped_mic_handling %in% c("conservative", "inverse") & as.character(values_bak) %like% "^[<][0-9]",
paste0("MIC values with the operator '<' are all considered 'S' since capped_mic_handling = \"", capped_mic_handling, "\""), paste0("MIC values with the operator '<' are all considered 'S' since capped_mic_handling = \"", capped_mic_handling, "\"."),
"" ""
), ),
"\n", "\n",
ifelse(method == "mic" & capped_mic_handling %in% c("conservative", "inverse") & as.character(values_bak) %like% "^[>][0-9]", ifelse(method == "mic" & capped_mic_handling %in% c("conservative", "inverse") & as.character(values_bak) %like% "^[>][0-9]",
paste0("MIC values with the operator '>' are all considered 'R' since capped_mic_handling = \"", capped_mic_handling, "\""), paste0("MIC values with the operator '>' are all considered 'R' since capped_mic_handling = \"", capped_mic_handling, "\"."),
"" ""
), ),
"\n", "\n",
ifelse(method == "mic" & capped_mic_handling %in% c("conservative", "standard") & as.character(values_bak) %like% "^[><]=[0-9]" & as.double(values) > breakpoints_current$breakpoint_S & as.double(values) < breakpoints_current$breakpoint_R, ifelse(method == "mic" & capped_mic_handling %in% c("conservative", "standard") & as.character(values_bak) %like% "^[><]=[0-9]" & as.double(values) > breakpoints_current$breakpoint_S & as.double(values) < breakpoints_current$breakpoint_R,
paste0("MIC values within the breakpoint guideline range with the operator '<=' or '>=' are considered 'NI' (non-interpretable) since capped_mic_handling = \"", capped_mic_handling, "\""), paste0("MIC values within the breakpoint guideline range with the operator '<=' or '>=' are considered 'NI' (non-interpretable) since capped_mic_handling = \"", capped_mic_handling, "\"."),
"" ""
), ),
"\n", "\n",
ifelse(method == "mic" & capped_mic_handling %in% c("conservative", "standard") & as.character(values_bak) %like% "^<=[0-9]" & as.double(values) == breakpoints_current$breakpoint_R, ifelse(method == "mic" & capped_mic_handling %in% c("conservative", "standard") & as.character(values_bak) %like% "^<=[0-9]" & as.double(values) == breakpoints_current$breakpoint_R,
paste0("MIC values at the R breakpoint with the operator '<=' are considered 'NI' (non-interpretable) since capped_mic_handling = \"", capped_mic_handling, "\""), paste0("MIC values at the R breakpoint with the operator '<=' are considered 'NI' (non-interpretable) since capped_mic_handling = \"", capped_mic_handling, "\"."),
"" ""
), ),
"\n", "\n",
ifelse(method == "mic" & capped_mic_handling %in% c("conservative", "standard") & as.character(values_bak) %like% "^>=[0-9]" & as.double(values) == breakpoints_current$breakpoint_S, ifelse(method == "mic" & capped_mic_handling %in% c("conservative", "standard") & as.character(values_bak) %like% "^>=[0-9]" & as.double(values) == breakpoints_current$breakpoint_S,
paste0("MIC values at the S breakpoint with the operator '>=' are considered 'NI' (non-interpretable) since capped_mic_handling = \"", capped_mic_handling, "\""), paste0("MIC values at the S breakpoint with the operator '>=' are considered 'NI' (non-interpretable) since capped_mic_handling = \"", capped_mic_handling, "\"."),
"" ""
) )
) )
@@ -1757,7 +1756,7 @@ as_sir_method <- function(method_short,
notes_current <- paste0( notes_current <- paste0(
notes_current, "\n", notes_current, "\n",
ifelse(!is.na(breakpoints_current$breakpoint_S) & is.na(breakpoints_current$breakpoint_R), ifelse(!is.na(breakpoints_current$breakpoint_S) & is.na(breakpoints_current$breakpoint_R),
"NAs because of missing R breakpoints were substituted with R since substitute_missing_r_breakpoint = TRUE", "NAs because of missing R breakpoints were substituted with R since substitute_missing_r_breakpoint = TRUE.",
"" ""
) )
) )
@@ -1796,7 +1795,7 @@ as_sir_method <- function(method_short,
} }
# write to verbose output # write to verbose output
notes_current <- trimws2(notes_current) notes_current <- gsub("\n\n", "\n", trimws2(notes_current), fixed = TRUE)
notes_current[notes_current == ""] <- NA_character_ notes_current[notes_current == ""] <- NA_character_
out <- data.frame( out <- data.frame(
# recycling 1 to 2 rows does not always seem to work, which is why vectorise_log_entry() was added # recycling 1 to 2 rows does not always seem to work, which is why vectorise_log_entry() was added
@@ -1819,6 +1818,7 @@ as_sir_method <- function(method_short,
breakpoint_S_R = vectorise_log_entry(paste0(breakpoints_current[, "breakpoint_S", drop = TRUE], "-", breakpoints_current[, "breakpoint_R", drop = TRUE]), length(rows)), breakpoint_S_R = vectorise_log_entry(paste0(breakpoints_current[, "breakpoint_S", drop = TRUE], "-", breakpoints_current[, "breakpoint_R", drop = TRUE]), length(rows)),
stringsAsFactors = FALSE stringsAsFactors = FALSE
) )
attr(new_sir, "interpretation_details") <- out
out <- subset(out, !is.na(input_given)) out <- subset(out, !is.na(input_given))
AMR_env$sir_interpretation_history <- rbind_AMR(AMR_env$sir_interpretation_history, out) AMR_env$sir_interpretation_history <- rbind_AMR(AMR_env$sir_interpretation_history, out)
} }
@@ -1863,14 +1863,26 @@ as_sir_method <- function(method_short,
new_part <- new_part[order(new_part$index), , drop = FALSE] new_part <- new_part[order(new_part$index), , drop = FALSE]
AMR_env$sir_interpretation_history <- rbind_AMR(old_part, new_part) AMR_env$sir_interpretation_history <- rbind_AMR(old_part, new_part)
df$result as_sir_structure(df$result)
} }
#' @rdname as.sir #' @rdname as.sir
#' @param sir_values SIR values that were interpreted from MIC or disk diffusion values using [as.sir()].
#' @param clean A [logical] to indicate whether previously stored results should be forgotten after returning the 'logbook' with results. #' @param clean A [logical] to indicate whether previously stored results should be forgotten after returning the 'logbook' with results.
#' @export #' @export
sir_interpretation_history <- function(clean = FALSE) { sir_interpretation_history <- function(sir_values = NULL, clean = FALSE) {
# for AMR v3.0.0 and lower, the first argument was `clean`, so allow `sir_interpretation_history(TRUE)` to keep working
if (is.logical(sir_values) && missing(clean)) {
clean <- sir_values
sir_values <- NULL
warning_("For `sir_interpretation_history()`, the `clean` argument is no longer the first argument, please update your code to explicitly state 'clean': `sir_interpretation_history(clean = ", clean, ")`.")
}
meet_criteria(sir_values, allow_class = "sir", allow_NULL = TRUE)
meet_criteria(clean, allow_class = "logical", has_length = 1) meet_criteria(clean, allow_class = "logical", has_length = 1)
if (!is.null(sir_values)) {
out <- attr(sir_values, "interpretation_details")
} else {
out <- AMR_env$sir_interpretation_history out <- AMR_env$sir_interpretation_history
out <- out[which(!is.na(out$datetime)), , drop = FALSE] out <- out[which(!is.na(out$datetime)), , drop = FALSE]
out$outcome <- as.sir(out$outcome) out$outcome <- as.sir(out$outcome)
@@ -1878,6 +1890,7 @@ sir_interpretation_history <- function(clean = FALSE) {
if (isTRUE(clean)) { if (isTRUE(clean)) {
AMR_env$sir_interpretation_history <- AMR_env$sir_interpretation_history[0, , drop = FALSE] AMR_env$sir_interpretation_history <- AMR_env$sir_interpretation_history[0, , drop = FALSE]
} }
}
if (pkg_is_available("tibble")) { if (pkg_is_available("tibble")) {
out <- import_fn("as_tibble", "tibble")(out) out <- import_fn("as_tibble", "tibble")(out)
} }
@@ -1904,11 +1917,11 @@ pillar_shaft.sir <- function(x, ...) {
# colours will anyway not work when has_colour() == FALSE, # colours will anyway not work when has_colour() == FALSE,
# but then the indentation should also not be applied # but then the indentation should also not be applied
out[is.na(x)] <- font_grey(" NA") out[is.na(x)] <- font_grey(" NA")
out[x == "NI"] <- font_grey_bg(font_black(" NI "))
out[x == "S"] <- font_green_bg(" S ") out[x == "S"] <- font_green_bg(" S ")
out[x == "SDD"] <- font_green_lighter_bg(" SDD ")
out[x == "I"] <- font_orange_bg(" I ") out[x == "I"] <- font_orange_bg(" I ")
out[x == "SDD"] <- font_orange_bg(" SDD ")
out[x == "R"] <- font_rose_bg(" R ") out[x == "R"] <- font_rose_bg(" R ")
out[x == "NI"] <- font_grey_bg(font_black(" NI "))
} }
create_pillar_column(out, align = "left", width = 5) create_pillar_column(out, align = "left", width = 5)
} }
@@ -2000,21 +2013,60 @@ get_skimmers.sir <- function(column) {
#' @export #' @export
#' @noRd #' @noRd
print.sir <- function(x, ...) { print.sir <- function(x, ...) {
x_name <- deparse(substitute(x))
cat("Class 'sir'\n") cat("Class 'sir'\n")
# TODO for #170
# if (!is.null(attributes(x)$guideline) && !all(is.na(attributes(x)$guideline))) {
# cat(font_blue(word_wrap("These values were interpreted using ",
# font_bold(vector_and(attributes(x)$guideline, quotes = FALSE)),
# " based on ",
# vector_and(attributes(x)$method, quotes = FALSE),
# " values. ",
# "Use `sir_interpretation_history(", x_name, ")` to return a full logbook.")))
# cat("\n")
# }
print(as.character(x), quote = FALSE) print(as.character(x), quote = FALSE)
} }
#' @method print interpreted_sir
#' @export
#' @noRd
print.interpreted_sir <- function(x, ...) {
cat("Class 'sir'\n")
print(as.character(x), quote = FALSE)
if (length(x) == 0) {
return(invisible())
}
int <- attr(x, "interpretation_details")
if (NROW(int) == 0) {
if (length(x) == 1) {
cat(font_blue(word_wrap("Source data were lost for this interpreted value.")))
} else {
cat(font_blue(word_wrap("Source data were lost for these interpreted values.")))
}
} else {
relevant_cols <- int[, c("guideline", "method", "ab", "mo"), drop = FALSE]
relevant_cols <- unique(relevant_cols)
vals1_plural <- ifelse(length(x) == 1, "This value was", "These values were")
vals2_plural <- ifelse(length(x) == 1, "value", "values")
method_fn <- ifelse(relevant_cols$method == "MIC", "MIC", "disk diffusion")
if (NROW(relevant_cols) == 1) {
in_host <- ifelse(relevant_cols$host == "human", "", paste0(" in ", relevant_cols$host))
cat(font_blue(word_wrap(
vals1_plural, " interpreted using ",
relevant_cols$guideline,
" based on the ",
method_fn,
" ", vals2_plural, " for ",
ab_name(relevant_cols$ab, language = NULL, info = FALSE, tolower = TRUE), " in ",
italicise_taxonomy(mo_name(relevant_cols$mo, language = NULL, info = FALSE), type = "ansi"),
in_host,
"."
)))
} else {
cat(font_blue(word_wrap(
vals1_plural, " interpreted using ",
vector_and(relevant_cols$guideline, quotes = FALSE),
" based on ",
vector_and(method_fn, quotes = FALSE),
" ", vals2_plural, "."
)))
}
cat(font_blue(word_wrap("\nUse `sir_interpretation_history()` on this object to return a full logbook.\n")))
}
}
#' @method as.double sir #' @method as.double sir
#' @export #' @export
@@ -2070,51 +2122,132 @@ summary.sir <- function(object, ...) {
value value
} }
#' @method [ sir
#' @export
#' @noRd
"[.sir" <- function(x, ...) {
y <- NextMethod()
det <- attr(x, "interpretation_details")
if (!is.null(det)) {
subset_idx <- seq_along(x)[...]
# safer than relying on implicit eval inside NextMethod()
attr(y, "interpretation_details") <- det[subset_idx, , drop = FALSE]
}
y
}
#' @method [[ sir
#' @export
#' @noRd
"[[.sir" <- function(x, i, ...) {
if (length(i) != 1L) {
stop("attempt to select more than one element with [[.", call. = FALSE)
}
x[i] # calls `[.sir`, ensures attr alignment
}
#' @method [<- sir #' @method [<- sir
#' @export #' @export
#' @noRd #' @noRd
"[<-.sir" <- function(i, j, ..., value) { "[<-.sir" <- function(i, j, ..., value) {
value <- as.sir(value) value <- as.sir(value)
y <- NextMethod() y <- NextMethod()
attributes(y) <- attributes(i)
old_det <- attr(i, "interpretation_details")
new_det <- attr(value, "interpretation_details")
len_y <- length(y)
# Neither i nor value have details -> do nothing
if (is.null(old_det) && is.null(new_det)) {
return(y)
}
# Start building full_det as copy of old_det or empty
full_det <- if (!is.null(old_det)) old_det else data.frame(row = seq_along(i))
# Ensure full_det has correct row count and order
if (nrow(full_det) != length(i)) {
attr(y, "interpretation_details") <- NULL
return(y)
}
# Which rows are being assigned?
assign_idx <- if (missing(j)) seq_along(i) else j
assign_idx <- as.integer(assign_idx)
# If new_det is missing or too short, fill it
if (is.null(new_det)) {
new_det <- data.frame(row = assign_idx)
} else if (nrow(new_det) != length(value)) {
new_det <- data.frame(row = assign_idx)
}
# Add temporary .row to track positions
full_det$.row <- seq_len(nrow(full_det))
new_det$.row <- assign_idx
# Replace old rows with new rows
full_det <- rbind(
subset(full_det, !.row %in% assign_idx),
new_det
)
full_det <- full_det[order(full_det$.row), , drop = FALSE]
full_det$.row <- NULL
# Clean up: ensure right number of rows
if (nrow(full_det) == len_y) {
attr(y, "interpretation_details") <- full_det
} else {
attr(y, "interpretation_details") <- NULL
}
y y
} }
#' @method [[<- sir #' @method [[<- sir
#' @export #' @export
#' @noRd #' @noRd
"[[<-.sir" <- function(i, j, ..., value) { "[[<-.sir" <- function(i, j, ..., value) {
value <- as.sir(value) if (!is.null(det) && length(i) == 1 && nrow(det) >= i) {
y <- NextMethod() i[j] <- value
attributes(y) <- attributes(i) i
y } else {
NextMethod()
}
} }
#' @method c sir #' @method c sir
#' @export #' @export
#' @noRd #' @noRd
c.sir <- function(...) { c.sir <- function(..., recursive = FALSE) {
lst <- list(...) lst <- lapply(
list(...),
function(x) {
list(
values = as.character(x),
interpretation_details = attr(x, "interpretation_details")
)
}
)
x <- unlist(lapply(lst, `[[`, "values"), use.names = FALSE)
details <- lapply(lst, `[[`, "interpretation_details")
has_details <- vapply(details, is.data.frame, logical(1))
if (!any(has_details)) {
return(as_sir_structure(x))
}
# TODO for #170 # Pre-allocate details (no Map, no matrix allocation)
# guideline <- vapply(FUN.VALUE = character(1), lst, function(x) attributes(x)$guideline %or% NA_character_) combined_details <- do.call(rbind, lapply(seq_along(details), function(i) {
# mo <- vapply(FUN.VALUE = character(1), lst, function(x) attributes(x)$mo %or% NA_character_) d <- details[[i]]
# ab <- vapply(FUN.VALUE = character(1), lst, function(x) attributes(x)$ab %or% NA_character_) if (is.null(d)) {
# method <- vapply(FUN.VALUE = character(1), lst, function(x) attributes(x)$method %or% NA_character_) # generate NA rows of correct length, but fast
# ref_tbl <- vapply(FUN.VALUE = character(1), lst, function(x) attributes(x)$ref_tbl %or% NA_character_) n <- length(details[[i]])
# ref_breakpoints <- vapply(FUN.VALUE = character(1), lst, function(x) attributes(x)$ref_breakpoints %or% NA_character_) as.data.frame(matrix(NA, nrow = n, ncol = 0))
} else {
d
}
}))
out <- as.sir(unlist(lapply(list(...), as.character))) attr(x, "interpretation_details") <- combined_details
as_sir_structure(x)
# TODO for #170
# if (!all(is.na(guideline))) {
# attributes(out)$guideline <- guideline
# attributes(out)$mo <- mo
# attributes(out)$ab <- ab
# attributes(out)$method <- method
# attributes(out)$ref_tbl <- ref_tbl
# attributes(out)$ref_breakpoints <- ref_breakpoints
# }
out
} }
#' @method unique sir #' @method unique sir

View File

@@ -244,7 +244,7 @@ sir_calc_df <- function(type, # "proportion", "count" or "both"
translate_ab <- get_translate_ab(translate_ab) translate_ab <- get_translate_ab(translate_ab)
data.bak <- data data.bak <- data
# select only groups and antimicrobials # select only groups and antibiotics
if (is_null_or_grouped_tbl(data)) { if (is_null_or_grouped_tbl(data)) {
data_has_groups <- TRUE data_has_groups <- TRUE
groups <- get_group_names(data) groups <- get_group_names(data)
@@ -255,10 +255,12 @@ sir_calc_df <- function(type, # "proportion", "count" or "both"
} }
data <- as.data.frame(data, stringsAsFactors = FALSE) data <- as.data.frame(data, stringsAsFactors = FALSE)
if (isTRUE(combine_SI)) {
for (i in seq_len(ncol(data))) { for (i in seq_len(ncol(data))) {
# transform SIR columns
if (is.sir(data[, i, drop = TRUE])) { if (is.sir(data[, i, drop = TRUE])) {
data[, i] <- as.character(data[, i, drop = TRUE]) data[, i] <- as.character(data[, i, drop = TRUE])
if (isTRUE(combine_SI)) {
if ("SDD" %in% data[, i, drop = TRUE] && message_not_thrown_before("sir_calc_df", combine_SI, entire_session = TRUE)) { if ("SDD" %in% data[, i, drop = TRUE] && message_not_thrown_before("sir_calc_df", combine_SI, entire_session = TRUE)) {
message_("Note that `sir_calc_df()` will also count dose-dependent susceptibility, 'SDD', as 'SI' when `combine_SI = TRUE`. This note will be shown once for this session.", as_note = FALSE) message_("Note that `sir_calc_df()` will also count dose-dependent susceptibility, 'SDD', as 'SI' when `combine_SI = TRUE`. This note will be shown once for this session.", as_note = FALSE)
} }
@@ -364,7 +366,7 @@ sir_calc_df <- function(type, # "proportion", "count" or "both"
} else { } else {
# don't use as.sir() here, as it would add the class 'sir' and we would like # don't use as.sir() here, as it would add the class 'sir' and we would like
# the same data structure as output, regardless of input # the same data structure as output, regardless of input
if (out$value[out$interpretation == "SDD"] > 0) { if (any(out$value[out$interpretation == "SDD"] > 0, na.rm = TRUE)) {
out$interpretation <- factor(out$interpretation, levels = c("S", "SDD", "I", "R"), ordered = TRUE) out$interpretation <- factor(out$interpretation, levels = c("S", "SDD", "I", "R"), ordered = TRUE)
} else { } else {
out$interpretation <- factor(out$interpretation, levels = c("S", "I", "R"), ordered = TRUE) out$interpretation <- factor(out$interpretation, levels = c("S", "I", "R"), ordered = TRUE)

View File

@@ -47,6 +47,6 @@ sir_df <- function(data,
combine_SI = combine_SI, combine_SI = combine_SI,
confidence_level = confidence_level confidence_level = confidence_level
), ),
error = function(e) stop_(gsub("in sir_calc_df(): ", "", e$message, fixed = TRUE), call = -5) error = function(e) stop_(gsub("in sir_calc_df(): ", "", conditionMessage(e), fixed = TRUE), call = -5)
) )
} }

Binary file not shown.

View File

@@ -19,7 +19,7 @@
#' @keywords internal #' @keywords internal
#' @export #' @export
#' @examples #' @examples
#' library(tidymodels) #' if (require("tidymodels")) {
#' #'
#' # The below approach formed the basis for this paper: DOI 10.3389/fmicb.2025.1582703 #' # The below approach formed the basis for this paper: DOI 10.3389/fmicb.2025.1582703
#' # Presence of ESBL genes was predicted based on raw MIC values. #' # Presence of ESBL genes was predicted based on raw MIC values.
@@ -39,10 +39,14 @@
#' #'
#' # Create and prep a recipe with MIC log2 transformation #' # Create and prep a recipe with MIC log2 transformation
#' mic_recipe <- recipe(esbl ~ ., data = training_data) %>% #' mic_recipe <- recipe(esbl ~ ., data = training_data) %>%
#'
#' # Optionally remove non-predictive variables #' # Optionally remove non-predictive variables
#' remove_role(genus, old_role = "predictor") %>% #' remove_role(genus, old_role = "predictor") %>%
#'
#' # Apply the log2 transformation to all MIC predictors #' # Apply the log2 transformation to all MIC predictors
#' step_mic_log2(all_mic_predictors()) %>% #' step_mic_log2(all_mic_predictors()) %>%
#'
#' # And apply the preparation steps
#' prep() #' prep()
#' #'
#' # View prepped recipe #' # View prepped recipe
@@ -65,10 +69,9 @@
#' our_metrics <- metric_set(accuracy, kap, ppv, npv) #' our_metrics <- metric_set(accuracy, kap, ppv, npv)
#' metrics <- our_metrics(predictions, truth = esbl, estimate = .pred_class) #' metrics <- our_metrics(predictions, truth = esbl, estimate = .pred_class)
#' #'
#' # Show performance: #' # Show performance
#' # - negative predictive value (NPV) of ~98%
#' # - positive predictive value (PPV) of ~94%
#' metrics #' metrics
#' }
all_mic <- function() { all_mic <- function() {
x <- tidymodels_amr_select(levels(NA_mic_)) x <- tidymodels_amr_select(levels(NA_mic_))
names(x) names(x)

View File

@@ -30,7 +30,6 @@
# These are all S3 implementations for the vctrs package, # These are all S3 implementations for the vctrs package,
# that is used internally by tidyverse packages such as dplyr. # that is used internally by tidyverse packages such as dplyr.
# They are to convert AMR-specific classes to bare characters and integers. # They are to convert AMR-specific classes to bare characters and integers.
# All of them will be exported using s3_register() in R/zzz.R when loading the package.
# see https://github.com/tidyverse/dplyr/issues/5955 why this is required # see https://github.com/tidyverse/dplyr/issues/5955 why this is required

View File

@@ -127,7 +127,7 @@ AMR_env$cross_icon <- if (isTRUE(base::l10n_info()$`UTF-8`)) "\u00d7" else "x"
suppressWarnings(suppressMessages(add_custom_antimicrobials(x))) suppressWarnings(suppressMessages(add_custom_antimicrobials(x)))
packageStartupMessage("OK.") packageStartupMessage("OK.")
}, },
error = function(e) packageStartupMessage("Failed: ", e$message) error = function(e) packageStartupMessage("Failed: ", conditionMessage(e))
) )
} }
} }
@@ -143,7 +143,7 @@ AMR_env$cross_icon <- if (isTRUE(base::l10n_info()$`UTF-8`)) "\u00d7" else "x"
suppressWarnings(suppressMessages(add_custom_microorganisms(x))) suppressWarnings(suppressMessages(add_custom_microorganisms(x)))
packageStartupMessage("OK.") packageStartupMessage("OK.")
}, },
error = function(e) packageStartupMessage("Failed: ", e$message) error = function(e) packageStartupMessage("Failed: ", conditionMessage(e))
) )
} }
} }

View File

@@ -56,7 +56,8 @@ os.makedirs(r_lib_path, exist_ok=True)
os.environ['R_LIBS_SITE'] = r_lib_path os.environ['R_LIBS_SITE'] = r_lib_path
from rpy2 import robjects from rpy2 import robjects
from rpy2.robjects import pandas2ri from rpy2.robjects.conversion import localconverter
from rpy2.robjects import default_converter, numpy2ri, pandas2ri
from rpy2.robjects.packages import importr, isinstalled from rpy2.robjects.packages import importr, isinstalled
# Import base and utils # Import base and utils
@@ -94,27 +95,26 @@ if r_amr_version != python_amr_version:
print(f"AMR: Setting up R environment and AMR datasets...", flush=True) print(f"AMR: Setting up R environment and AMR datasets...", flush=True)
# Activate the automatic conversion between R and pandas DataFrames # Activate the automatic conversion between R and pandas DataFrames
pandas2ri.activate() with localconverter(default_converter + numpy2ri.converter + pandas2ri.converter):
# example_isolates
# example_isolates example_isolates = robjects.r('''
example_isolates = pandas2ri.rpy2py(robjects.r(''' df <- AMR::example_isolates
df <- AMR::example_isolates df[] <- lapply(df, function(x) {
df[] <- lapply(df, function(x) {
if (inherits(x, c("Date", "POSIXt", "factor"))) { if (inherits(x, c("Date", "POSIXt", "factor"))) {
as.character(x) as.character(x)
} else { } else {
x x
} }
}) })
df <- df[, !sapply(df, is.list)] df <- df[, !sapply(df, is.list)]
df df
''')) ''')
example_isolates['date'] = pd.to_datetime(example_isolates['date']) example_isolates['date'] = pd.to_datetime(example_isolates['date'])
# microorganisms # microorganisms
microorganisms = pandas2ri.rpy2py(robjects.r('AMR::microorganisms[, !sapply(AMR::microorganisms, is.list)]')) microorganisms = robjects.r('AMR::microorganisms[, !sapply(AMR::microorganisms, is.list)]')
antimicrobials = pandas2ri.rpy2py(robjects.r('AMR::antimicrobials[, !sapply(AMR::antimicrobials, is.list)]')) antimicrobials = robjects.r('AMR::antimicrobials[, !sapply(AMR::antimicrobials, is.list)]')
clinical_breakpoints = pandas2ri.rpy2py(robjects.r('AMR::clinical_breakpoints[, !sapply(AMR::clinical_breakpoints, is.list)]')) clinical_breakpoints = robjects.r('AMR::clinical_breakpoints[, !sapply(AMR::clinical_breakpoints, is.list)]')
base.options(warn = 0) base.options(warn = 0)
@@ -129,16 +129,15 @@ echo "from .datasets import clinical_breakpoints" >> $init_file
# Write header to the functions Python file, including the convert_to_python function # Write header to the functions Python file, including the convert_to_python function
cat <<EOL > "$functions_file" cat <<EOL > "$functions_file"
import functools
import rpy2.robjects as robjects import rpy2.robjects as robjects
from rpy2.robjects.packages import importr from rpy2.robjects.packages import importr
from rpy2.robjects.vectors import StrVector, FactorVector, IntVector, FloatVector, DataFrame from rpy2.robjects.vectors import StrVector, FactorVector, IntVector, FloatVector, DataFrame
from rpy2.robjects import pandas2ri from rpy2.robjects.conversion import localconverter
from rpy2.robjects import default_converter, numpy2ri, pandas2ri
import pandas as pd import pandas as pd
import numpy as np import numpy as np
# Activate automatic conversion between R data frames and pandas data frames
pandas2ri.activate()
# Import the AMR R package # Import the AMR R package
amr_r = importr('AMR') amr_r = importr('AMR')
@@ -156,10 +155,8 @@ def convert_to_python(r_output):
return list(r_output) # Convert to a Python list of integers or floats return list(r_output) # Convert to a Python list of integers or floats
# Check if it's a pandas-compatible R data frame # Check if it's a pandas-compatible R data frame
elif isinstance(r_output, pd.DataFrame): elif isinstance(r_output, (pd.DataFrame, DataFrame)):
return r_output # Return as pandas DataFrame (already converted by pandas2ri) return r_output # Return as pandas DataFrame (already converted by pandas2ri)
elif isinstance(r_output, DataFrame):
return pandas2ri.rpy2py(r_output) # Return as pandas DataFrame
# Check if the input is a NumPy array and has a string data type # Check if the input is a NumPy array and has a string data type
if isinstance(r_output, np.ndarray) and np.issubdtype(r_output.dtype, np.str_): if isinstance(r_output, np.ndarray) and np.issubdtype(r_output.dtype, np.str_):
@@ -167,6 +164,15 @@ def convert_to_python(r_output):
# Fall-back # Fall-back
return r_output return r_output
def r_to_python(r_func):
"""Decorator that runs an rpy2 function under a localconverter
and then applies convert_to_python to its output."""
@functools.wraps(r_func)
def wrapper(*args, **kwargs):
with localconverter(default_converter + numpy2ri.converter + pandas2ri.converter):
return convert_to_python(r_func(*args, **kwargs))
return wrapper
EOL EOL
# Directory where the .Rd files are stored (update path as needed) # Directory where the .Rd files are stored (update path as needed)
@@ -246,10 +252,11 @@ for rd_file in "$rd_dir"/*.Rd; do
gsub("FALSE", "False", func_args) gsub("FALSE", "False", func_args)
gsub("NULL", "None", func_args) gsub("NULL", "None", func_args)
# Write the Python function definition to the output file # Write the Python function definition to the output file, using decorator
print "@r_to_python" >> "'"$functions_file"'"
print "def " func_name_py "(" func_args "):" >> "'"$functions_file"'" print "def " func_name_py "(" func_args "):" >> "'"$functions_file"'"
print " \"\"\"Please see our website of the R package for the full manual: https://amr-for-r.org\"\"\"" >> "'"$functions_file"'" print " \"\"\"Please see our website of the R package for the full manual: https://amr-for-r.org\"\"\"" >> "'"$functions_file"'"
print " return convert_to_python(amr_r." func_name_py "(" func_args "))" >> "'"$functions_file"'" print " return amr_r." func_name_py "(" func_args ")" >> "'"$functions_file"'"
print "from .functions import " func_name_py >> "'"$init_file"'" print "from .functions import " func_name_py >> "'"$init_file"'"
} }

View File

@@ -288,7 +288,7 @@ for (page in LETTERS) {
url <- paste0("https://lpsn.dsmz.de/genus?page=", page) url <- paste0("https://lpsn.dsmz.de/genus?page=", page)
x <- tryCatch(read_html(url), x <- tryCatch(read_html(url),
error = function(e) { error = function(e) {
message("Waiting 10 seconds because of error: ", e$message) message("Waiting 10 seconds because of error: ", conditionMessage(e))
Sys.sleep(10) Sys.sleep(10)
read_html(url) read_html(url)
}) })

View File

@@ -108,3 +108,18 @@ writeLines(contents, "R/aa_helper_pm_functions.R")
# note: pm_left_join() will be overwritten by aaa_helper_functions.R, which contains a faster implementation # note: pm_left_join() will be overwritten by aaa_helper_functions.R, which contains a faster implementation
# replace `res <- as.data.frame(res)` with `res <- as.data.frame(res, stringsAsFactors = FALSE)` # replace `res <- as.data.frame(res)` with `res <- as.data.frame(res, stringsAsFactors = FALSE)`
# after running, pm_select must be altered. The line:
# col_pos <- pm_select_positions(.data, ..., .group_pos = TRUE)
# ... must be replaced with this to support tidyselect functionality such as `starts_with()`:
# col_pos <- tryCatch(pm_select_positions(.data, ..., .group_pos = TRUE), error = function(e) NULL)
# if (is.null(col_pos)) {
# # try with tidyverse
# select_dplyr <- import_fn("select", "dplyr", error_on_fail = FALSE)
# if (!is.null(select_dplyr)) {
# col_pos <- which(colnames(.data) %in% colnames(select_dplyr(.data, ...)))
# } else {
# # this will throw an error as it did, but dplyr is not available, so no other option
# col_pos <- pm_select_positions(.data, ..., .group_pos = TRUE)
# }
# }

View File

@@ -283,7 +283,7 @@ for (i in 2:length(sheets_to_analyse)) {
guideline_name = guideline_name guideline_name = guideline_name
) )
), ),
error = function(e) message(e$message) error = function(e) message(conditionMessage(e))
) )
} }

Binary file not shown.

View File

@@ -133,7 +133,7 @@ ggplot(data.frame(mic = some_mic_values,
sir = interpretation), sir = interpretation),
aes(x = group, y = mic, colour = sir)) + aes(x = group, y = mic, colour = sir)) +
theme_minimal() + theme_minimal() +
geom_boxplot(fill = NA, colour = "grey") + geom_boxplot(fill = NA, colour = "grey30") +
geom_jitter(width = 0.25) + geom_jitter(width = 0.25) +
# NEW scale function: plot MIC values to x, y, colour or fill # NEW scale function: plot MIC values to x, y, colour or fill

View File

@@ -27,12 +27,12 @@
<p style="text-align:left; width: 50%;"> <p style="text-align:left; width: 50%;">
<small><a href="https://amr-for-r.org/">https://amr-for-r.org</a></small> <small><a href="https://amr-for-r.org/">amr-for-r.org</a></small>
</p> </p>
<p style="text-align:right; width: 50%;"> <p style="text-align:right; width: 50%;">
<small><a href="https://doi.org/10.18637/jss.v104.i03" target="_blank">https://doi.org/10.18637/jss.v104.i03</a></small> <small><a href="https://doi.org/10.18637/jss.v104.i03" target="_blank">doi.org/10.18637/jss.v104.i03</a></small>
</p> </p>
</div> </div>
@@ -171,14 +171,14 @@ example_isolates %>%
select(bacteria, select(bacteria,
aminoglycosides(), aminoglycosides(),
carbapenems()) carbapenems())
#> Using column 'mo' as input for mo_fullname() #> Using column 'mo' as input for `mo_fullname()`
#> Using column 'mo' as input for mo_is_gram_negative() #> Using column 'mo' as input for `mo_is_gram_negative()`
#> Using column 'mo' as input for mo_is_intrinsic_resistant() #> Using column 'mo' as input for `mo_is_intrinsic_resistant()`
#> Determining intrinsic resistance based on 'EUCAST Expected Resistant #> Determining intrinsic resistance based on 'EUCAST Expected Resistant
#> Phenotypes' v1.2 (2023). This note will be shown once per session. #> Phenotypes' v1.2 (2023). This note will be shown once per session.
#> For aminoglycosides() using columns 'GEN' (gentamicin), 'TOB' #> For `aminoglycosides()` using columns 'GEN' (gentamicin), 'TOB'
#> (tobramycin), 'AMK' (amikacin), and 'KAN' (kanamycin) #> (tobramycin), 'AMK' (amikacin), and 'KAN' (kanamycin)
#> For carbapenems() using columns 'IPM' (imipenem) and 'MEM' (meropenem) #> For `carbapenems()` using columns 'IPM' (imipenem) and 'MEM' (meropenem)
#> # A tibble: 35 × 7 #> # A tibble: 35 × 7
#> bacteria GEN TOB AMK KAN IPM MEM #> bacteria GEN TOB AMK KAN IPM MEM
#> <chr> <sir> <sir> <sir> <sir> <sir> <sir> #> <chr> <sir> <sir> <sir> <sir> <sir> <sir>
@@ -215,9 +215,9 @@ output format automatically (such as markdown, LaTeX, HTML, etc.).
``` r ``` r
antibiogram(example_isolates, antibiogram(example_isolates,
antimicrobials = c(aminoglycosides(), carbapenems())) antimicrobials = c(aminoglycosides(), carbapenems()))
#> For aminoglycosides() using columns 'GEN' (gentamicin), 'TOB' #> For `aminoglycosides()` using columns 'GEN' (gentamicin), 'TOB'
#> (tobramycin), 'AMK' (amikacin), and 'KAN' (kanamycin) #> (tobramycin), 'AMK' (amikacin), and 'KAN' (kanamycin)
#> For carbapenems() using columns 'IPM' (imipenem) and 'MEM' (meropenem) #> For `carbapenems()` using columns 'IPM' (imipenem) and 'MEM' (meropenem)
``` ```
| Pathogen | Amikacin | Gentamicin | Imipenem | Kanamycin | Meropenem | Tobramycin | | Pathogen | Amikacin | Gentamicin | Imipenem | Kanamycin | Meropenem | Tobramycin |
@@ -289,7 +289,7 @@ ggplot(data.frame(mic = some_mic_values,
sir = interpretation), sir = interpretation),
aes(x = group, y = mic, colour = sir)) + aes(x = group, y = mic, colour = sir)) +
theme_minimal() + theme_minimal() +
geom_boxplot(fill = NA, colour = "grey") + geom_boxplot(fill = NA, colour = "grey30") +
geom_jitter(width = 0.25) + geom_jitter(width = 0.25) +
# NEW scale function: plot MIC values to x, y, colour or fill # NEW scale function: plot MIC values to x, y, colour or fill
@@ -321,9 +321,9 @@ example_isolates %>%
#> # A tibble: 3 × 5 #> # A tibble: 3 × 5
#> ward GEN_total_R GEN_conf_int TOB_total_R TOB_conf_int #> ward GEN_total_R GEN_conf_int TOB_total_R TOB_conf_int
#> <chr> <dbl> <chr> <dbl> <chr> #> <chr> <dbl> <chr> <dbl> <chr>
#> 1 Clinical 0.2289362 0.205-0.254 0.3147503 0.284-0.347 #> 1 Clinical 0.229 0.205-0.254 0.315 0.284-0.347
#> 2 ICU 0.2902655 0.253-0.33 0.4004739 0.353-0.449 #> 2 ICU 0.290 0.253-0.33 0.400 0.353-0.449
#> 3 Outpatient 0.2 0.131-0.285 0.3676471 0.254-0.493 #> 3 Outpatient 0.2 0.131-0.285 0.368 0.254-0.493
``` ```
Or use [antimicrobial Or use [antimicrobial
@@ -340,22 +340,22 @@ out <- example_isolates %>%
# calculate AMR using resistance(), over all aminoglycosides and polymyxins: # calculate AMR using resistance(), over all aminoglycosides and polymyxins:
summarise(across(c(aminoglycosides(), polymyxins()), summarise(across(c(aminoglycosides(), polymyxins()),
resistance)) resistance))
#> For aminoglycosides() using columns 'GEN' (gentamicin), 'TOB' #> For `aminoglycosides()` using columns 'GEN' (gentamicin), 'TOB'
#> (tobramycin), 'AMK' (amikacin), and 'KAN' (kanamycin) #> (tobramycin), 'AMK' (amikacin), and 'KAN' (kanamycin)
#> For polymyxins() using column 'COL' (colistin) #> For `polymyxins()` using column 'COL' (colistin)
#> Warning: There was 1 warning in `summarise()`. #> Warning: There was 1 warning in `summarise()`.
#> In argument: `across(c(aminoglycosides(), polymyxins()), resistance)`. #> In argument: `across(c(aminoglycosides(), polymyxins()), resistance)`.
#> In group 3: `ward = "Outpatient"`. #> In group 3: `ward = "Outpatient"`.
#> Caused by warning: #> Caused by warning:
#> ! Introducing NA: only 23 results available for KAN in group: ward = #> ! Introducing NA: only 23 results available for KAN in group: ward =
#> "Outpatient" (minimum = 30). #> "Outpatient" (`minimum` = 30).
out out
#> # A tibble: 3 × 6 #> # A tibble: 3 × 6
#> ward GEN TOB AMK KAN COL #> ward GEN TOB AMK KAN COL
#> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> #> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Clinical 0.2289362 0.3147503 0.6258993 1 0.7802956 #> 1 Clinical 0.229 0.315 0.626 1 0.780
#> 2 ICU 0.2902655 0.4004739 0.6624473 1 0.8574144 #> 2 ICU 0.290 0.400 0.662 1 0.857
#> 3 Outpatient 0.2 0.3676471 0.6052632 NA 0.8888889 #> 3 Outpatient 0.2 0.368 0.605 NA 0.889
``` ```
``` r ``` r
@@ -364,9 +364,9 @@ out %>% set_ab_names()
#> # A tibble: 3 × 6 #> # A tibble: 3 × 6
#> ward gentamicin tobramycin amikacin kanamycin colistin #> ward gentamicin tobramycin amikacin kanamycin colistin
#> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> #> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Clinical 0.2289362 0.3147503 0.6258993 1 0.7802956 #> 1 Clinical 0.229 0.315 0.626 1 0.780
#> 2 ICU 0.2902655 0.4004739 0.6624473 1 0.8574144 #> 2 ICU 0.290 0.400 0.662 1 0.857
#> 3 Outpatient 0.2 0.3676471 0.6052632 NA 0.8888889 #> 3 Outpatient 0.2 0.368 0.605 NA 0.889
``` ```
``` r ``` r
@@ -375,9 +375,9 @@ out %>% set_ab_names(property = "atc")
#> # A tibble: 3 × 6 #> # A tibble: 3 × 6
#> ward J01GB03 J01GB01 J01GB06 J01GB04 J01XB01 #> ward J01GB03 J01GB01 J01GB06 J01GB04 J01XB01
#> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> #> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Clinical 0.2289362 0.3147503 0.6258993 1 0.7802956 #> 1 Clinical 0.229 0.315 0.626 1 0.780
#> 2 ICU 0.2902655 0.4004739 0.6624473 1 0.8574144 #> 2 ICU 0.290 0.400 0.662 1 0.857
#> 3 Outpatient 0.2 0.3676471 0.6052632 NA 0.8888889 #> 3 Outpatient 0.2 0.368 0.605 NA 0.889
``` ```
## What else can you do with this package? ## What else can you do with this package?

View File

@@ -4,20 +4,23 @@
\alias{age_groups} \alias{age_groups}
\title{Split Ages into Age Groups} \title{Split Ages into Age Groups}
\usage{ \usage{
age_groups(x, split_at = c(12, 25, 55, 75), na.rm = FALSE) age_groups(x, split_at = c(0, 12, 25, 55, 75), names = NULL,
na.rm = FALSE)
} }
\arguments{ \arguments{
\item{x}{Age, e.g. calculated with \code{\link[=age]{age()}}.} \item{x}{Age, e.g. calculated with \code{\link[=age]{age()}}.}
\item{split_at}{Values to split \code{x} at - the default is age groups 0-11, 12-24, 25-54, 55-74 and 75+. See \emph{Details}.} \item{split_at}{Values to split \code{x} at - the default is age groups 0-11, 12-24, 25-54, 55-74 and 75+. See \emph{Details}.}
\item{names}{Optional names to be given to the various age groups.}
\item{na.rm}{A \link{logical} to indicate whether missing values should be removed.} \item{na.rm}{A \link{logical} to indicate whether missing values should be removed.}
} }
\value{ \value{
Ordered \link{factor} Ordered \link{factor}
} }
\description{ \description{
Split ages into age groups defined by the \code{split} argument. This allows for easier demographic (antimicrobial resistance) analysis. Split ages into age groups defined by the \code{split} argument. This allows for easier demographic (antimicrobial resistance) analysis. The function returns an ordered \link{factor}.
} }
\details{ \details{
To split ages, the input for the \code{split_at} argument can be: To split ages, the input for the \code{split_at} argument can be:
@@ -41,6 +44,7 @@ age_groups(ages, 50)
# split into 0-19, 20-49 and 50+ # split into 0-19, 20-49 and 50+
age_groups(ages, c(20, 50)) age_groups(ages, c(20, 50))
age_groups(ages, c(20, 50), names = c("Under 20 years", "20 to 50 years", "Over 50 years"))
# split into groups of ten years # split into groups of ten years
age_groups(ages, 1:10 * 10) age_groups(ages, 1:10 * 10)

View File

@@ -65,56 +65,59 @@ Pre-processing pipeline steps include:
These steps integrate with \code{recipes::recipe()} and work like standard preprocessing steps. They are useful for preparing data for modelling, especially with classification models. These steps integrate with \code{recipes::recipe()} and work like standard preprocessing steps. They are useful for preparing data for modelling, especially with classification models.
} }
\examples{ \examples{
library(tidymodels) if (require("tidymodels")) {
# The below approach formed the basis for this paper: DOI 10.3389/fmicb.2025.1582703 # The below approach formed the basis for this paper: DOI 10.3389/fmicb.2025.1582703
# Presence of ESBL genes was predicted based on raw MIC values. # Presence of ESBL genes was predicted based on raw MIC values.
# example data set in the AMR package # example data set in the AMR package
esbl_isolates esbl_isolates
# Prepare a binary outcome and convert to ordered factor # Prepare a binary outcome and convert to ordered factor
data <- esbl_isolates \%>\% data <- esbl_isolates \%>\%
mutate(esbl = factor(esbl, levels = c(FALSE, TRUE), ordered = TRUE)) mutate(esbl = factor(esbl, levels = c(FALSE, TRUE), ordered = TRUE))
# Split into training and testing sets # Split into training and testing sets
split <- initial_split(data) split <- initial_split(data)
training_data <- training(split) training_data <- training(split)
testing_data <- testing(split) testing_data <- testing(split)
# Create and prep a recipe with MIC log2 transformation
mic_recipe <- recipe(esbl ~ ., data = training_data) \%>\%
# Create and prep a recipe with MIC log2 transformation
mic_recipe <- recipe(esbl ~ ., data = training_data) \%>\%
# Optionally remove non-predictive variables # Optionally remove non-predictive variables
remove_role(genus, old_role = "predictor") \%>\% remove_role(genus, old_role = "predictor") \%>\%
# Apply the log2 transformation to all MIC predictors # Apply the log2 transformation to all MIC predictors
step_mic_log2(all_mic_predictors()) \%>\% step_mic_log2(all_mic_predictors()) \%>\%
# And apply the preparation steps
prep() prep()
# View prepped recipe # View prepped recipe
mic_recipe mic_recipe
# Apply the recipe to training and testing data # Apply the recipe to training and testing data
out_training <- bake(mic_recipe, new_data = NULL) out_training <- bake(mic_recipe, new_data = NULL)
out_testing <- bake(mic_recipe, new_data = testing_data) out_testing <- bake(mic_recipe, new_data = testing_data)
# Fit a logistic regression model # Fit a logistic regression model
fitted <- logistic_reg(mode = "classification") \%>\% fitted <- logistic_reg(mode = "classification") \%>\%
set_engine("glm") \%>\% set_engine("glm") \%>\%
fit(esbl ~ ., data = out_training) fit(esbl ~ ., data = out_training)
# Generate predictions on the test set # Generate predictions on the test set
predictions <- predict(fitted, out_testing) \%>\% predictions <- predict(fitted, out_testing) \%>\%
bind_cols(out_testing) bind_cols(out_testing)
# Evaluate predictions using standard classification metrics # Evaluate predictions using standard classification metrics
our_metrics <- metric_set(accuracy, kap, ppv, npv) our_metrics <- metric_set(accuracy, kap, ppv, npv)
metrics <- our_metrics(predictions, truth = esbl, estimate = .pred_class) metrics <- our_metrics(predictions, truth = esbl, estimate = .pred_class)
# Show performance: # Show performance
# - negative predictive value (NPV) of ~98\% metrics
# - positive predictive value (PPV) of ~94\% }
metrics
} }
\seealso{ \seealso{
\code{\link[recipes:recipe]{recipes::recipe()}}, \code{\link[=as.mic]{as.mic()}}, \code{\link[=as.sir]{as.sir()}} \code{\link[recipes:recipe]{recipes::recipe()}}, \code{\link[=as.mic]{as.mic()}}, \code{\link[=as.sir]{as.sir()}}

View File

@@ -70,12 +70,14 @@ is_sir_eligible(x, threshold = 0.05)
language = get_AMR_locale(), verbose = FALSE, info = interactive(), language = get_AMR_locale(), verbose = FALSE, info = interactive(),
parallel = FALSE, max_cores = -1, conserve_capped_values = NULL) parallel = FALSE, max_cores = -1, conserve_capped_values = NULL)
sir_interpretation_history(clean = FALSE) sir_interpretation_history(sir_values = NULL, clean = FALSE)
} }
\arguments{ \arguments{
\item{x}{Vector of values (for class \code{\link{mic}}: MIC values in mg/L, for class \code{\link{disk}}: a disk diffusion radius in millimetres).} \item{x}{Vector of values (for class \code{\link{mic}}: MIC values in mg/L, for class \code{\link{disk}}: a disk diffusion radius in millimetres).}
\item{...}{For using on a \link{data.frame}: names of columns to apply \code{\link[=as.sir]{as.sir()}} on (supports tidy selection such as \code{column1:column4}). Otherwise: arguments passed on to methods.} \item{...}{For using on a \link{data.frame}: selection of columns to apply \code{as.sir()} to. Supports \link[tidyselect:starts_with]{tidyselect language} such as \code{where(is.mic)}, \code{starts_with(...)}, or \code{column1:column4}, and can thus also be \link[=amr_selector]{antimicrobial selectors} such as \code{as.sir(df, penicillins())}.
Otherwise: arguments passed on to methods.}
\item{threshold}{Maximum fraction of invalid antimicrobial interpretations of \code{x}, see \emph{Examples}.} \item{threshold}{Maximum fraction of invalid antimicrobial interpretations of \code{x}, see \emph{Examples}.}
@@ -145,6 +147,8 @@ The default \code{"standard"} setting ensures cautious handling of uncertain val
\item{max_cores}{Maximum number of cores to use if \code{parallel = TRUE}. Use a negative value to subtract that number from the available number of cores, e.g. a value of \code{-2} on an 8-core machine means that at most 6 cores will be used. Defaults to \code{-1}. There will never be used more cores than variables to analyse. The available number of cores are detected using \code{\link[parallelly:availableCores]{parallelly::availableCores()}} if that package is installed, and base \R's \code{\link[parallel:detectCores]{parallel::detectCores()}} otherwise.} \item{max_cores}{Maximum number of cores to use if \code{parallel = TRUE}. Use a negative value to subtract that number from the available number of cores, e.g. a value of \code{-2} on an 8-core machine means that at most 6 cores will be used. Defaults to \code{-1}. There will never be used more cores than variables to analyse. The available number of cores are detected using \code{\link[parallelly:availableCores]{parallelly::availableCores()}} if that package is installed, and base \R's \code{\link[parallel:detectCores]{parallel::detectCores()}} otherwise.}
\item{sir_values}{SIR values that were interpreted from MIC or disk diffusion values using \code{\link[=as.sir]{as.sir()}}.}
\item{clean}{A \link{logical} to indicate whether previously stored results should be forgotten after returning the 'logbook' with results.} \item{clean}{A \link{logical} to indicate whether previously stored results should be forgotten after returning the 'logbook' with results.}
} }
\value{ \value{
@@ -314,9 +318,12 @@ if (require("dplyr")) {
df_wide \%>\% mutate_if(is.mic, as.sir) df_wide \%>\% mutate_if(is.mic, as.sir)
df_wide \%>\% mutate_if(function(x) is.mic(x) | is.disk(x), as.sir) df_wide \%>\% mutate_if(function(x) is.mic(x) | is.disk(x), as.sir)
df_wide \%>\% mutate(across(where(is.mic), as.sir)) df_wide \%>\% mutate(across(where(is.mic), as.sir))
df_wide \%>\% mutate_at(vars(amoxicillin:tobra), as.sir) df_wide \%>\% mutate_at(vars(amoxicillin:tobra), as.sir)
df_wide \%>\% mutate(across(amoxicillin:tobra, as.sir)) df_wide \%>\% mutate(across(amoxicillin:tobra, as.sir))
df_wide \%>\% mutate(across(aminopenicillins(), as.sir))
# approaches that all work with additional arguments: # approaches that all work with additional arguments:
df_long \%>\% df_long \%>\%
# given a certain data type, e.g. MIC values # given a certain data type, e.g. MIC values

View File

@@ -9,10 +9,10 @@ ggplot_sir(data, position = NULL, x = "antibiotic",
fill = "interpretation", facet = NULL, breaks = seq(0, 1, 0.1), fill = "interpretation", facet = NULL, breaks = seq(0, 1, 0.1),
limits = NULL, translate_ab = "name", combine_SI = TRUE, limits = NULL, translate_ab = "name", combine_SI = TRUE,
minimum = 30, language = get_AMR_locale(), nrow = NULL, colours = c(S minimum = 30, language = get_AMR_locale(), nrow = NULL, colours = c(S
= "#3CAEA3", SI = "#3CAEA3", I = "#F6D55C", IR = "#ED553B", R = "#ED553B"), = "#3CAEA3", SDD = "#8FD6C4", SI = "#3CAEA3", I = "#F6D55C", IR = "#ED553B",
datalabels = TRUE, datalabels.size = 2.5, datalabels.colour = "grey15", R = "#ED553B"), datalabels = TRUE, datalabels.size = 2.5,
title = NULL, subtitle = NULL, caption = NULL, datalabels.colour = "grey15", title = NULL, subtitle = NULL,
x.title = "Antimicrobial", y.title = "Proportion", ...) caption = NULL, x.title = "Antimicrobial", y.title = "Proportion", ...)
geom_sir(position = NULL, x = c("antibiotic", "interpretation"), geom_sir(position = NULL, x = c("antibiotic", "interpretation"),
fill = "interpretation", translate_ab = "name", minimum = 30, fill = "interpretation", translate_ab = "name", minimum = 30,

View File

@@ -18,7 +18,7 @@ amr_distance_from_row(amr_distance, row)
\arguments{ \arguments{
\item{x}{A vector of class \link[=as.sir]{sir}, \link[=as.mic]{mic} or \link[=as.disk]{disk}, or a \link{data.frame} containing columns of any of these classes.} \item{x}{A vector of class \link[=as.sir]{sir}, \link[=as.mic]{mic} or \link[=as.disk]{disk}, or a \link{data.frame} containing columns of any of these classes.}
\item{...}{Variables to select. Supports \link[tidyselect:language]{tidyselect language} (such as \code{column1:column4} and \code{where(is.mic)}), and can thus also be \link[=amr_selector]{antimicrobial selectors}.} \item{...}{Variables to select. Supports \link[tidyselect:starts_with]{tidyselect language} such as \code{where(is.mic)}, \code{starts_with(...)}, or \code{column1:column4}, and can thus also be \link[=amr_selector]{antimicrobial selectors}.}
\item{combine_SI}{A \link{logical} to indicate whether all values of S, SDD, and I must be merged into one, so the input only consists of S+I vs. R (susceptible vs. resistant) - the default is \code{TRUE}.} \item{combine_SI}{A \link{logical} to indicate whether all values of S, SDD, and I must be merged into one, so the input only consists of S+I vs. R (susceptible vs. resistant) - the default is \code{TRUE}.}

View File

@@ -33,25 +33,25 @@ scale_colour_mic(keep_operators = "edges", mic_range = NULL, ...)
scale_fill_mic(keep_operators = "edges", mic_range = NULL, ...) scale_fill_mic(keep_operators = "edges", mic_range = NULL, ...)
scale_x_sir(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), scale_x_sir(colours_SIR = c(S = "#3CAEA3", SDD = "#8FD6C4", I = "#F6D55C", R
language = get_AMR_locale(), eucast_I = getOption("AMR_guideline", = "#ED553B"), language = get_AMR_locale(),
"EUCAST") == "EUCAST", ...) eucast_I = getOption("AMR_guideline", "EUCAST") == "EUCAST", ...)
scale_colour_sir(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), scale_colour_sir(colours_SIR = c(S = "#3CAEA3", SDD = "#8FD6C4", I =
language = get_AMR_locale(), eucast_I = getOption("AMR_guideline", "#F6D55C", R = "#ED553B"), language = get_AMR_locale(),
"EUCAST") == "EUCAST", ...) eucast_I = getOption("AMR_guideline", "EUCAST") == "EUCAST", ...)
scale_fill_sir(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), scale_fill_sir(colours_SIR = c(S = "#3CAEA3", SDD = "#8FD6C4", I = "#F6D55C",
language = get_AMR_locale(), eucast_I = getOption("AMR_guideline", R = "#ED553B"), language = get_AMR_locale(),
"EUCAST") == "EUCAST", ...) eucast_I = getOption("AMR_guideline", "EUCAST") == "EUCAST", ...)
\method{plot}{mic}(x, mo = NULL, ab = NULL, \method{plot}{mic}(x, mo = NULL, ab = NULL,
guideline = getOption("AMR_guideline", "EUCAST"), guideline = getOption("AMR_guideline", "EUCAST"),
main = deparse(substitute(x)), ylab = translate_AMR("Frequency", language main = deparse(substitute(x)), ylab = translate_AMR("Frequency", language
= language), = language),
xlab = translate_AMR("Minimum Inhibitory Concentration (mg/L)", language = xlab = translate_AMR("Minimum Inhibitory Concentration (mg/L)", language =
language), colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), language), colours_SIR = c(S = "#3CAEA3", SDD = "#8FD6C4", I = "#F6D55C", R
language = get_AMR_locale(), expand = TRUE, = "#ED553B"), language = get_AMR_locale(), expand = TRUE,
include_PKPD = getOption("AMR_include_PKPD", TRUE), include_PKPD = getOption("AMR_include_PKPD", TRUE),
breakpoint_type = getOption("AMR_breakpoint_type", "human"), ...) breakpoint_type = getOption("AMR_breakpoint_type", "human"), ...)
@@ -60,8 +60,8 @@ scale_fill_sir(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
title = deparse(substitute(object)), ylab = translate_AMR("Frequency", title = deparse(substitute(object)), ylab = translate_AMR("Frequency",
language = language), language = language),
xlab = translate_AMR("Minimum Inhibitory Concentration (mg/L)", language = xlab = translate_AMR("Minimum Inhibitory Concentration (mg/L)", language =
language), colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), language), colours_SIR = c(S = "#3CAEA3", SDD = "#8FD6C4", I = "#F6D55C", R
language = get_AMR_locale(), expand = TRUE, = "#ED553B"), language = get_AMR_locale(), expand = TRUE,
include_PKPD = getOption("AMR_include_PKPD", TRUE), include_PKPD = getOption("AMR_include_PKPD", TRUE),
breakpoint_type = getOption("AMR_breakpoint_type", "human"), ...) breakpoint_type = getOption("AMR_breakpoint_type", "human"), ...)
@@ -69,8 +69,8 @@ scale_fill_sir(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
ylab = translate_AMR("Frequency", language = language), ylab = translate_AMR("Frequency", language = language),
xlab = translate_AMR("Disk diffusion diameter (mm)", language = language), xlab = translate_AMR("Disk diffusion diameter (mm)", language = language),
mo = NULL, ab = NULL, guideline = getOption("AMR_guideline", "EUCAST"), mo = NULL, ab = NULL, guideline = getOption("AMR_guideline", "EUCAST"),
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), colours_SIR = c(S = "#3CAEA3", SDD = "#8FD6C4", I = "#F6D55C", R =
language = get_AMR_locale(), expand = TRUE, "#ED553B"), language = get_AMR_locale(), expand = TRUE,
include_PKPD = getOption("AMR_include_PKPD", TRUE), include_PKPD = getOption("AMR_include_PKPD", TRUE),
breakpoint_type = getOption("AMR_breakpoint_type", "human"), ...) breakpoint_type = getOption("AMR_breakpoint_type", "human"), ...)
@@ -78,8 +78,8 @@ scale_fill_sir(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
title = deparse(substitute(object)), ylab = translate_AMR("Frequency", title = deparse(substitute(object)), ylab = translate_AMR("Frequency",
language = language), xlab = translate_AMR("Disk diffusion diameter (mm)", language = language), xlab = translate_AMR("Disk diffusion diameter (mm)",
language = language), guideline = getOption("AMR_guideline", "EUCAST"), language = language), guideline = getOption("AMR_guideline", "EUCAST"),
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), colours_SIR = c(S = "#3CAEA3", SDD = "#8FD6C4", I = "#F6D55C", R =
language = get_AMR_locale(), expand = TRUE, "#ED553B"), language = get_AMR_locale(), expand = TRUE,
include_PKPD = getOption("AMR_include_PKPD", TRUE), include_PKPD = getOption("AMR_include_PKPD", TRUE),
breakpoint_type = getOption("AMR_breakpoint_type", "human"), ...) breakpoint_type = getOption("AMR_breakpoint_type", "human"), ...)
@@ -90,8 +90,8 @@ scale_fill_sir(colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"),
\method{autoplot}{sir}(object, title = deparse(substitute(object)), \method{autoplot}{sir}(object, title = deparse(substitute(object)),
xlab = translate_AMR("Antimicrobial Interpretation", language = language), xlab = translate_AMR("Antimicrobial Interpretation", language = language),
ylab = translate_AMR("Frequency", language = language), ylab = translate_AMR("Frequency", language = language), colours_SIR = c(S
colours_SIR = c("#3CAEA3", "#F6D55C", "#ED553B"), = "#3CAEA3", SDD = "#8FD6C4", I = "#F6D55C", R = "#ED553B"),
language = get_AMR_locale(), ...) language = get_AMR_locale(), ...)
facet_sir(facet = c("interpretation", "antibiotic"), nrow = NULL) facet_sir(facet = c("interpretation", "antibiotic"), nrow = NULL)
@@ -99,8 +99,8 @@ facet_sir(facet = c("interpretation", "antibiotic"), nrow = NULL)
scale_y_percent(breaks = function(x) seq(0, max(x, na.rm = TRUE), 0.1), scale_y_percent(breaks = function(x) seq(0, max(x, na.rm = TRUE), 0.1),
limits = c(0, NA)) limits = c(0, NA))
scale_sir_colours(..., aesthetics, colours_SIR = c("#3CAEA3", "#F6D55C", scale_sir_colours(..., aesthetics, colours_SIR = c(S = "#3CAEA3", SDD =
"#ED553B")) "#8FD6C4", I = "#F6D55C", R = "#ED553B"))
theme_sir() theme_sir()
@@ -210,6 +210,10 @@ if (require("ggplot2")) {
# when providing the microorganism and antibiotic, colours will show interpretations: # when providing the microorganism and antibiotic, colours will show interpretations:
autoplot(some_mic_values, mo = "Escherichia coli", ab = "cipro") autoplot(some_mic_values, mo = "Escherichia coli", ab = "cipro")
} }
if (require("ggplot2")) {
autoplot(some_mic_values, mo = "Staph aureus", ab = "Ceftaroline", guideline = "CLSI")
}
if (require("ggplot2")) { if (require("ggplot2")) {
# support for 27 languages, various guidelines, and many options # support for 27 languages, various guidelines, and many options
autoplot(some_disk_values, autoplot(some_disk_values,
@@ -267,7 +271,7 @@ if (require("ggplot2")) {
aes(group, mic) aes(group, mic)
) + ) +
geom_boxplot() + geom_boxplot() +
geom_violin(linetype = 2, colour = "grey", fill = NA) + geom_violin(linetype = 2, colour = "grey30", fill = NA) +
scale_y_mic() scale_y_mic()
} }
if (require("ggplot2")) { if (require("ggplot2")) {
@@ -279,7 +283,7 @@ if (require("ggplot2")) {
aes(group, mic) aes(group, mic)
) + ) +
geom_boxplot() + geom_boxplot() +
geom_violin(linetype = 2, colour = "grey", fill = NA) + geom_violin(linetype = 2, colour = "grey30", fill = NA) +
scale_y_mic(mic_range = c(NA, 0.25)) scale_y_mic(mic_range = c(NA, 0.25))
} }
@@ -312,7 +316,7 @@ if (require("ggplot2")) {
aes(x = group, y = mic, colour = sir) aes(x = group, y = mic, colour = sir)
) + ) +
theme_minimal() + theme_minimal() +
geom_boxplot(fill = NA, colour = "grey") + geom_boxplot(fill = NA, colour = "grey30") +
geom_jitter(width = 0.25) geom_jitter(width = 0.25)
plain plain

View File

@@ -190,6 +190,15 @@ this shows on top of every sidebar to the right
} }
} }
.template-reference-topic h3,
.template-reference-topic h3 code {
color: var(--amr-green-dark) !important;
}
.template-reference-topic h3 {
font-weight: normal;
margin-top: 2rem;
}
/* replace 'Developers' with 'Maintainers' */ /* replace 'Developers' with 'Maintainers' */
.developers h2 { .developers h2 {
display: none; display: none;

View File

@@ -63,10 +63,12 @@ test_that("test-zzz.R", {
"progress_bar" = "progress", "progress_bar" = "progress",
"read_html" = "xml2", "read_html" = "xml2",
"right_join" = "dplyr", "right_join" = "dplyr",
"select" = "dplyr",
"semi_join" = "dplyr", "semi_join" = "dplyr",
"showQuestion" = "rstudioapi", "showQuestion" = "rstudioapi",
"symbol" = "cli", "symbol" = "cli",
"tibble" = "tibble", "tibble" = "tibble",
"where" = "tidyselect",
"write.xlsx" = "openxlsx" "write.xlsx" = "openxlsx"
) )