1
0
mirror of https://github.com/msberends/AMR.git synced 2026-03-11 15:47:54 +01:00

(v3.0.1.9031) fix MDRO for non-RStudio terminal

This commit is contained in:
2026-03-08 11:30:18 +01:00
parent e2102c081a
commit b6f8584994
6 changed files with 80 additions and 59 deletions

View File

@@ -1,6 +1,6 @@
Package: AMR Package: AMR
Version: 3.0.1.9030 Version: 3.0.1.9031
Date: 2026-03-07 Date: 2026-03-08
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

@@ -1,4 +1,4 @@
# AMR 3.0.1.9030 # AMR 3.0.1.9031
### New ### New
* Integration with the **tidymodels** framework to allow seamless use of SIR, MIC and disk data in modelling pipelines via `recipes` * Integration with the **tidymodels** framework to allow seamless use of SIR, MIC and disk data in modelling pipelines via `recipes`
@@ -18,7 +18,6 @@
* Two new `NA` objects, `NA_ab_` and `NA_mo_`, analogous to base R's `NA_character_` and `NA_integer_`, for use in pipelines that require typed missing values * Two new `NA` objects, `NA_ab_` and `NA_mo_`, analogous to base R's `NA_character_` and `NA_integer_`, for use in pipelines that require typed missing values
### Fixes ### Fixes
* `mdro()`: when a base beta-lactam drug column is missing but a corresponding drug+inhibitor combination is present in the data and resistant (e.g., piperacillin/tazobactam = R while piperacillin is absent), the base drug is now correctly inferred as resistant. This ensures MDRO classification is not missed due to test-ordering differences in the laboratory. The reverse direction is also valid: susceptibility in a combination does not imply susceptibility in the base drug (the inhibitor may be responsible), so only resistance is propagated. Closes #209
* Fixed a bug in `as.sir()` where values that were purely numeric (e.g., `"1"`) and matched the broad SIR-matching regex would be incorrectly stripped of all content by the Unicode letter filter * Fixed a bug in `as.sir()` where values that were purely numeric (e.g., `"1"`) and matched the broad SIR-matching regex would be incorrectly stripped of all content by the Unicode letter filter
* Fixed a bug in `as.mic()` where MIC values in scientific notation (e.g., `"1e-3"`) were incorrectly handled because the letter `e` was removed along with other Unicode letters; scientific notation `e` is now preserved * Fixed a bug in `as.mic()` where MIC values in scientific notation (e.g., `"1e-3"`) were incorrectly handled because the letter `e` was removed along with other Unicode letters; scientific notation `e` is now preserved
* Fixed a bug in `as.ab()` where certain AB codes containing "PH" or "TH" (such as `ETH`, `MTH`, `PHE`, `PHN`, `STH`, `THA`, `THI1`) would incorrectly return `NA` when combined in a vector with any untranslatable value (#245) * Fixed a bug in `as.ab()` where certain AB codes containing "PH" or "TH" (such as `ETH`, `MTH`, `PHE`, `PHN`, `STH`, `THA`, `THI1`) would incorrectly return `NA` when combined in a vector with any untranslatable value (#245)
@@ -31,6 +30,7 @@
* Fixed SIR and MIC coercion of combined values, e.g. `as.sir("<= 0.002; S") ` or `as.mic("S; 0.002")` (#252) * Fixed SIR and MIC coercion of combined values, e.g. `as.sir("<= 0.002; S") ` or `as.mic("S; 0.002")` (#252)
### Updates ### Updates
* `mdro()` now infers resistance for a _missing_ base drug column from an _available_ corresponding drug+inhibitor combination showing resistance (e.g., piperacillin is absent but required, while piperacillin/tazobactam available and resistant). Can be set with the new argument `infer_from_combinations`, which defaults to `TRUE` (#209). Note that this can yield a higher MDRO detection (which is a good thing as it has become more reliable).
* `susceptibility()` and `resistance()` gained the argument `guideline`, which defaults to EUCAST, for interpreting the 'I' category correctly. * `susceptibility()` and `resistance()` gained the argument `guideline`, which defaults to EUCAST, for interpreting the 'I' category correctly.
* `as.mic()` and `rescale_mic()` gained the argument `round_to_next_log2`, which can be set to `TRUE` to round all values up to the nearest next log2 level (#255) * `as.mic()` and `rescale_mic()` gained the argument `round_to_next_log2`, which can be set to `TRUE` to round all values up to the nearest next log2 level (#255)
* `antimicrobials$group` is now a `list` instead of a `character`, to contain any group the drug is in (#246) * `antimicrobials$group` is now a `list` instead of a `character`, to contain any group the drug is in (#246)

View File

@@ -387,6 +387,10 @@ import_fn <- function(name, pkg, error_on_fail = TRUE) {
if (isTRUE(error_on_fail)) { if (isTRUE(error_on_fail)) {
stop_ifnot_installed(pkg) stop_ifnot_installed(pkg)
} }
if (pkg == "rstudioapi" && tryCatch(!rstudioapi::isAvailable(), error = function(e) TRUE)) {
# only allow rstudioapi to be imported if RStudio is available
return(NULL)
}
tryCatch( tryCatch(
# don't use get() to avoid fetching non-API functions # don't use get() to avoid fetching non-API functions
getExportedValue(name = name, ns = asNamespace(pkg)), getExportedValue(name = name, ns = asNamespace(pkg)),
@@ -1220,10 +1224,14 @@ try_colour <- function(..., before, after, collapse = " ") {
} }
} }
is_dark <- function() { is_dark <- function() {
AMR_env$current_theme <- tryCatch(getExportedValue("getThemeInfo", ns = asNamespace("rstudioapi"))()$editor, error = function(e) NULL) AMR_env$current_theme <- NULL
current_theme_fn <- import_fn("getThemeInfo", "rstudioapi", error_on_fail = FALSE)
if (!is.null(current_theme_fn)) {
AMR_env$current_theme <- current_theme_fn()$editor
}
if (!identical(AMR_env$current_theme, AMR_env$former_theme) || is.null(AMR_env$is_dark_theme)) { if (!identical(AMR_env$current_theme, AMR_env$former_theme) || is.null(AMR_env$is_dark_theme)) {
AMR_env$former_theme <- AMR_env$current_theme AMR_env$former_theme <- AMR_env$current_theme
AMR_env$is_dark_theme <- !has_colour() || tryCatch(isTRUE(getExportedValue("getThemeInfo", ns = asNamespace("rstudioapi"))()$dark), error = function(e) TRUE) AMR_env$is_dark_theme <- !has_colour() || tryCatch(isTRUE(current_theme_fn()$dark), error = function(e) TRUE)
} }
isTRUE(AMR_env$is_dark_theme) isTRUE(AMR_env$is_dark_theme)
} }

View File

@@ -31,7 +31,7 @@
#' #'
#' Determine which isolates are multidrug-resistant organisms (MDRO) according to international, national, or custom guidelines. #' Determine which isolates are multidrug-resistant organisms (MDRO) according to international, national, or custom guidelines.
#' @param x A [data.frame] with antimicrobials columns, like `AMX` or `amox`. Can be left blank for automatic determination. #' @param x A [data.frame] with antimicrobials columns, like `AMX` or `amox`. Can be left blank for automatic determination.
#' @param guideline A specific guideline to follow, see sections *Supported international / national guidelines* and *Using Custom Guidelines* below. When left empty, the publication by Magiorakos *et al.* (see below) will be followed. #' @param guideline A specific guideline to follow, see sections *Supported International / National Guidelines* and *Using Custom Guidelines* below. When left empty, the publication by Magiorakos *et al.* (see below) will be followed.
#' @param esbl [logical] values, or a column name containing logical values, indicating the presence of an ESBL gene (or production of its proteins). #' @param esbl [logical] values, or a column name containing logical values, indicating the presence of an ESBL gene (or production of its proteins).
#' @param carbapenemase [logical] values, or a column name containing logical values, indicating the presence of a carbapenemase gene (or production of its proteins). #' @param carbapenemase [logical] values, or a column name containing logical values, indicating the presence of a carbapenemase gene (or production of its proteins).
#' @param mecA [logical] values, or a column name containing logical values, indicating the presence of a *mecA* gene (or production of its proteins). #' @param mecA [logical] values, or a column name containing logical values, indicating the presence of a *mecA* gene (or production of its proteins).
@@ -42,6 +42,7 @@
#' @param pct_required_classes Minimal required percentage of antimicrobial classes that must be available per isolate, rounded down. For example, with the default guideline, 17 antimicrobial classes must be available for *S. aureus*. Setting this `pct_required_classes` argument to `0.5` (default) means that for every *S. aureus* isolate at least 8 different classes must be available. Any lower number of available classes will return `NA` for that isolate. #' @param pct_required_classes Minimal required percentage of antimicrobial classes that must be available per isolate, rounded down. For example, with the default guideline, 17 antimicrobial classes must be available for *S. aureus*. Setting this `pct_required_classes` argument to `0.5` (default) means that for every *S. aureus* isolate at least 8 different classes must be available. Any lower number of available classes will return `NA` for that isolate.
#' @param combine_SI A [logical] to indicate whether all values of S and I must be merged into one, so resistance is only considered when isolates are R, not I. As this is the default behaviour of the [mdro()] function, it follows the redefinition by EUCAST about the interpretation of I (increased exposure) in 2019, see section 'Interpretation of S, I and R' below. When using `combine_SI = FALSE`, resistance is considered when isolates are R or I. #' @param combine_SI A [logical] to indicate whether all values of S and I must be merged into one, so resistance is only considered when isolates are R, not I. As this is the default behaviour of the [mdro()] function, it follows the redefinition by EUCAST about the interpretation of I (increased exposure) in 2019, see section 'Interpretation of S, I and R' below. When using `combine_SI = FALSE`, resistance is considered when isolates are R or I.
#' @param verbose A [logical] to turn Verbose mode on and off (default is off). In Verbose mode, the function returns a data set with the MDRO results in logbook form with extensive info about which isolates would be MDRO-positive, or why they are not. #' @param verbose A [logical] to turn Verbose mode on and off (default is off). In Verbose mode, the function returns a data set with the MDRO results in logbook form with extensive info about which isolates would be MDRO-positive, or why they are not.
#' @param infer_from_combinations A [logical] to indicate whether resistance for a missing base beta-lactam drug should be inferred from an available drug+inhibitor combination (e.g., piperacillin from piperacillin/tazobactam). The clinical basis is that resistance in a combination always implies resistance in the base drug, since the enzyme inhibitor provides no benefit when the organism is truly resistant. Only resistance is inferred; susceptibility in a combination does **not** imply susceptibility in the base drug (the inhibitor may be responsible). Defaults to `TRUE`.
#' @details #' @details
#' These functions are context-aware. This means that the `x` argument can be left blank if used inside a [data.frame] call, see *Examples*. #' These functions are context-aware. This means that the `x` argument can be left blank if used inside a [data.frame] call, see *Examples*.
#' #'
@@ -143,6 +144,7 @@ mdro <- function(x = NULL,
combine_SI = TRUE, combine_SI = TRUE,
verbose = FALSE, verbose = FALSE,
only_sir_columns = any(is.sir(x)), only_sir_columns = any(is.sir(x)),
infer_from_combinations = TRUE,
...) { ...) {
if (is_null_or_grouped_tbl(x)) { if (is_null_or_grouped_tbl(x)) {
# when `x` is left blank, auto determine it (get_current_data() searches underlying data within call) # when `x` is left blank, auto determine it (get_current_data() searches underlying data within call)
@@ -165,7 +167,7 @@ mdro <- function(x = NULL,
meet_criteria(combine_SI, allow_class = "logical", has_length = 1) meet_criteria(combine_SI, allow_class = "logical", has_length = 1)
meet_criteria(verbose, allow_class = "logical", has_length = 1) meet_criteria(verbose, allow_class = "logical", has_length = 1)
meet_criteria(only_sir_columns, allow_class = "logical", has_length = 1) meet_criteria(only_sir_columns, allow_class = "logical", has_length = 1)
meet_criteria(infer_from_combinations, allow_class = "logical", has_length = 1)
if (isTRUE(only_sir_columns) && !any(is.sir(x))) { if (isTRUE(only_sir_columns) && !any(is.sir(x))) {
stop_("There were no SIR columns found in the data set, despite `only_sir_columns` being `TRUE`. Transform columns with `as.sir()` for valid antimicrobial interpretations.") stop_("There were no SIR columns found in the data set, despite `only_sir_columns` being `TRUE`. Transform columns with `as.sir()` for valid antimicrobial interpretations.")
@@ -480,49 +482,51 @@ mdro <- function(x = NULL,
} }
cols_ab <- cols_ab[!duplicated(cols_ab)] cols_ab <- cols_ab[!duplicated(cols_ab)]
# Infer resistance for missing base drugs from available drug+inhibitor combination columns. # Infer resistance for missing base drugs ----
# Clinical principle: resistance in drug+inhibitor (e.g., piperacillin/tazobactam = R) if (isTRUE(infer_from_combinations)) {
# always implies resistance in the base drug (e.g., piperacillin = R), because the .combos_in_data <- AB_BETALACTAMS_WITH_INHIBITOR[AB_BETALACTAMS_WITH_INHIBITOR %in% names(cols_ab)]
# enzyme inhibitor adds nothing when the organism is truly resistant to the base drug. if (length(.combos_in_data) > 0) {
# NOTE: susceptibility in a combination does NOT imply susceptibility in the base drug .base_drugs <- suppressMessages(
# (the inhibitor may be responsible), so synthetic proxy columns only propagate R, not S/I. as.ab(gsub("/.*", "", ab_name(as.character(.combos_in_data), language = NULL)))
.combos_in_data <- AB_BETALACTAMS_WITH_INHIBITOR[AB_BETALACTAMS_WITH_INHIBITOR %in% names(cols_ab)] )
if (length(.combos_in_data) > 0) { .unique_bases <- unique(.base_drugs[!is.na(.base_drugs)])
.base_drugs <- suppressMessages( for (.base in .unique_bases) {
as.ab(gsub("/.*", "", ab_name(as.character(.combos_in_data), language = NULL))) .base_code <- as.character(.base)
) if (!.base_code %in% names(cols_ab)) {
.unique_bases <- unique(.base_drugs[!is.na(.base_drugs)]) # Base drug column absent; find all available combo columns for this base drug
for (.base in .unique_bases) { .combos <- .combos_in_data[!is.na(.base_drugs) & as.character(.base_drugs) == .base_code]
.base_code <- as.character(.base) .combo_cols <- unname(cols_ab[as.character(.combos)])
if (!.base_code %in% names(cols_ab)) { .combo_cols <- .combo_cols[!is.na(.combo_cols)]
# Base drug column absent; find all available combo columns for this base drug if (length(.combo_cols) > 0) {
.combos <- .combos_in_data[!is.na(.base_drugs) & as.character(.base_drugs) == .base_code] # Vectorised: if ANY combination is R, infer base drug as R; otherwise NA
.combo_cols <- unname(cols_ab[as.character(.combos)]) .sir_chars <- as.data.frame(
.combo_cols <- .combo_cols[!is.na(.combo_cols)] lapply(x[, .combo_cols, drop = FALSE], function(col) as.character(as.sir(col))),
if (length(.combo_cols) > 0) { stringsAsFactors = FALSE
# Vectorised: if ANY combination is R, infer base drug as R; otherwise NA
.sir_chars <- as.data.frame(
lapply(x[, .combo_cols, drop = FALSE], function(col) as.character(as.sir(col))),
stringsAsFactors = FALSE
)
.new_col <- paste0(".sir_proxy_", .base_code)
x[[.new_col]] <- ifelse(rowSums(.sir_chars == "R", na.rm = TRUE) > 0L, "R", NA_character_)
cols_ab <- c(cols_ab, stats::setNames(.new_col, .base_code))
if (isTRUE(verbose)) {
message_(
"Inferring resistance for ", ab_name(.base_code, language = NULL),
" from available drug+inhibitor combination(s): ",
paste(ab_name(as.character(.combos), language = NULL), collapse = ", "),
" (resistance in a combination always implies resistance in the base drug)",
add_fn = font_blue
) )
.new_col <- paste0(.base_code, ".inferred_sir_proxy_from#", paste0(.combos, collapse = "/"), "#")
x[[.new_col]] <- ifelse(rowSums(.sir_chars == "R", na.rm = TRUE) > 0L, "R", NA_character_)
cols_ab <- c(cols_ab, stats::setNames(.new_col, .base_code))
if (info == TRUE) {
message_(
"Inferring resistance for ",
ab_name(.base_code, language = NULL, tolower = TRUE),
" (", font_bold(.base_code, collapse = NULL), ", ", font_italic("missing"), ") from ",
vector_or(
quotes = FALSE,
last_sep = " and/or ",
paste0(
ab_name(.combos, language = NULL, tolower = TRUE),
" (", font_bold(.combos, collapse = NULL), ", ", font_italic("available"), ")"
)
)
)
}
} }
} }
} }
cols_ab <- cols_ab[!duplicated(names(cols_ab))]
} }
cols_ab <- cols_ab[!duplicated(names(cols_ab))]
} }
rm(list = intersect(ls(), c(".combos_in_data", ".base_drugs", ".unique_bases", ".base", ".base_code", ".combos", ".combo_cols", ".sir_chars", ".new_col")))
# nolint start # nolint start
AMC <- cols_ab["AMC"] AMC <- cols_ab["AMC"]
@@ -1937,7 +1941,8 @@ mdro <- function(x = NULL,
# format data set # format data set
colnames(x)[colnames(x) == col_mo] <- "microorganism" colnames(x)[colnames(x) == col_mo] <- "microorganism"
x$microorganism <- mo_name(x$microorganism, language = NULL) x$microorganism <- mo_name(x$microorganism, language = NULL)
x$guideline <- paste0(guideline$author, " - ", guideline$name, ", ", guideline$version, ")") x$guideline <- paste0(guideline$author, " - ", guideline$name, ifelse(is.na(guideline$version), "", paste0(" (", guideline$version, ")")))
x$all_nonsusceptible_columns <- gsub(".inferred_sir_proxy_from#(.*?)#", " (inferred from \\1)", x$all_nonsusceptible_columns, perl = TRUE)
x[, c( x[, c(
"row_number", "row_number",
"microorganism", "microorganism",

View File

@@ -18,7 +18,8 @@
mdro(x = NULL, guideline = "CMI 2012", col_mo = NULL, esbl = NA, mdro(x = NULL, guideline = "CMI 2012", col_mo = NULL, esbl = NA,
carbapenemase = NA, mecA = NA, mecC = NA, vanA = NA, vanB = NA, carbapenemase = NA, mecA = NA, mecC = NA, vanA = NA, vanB = NA,
info = interactive(), pct_required_classes = 0.5, combine_SI = TRUE, info = interactive(), pct_required_classes = 0.5, combine_SI = TRUE,
verbose = FALSE, only_sir_columns = any(is.sir(x)), ...) verbose = FALSE, only_sir_columns = any(is.sir(x)),
infer_from_combinations = TRUE, ...)
brmo(x = NULL, only_sir_columns = any(is.sir(x)), ...) brmo(x = NULL, only_sir_columns = any(is.sir(x)), ...)
@@ -35,7 +36,7 @@ eucast_exceptional_phenotypes(x = NULL, only_sir_columns = any(is.sir(x)),
\arguments{ \arguments{
\item{x}{A \link{data.frame} with antimicrobials columns, like \code{AMX} or \code{amox}. Can be left blank for automatic determination.} \item{x}{A \link{data.frame} with antimicrobials columns, like \code{AMX} or \code{amox}. Can be left blank for automatic determination.}
\item{guideline}{A specific guideline to follow, see sections \emph{Supported international / national guidelines} and \emph{Using Custom Guidelines} below. When left empty, the publication by Magiorakos \emph{et al.} (see below) will be followed.} \item{guideline}{A specific guideline to follow, see sections \emph{Supported International / National Guidelines} and \emph{Using Custom Guidelines} below. When left empty, the publication by Magiorakos \emph{et al.} (see below) will be followed.}
\item{col_mo}{Column name of the names or codes of the microorganisms (see \code{\link[=as.mo]{as.mo()}}) - the default is the first column of class \code{\link{mo}}. Values will be coerced using \code{\link[=as.mo]{as.mo()}}.} \item{col_mo}{Column name of the names or codes of the microorganisms (see \code{\link[=as.mo]{as.mo()}}) - the default is the first column of class \code{\link{mo}}. Values will be coerced using \code{\link[=as.mo]{as.mo()}}.}
@@ -61,6 +62,8 @@ eucast_exceptional_phenotypes(x = NULL, only_sir_columns = any(is.sir(x)),
\item{only_sir_columns}{A \link{logical} to indicate whether only antimicrobial columns must be included that were transformed to class \link[=as.sir]{sir} on beforehand. Defaults to \code{FALSE} if no columns of \code{x} have a class \link[=as.sir]{sir}.} \item{only_sir_columns}{A \link{logical} to indicate whether only antimicrobial columns must be included that were transformed to class \link[=as.sir]{sir} on beforehand. Defaults to \code{FALSE} if no columns of \code{x} have a class \link[=as.sir]{sir}.}
\item{infer_from_combinations}{A \link{logical} to indicate whether resistance for a missing base beta-lactam drug should be inferred from an available drug+inhibitor combination (e.g., piperacillin from piperacillin/tazobactam). The clinical basis is that resistance in a combination always implies resistance in the base drug, since the enzyme inhibitor provides no benefit when the organism is truly resistant. Only resistance is inferred; susceptibility in a combination does \strong{not} imply susceptibility in the base drug (the inhibitor may be responsible). Defaults to \code{TRUE}.}
\item{...}{Column names of antimicrobials. To automatically detect antimicrobial column names, do not provide any named arguments; \code{\link[=guess_ab_col]{guess_ab_col()}} will then be used for detection. To manually specify a column, provide its name (case-insensitive) as an argument, e.g. \code{AMX = "amoxicillin"}. To skip a specific antimicrobial, set it to \code{NULL}, e.g. \code{TIC = NULL} to exclude ticarcillin. If a manually defined column does not exist in the data, it will be skipped with a warning.} \item{...}{Column names of antimicrobials. To automatically detect antimicrobial column names, do not provide any named arguments; \code{\link[=guess_ab_col]{guess_ab_col()}} will then be used for detection. To manually specify a column, provide its name (case-insensitive) as an argument, e.g. \code{AMX = "amoxicillin"}. To skip a specific antimicrobial, set it to \code{NULL}, e.g. \code{TIC = NULL} to exclude ticarcillin. If a manually defined column does not exist in the data, it will be skipped with a warning.}
} }
\value{ \value{

View File

@@ -313,14 +313,14 @@ test_that("test-mdro.R", {
# Inference message goes to message() / stderr, not stdout # Inference message goes to message() / stderr, not stdout
# -> must use expect_message(), NOT expect_output() # -> must use expect_message(), NOT expect_output()
expect_message( expect_message(
suppressWarnings(mdro(pseud_no_pip, guideline = "mrgn", info = FALSE, verbose = TRUE)), suppressWarnings(mdro(pseud_no_pip, guideline = "mrgn", info = TRUE)),
"Inferring resistance" "Inferring resistance"
) )
# With TZP=R, PIP is inferred R -> 4MRGN criteria met -> level 3 (> 1) inferred <- suppressWarnings(mdro(pseud_no_pip, guideline = "mrgn", info = FALSE))
result_no_pip <- suppressMessages(suppressWarnings( not_inferred <- suppressWarnings(mdro(pseud_no_pip, guideline = "mrgn", info = FALSE, infer_from_combinations = FALSE))
mdro(pseud_no_pip, guideline = "mrgn", info = FALSE) expect_equal(as.character(inferred), "4MRGN")
)) expect_equal(as.character(not_inferred), "Negative")
expect_true(as.integer(result_no_pip) > 1L)
# Susceptibility in combo does NOT propagate: proxy = NA, not S # Susceptibility in combo does NOT propagate: proxy = NA, not S
# -> 4MRGN criteria no longer met -> lower level than when TZP=R # -> 4MRGN criteria no longer met -> lower level than when TZP=R
pseud_tzp_s <- pseud_no_pip pseud_tzp_s <- pseud_no_pip
@@ -328,18 +328,23 @@ test_that("test-mdro.R", {
result_tzp_s <- suppressMessages(suppressWarnings( result_tzp_s <- suppressMessages(suppressWarnings(
mdro(pseud_tzp_s, guideline = "mrgn", info = FALSE) mdro(pseud_tzp_s, guideline = "mrgn", info = FALSE)
)) ))
expect_true(as.integer(result_tzp_s) < as.integer(result_no_pip)) expect_true(as.integer(result_tzp_s) < as.integer(inferred))
# Multiple combos for the same base drug: AMX can come from AMC (amoxicillin/clavulanic acid) # Multiple combos for the same base drug: AMX can come from AMC (amoxi/clavulanic acid) and AXS (amoxi/sulbactam)
ente_no_amx <- data.frame( ente_no_amx <- data.frame(
mo = as.mo("Enterococcus faecium"), mo = as.mo("Enterococcus faecium"),
AMC = as.sir("R"), # amoxicillin/clavulanic acid; no AMX column AMC = as.sir("R"), # amoxicillin/clavulanic acid
AXS = as.sir("R"), # amoxicillin/sulbactam
VAN = as.sir("R"), VAN = as.sir("R"),
TEC = as.sir("R"), TEC = as.sir("R"),
LNZ = as.sir("R"), LNZ = as.sir("R"),
DAP = as.sir("R"), DAP = as.sir("R"),
stringsAsFactors = FALSE stringsAsFactors = FALSE
) )
# Should run without error and return an ordered factor; AMX inferred R from AMC # Should have multiple columns in the verbose explanation
expect_inherits(suppressMessages(suppressWarnings(mdro(ente_no_amx, guideline = "EUCAST", info = FALSE))), c("factor", "ordered")) out <- mdro(ente_no_amx, guideline = "EUCAST 3.3", info = FALSE, verbose = TRUE)
expect_identical(
out$all_nonsusceptible_columns,
"AMC, AMX (inferred from AMC/AXS), AXS, DAP, LNZ, TEC, VAN"
)
}) })