From a4dc37a4e4157c31111429660affff762dab998f Mon Sep 17 00:00:00 2001 From: Matthijs Berends Date: Mon, 17 Jun 2024 16:52:12 +0200 Subject: [PATCH] (v2.1.1.9057) fix for missing breakpoints --- DESCRIPTION | 2 +- NEWS.md | 2 +- R/data.R | 4 +- R/sir.R | 75 +++++++++++++++++++++++-------------- _pkgdown.yml | 6 +-- man/as.sir.Rd | 25 ++++++------- man/clinical_breakpoints.Rd | 4 +- 7 files changed, 67 insertions(+), 51 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 033a8b86..b0e873f8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,5 +1,5 @@ Package: AMR -Version: 2.1.1.9056 +Version: 2.1.1.9057 Date: 2024-06-17 Title: Antimicrobial Resistance Data Analysis Description: Functions to simplify and standardise antimicrobial resistance (AMR) diff --git a/NEWS.md b/NEWS.md index ce5b37db..3e291835 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# AMR 2.1.1.9056 +# AMR 2.1.1.9057 *(this beta version will eventually become v3.0. We're happy to reach a new major milestone soon, which will be all about the new One Health support! Install this beta using [the instructions here](https://msberends.github.io/AMR/#latest-development-version).)* diff --git a/R/data.R b/R/data.R index 3993b3c7..aafc742e 100755 --- a/R/data.R +++ b/R/data.R @@ -290,10 +290,10 @@ #' The default is `"human"`, which can also be set with the [package option][AMR-options] [`AMR_breakpoint_type`][AMR-options]. Use [`as.sir(..., breakpoint_type = ...)`][as.sir()] to interpret raw data using a specific breakpoint type, e.g. `as.sir(..., breakpoint_type = "ECOFF")` to use ECOFFs. #' #' ### Imported from WHONET -#' Clinical breakpoints in this package were validated through and imported from [WHONET](https://whonet.org), a free desktop Windows application developed and supported by the WHO Collaborating Centre for Surveillance of Antimicrobial Resistance. More can be read on [their website](https://whonet.org). The developers of WHONET and this `AMR` package have been in contact about sharing their work. We highly appreciate their development on the WHONET software. +#' Clinical breakpoints in this package were validated through and imported from [WHONET](https://whonet.org), a free desktop Windows application developed and supported by the WHO Collaborating Centre for Surveillance of Antimicrobial Resistance. More can be read on [their website](https://whonet.org). The developers of WHONET and this `AMR` package have been in contact about sharing their work. We highly appreciate their great development on the WHONET software. #' #' ### Response from CLSI and EUCAST -#' The CEO of CLSI and the chairman of EUCAST have endorsed the work and public use of this `AMR` package (and consequently the use of their breakpoints) in June 2023, when future development of distributing clinical breakpoints was discussed in a meeting between CLSI, EUCAST, the WHO, and developers of WHONET and the `AMR` package. +#' The CEO of CLSI and the chairman of EUCAST have endorsed the work and public use of this `AMR` package (and consequently the use of their breakpoints) in June 2023, when future development of distributing clinical breakpoints was discussed in a meeting between CLSI, EUCAST, WHO, developers of WHONET software, and developers of this `AMR` package. #' #' ### Download #' Like all data sets in this package, this data set is publicly available for download in the following formats: R, MS Excel, Apache Feather, Apache Parquet, SPSS, SAS, and Stata. Please visit [our website for the download links](https://msberends.github.io/AMR/articles/datasets.html). The actual files are of course available on [our GitHub repository](https://github.com/msberends/AMR/tree/main/data-raw). They allow for machine reading EUCAST and CLSI guidelines, which is almost impossible with the MS Excel and PDF files distributed by EUCAST and CLSI, though initiatives have started to overcome these burdens. diff --git a/R/sir.R b/R/sir.R index fd8a8638..7bd23c94 100755 --- a/R/sir.R +++ b/R/sir.R @@ -152,6 +152,8 @@ #' - **CLSI M100: Performance Standard for Antimicrobial Susceptibility Testing**, `r min(as.integer(gsub("[^0-9]", "", subset(AMR::clinical_breakpoints, guideline %like% "CLSI" & type != "animal")$guideline)))`-`r max(as.integer(gsub("[^0-9]", "", subset(AMR::clinical_breakpoints, guideline %like% "CLSI" & type != "animal")$guideline)))`, *Clinical and Laboratory Standards Institute* (CLSI). . #' - **CLSI VET01: Performance Standards for Antimicrobial Disk and Dilution Susceptibility Tests for Bacteria Isolated From Animals**, `r min(as.integer(gsub("[^0-9]", "", subset(AMR::clinical_breakpoints, guideline %like% "CLSI" & type == "animal")$guideline)))`-`r max(as.integer(gsub("[^0-9]", "", subset(AMR::clinical_breakpoints, guideline %like% "CLSI" & type == "animal")$guideline)))`, *Clinical and Laboratory Standards Institute* (CLSI). . #' - **EUCAST Breakpoint tables for interpretation of MICs and zone diameters**, `r min(as.integer(gsub("[^0-9]", "", subset(AMR::clinical_breakpoints, guideline %like% "EUCAST")$guideline)))`-`r max(as.integer(gsub("[^0-9]", "", subset(AMR::clinical_breakpoints, guideline %like% "EUCAST")$guideline)))`, *European Committee on Antimicrobial Susceptibility Testing* (EUCAST). . +#' - **WHONET** as a source for machine-reading clinical breakpoints ((read more here)[https://msberends.github.io/AMR/reference/clinical_breakpoints.html#imported-from-whonet]), 1989-`r max(as.integer(gsub("[^0-9]", "", AMR::clinical_breakpoints$guideline)))`, *WHO Collaborating Centre for Surveillance of Antimicrobial Resistance*. . +#' #' @inheritSection AMR Reference Data Publicly Available #' @examples #' example_isolates @@ -162,10 +164,10 @@ #' # example data sets, with combined MIC values and disk zones #' df_wide <- data.frame( #' microorganism = "Escherichia coli", -#' AMP = as.mic(8), -#' CIP = as.mic(0.256), -#' GEN = as.disk(18), -#' TOB = as.disk(16), +#' amoxicillin = as.mic(8), +#' cipro = as.mic(0.256), +#' tobra = as.disk(16), +#' genta = as.disk(18), #' ERY = "R" #' ) #' df_long <- data.frame( @@ -182,8 +184,8 @@ #' 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(across(where(is.mic), as.sir)) -#' df_wide %>% mutate_at(vars(AMP:TOB), as.sir) -#' df_wide %>% mutate(across(AMP:TOB, as.sir)) +#' df_wide %>% mutate_at(vars(amoxicillin:tobra), as.sir) +#' df_wide %>% mutate(across(amoxicillin:tobra, as.sir)) #' #' # approaches that all work with additional arguments: #' df_long %>% @@ -198,17 +200,15 @@ #' mo = "bacteria", #' ab = "antibiotic", #' guideline = "CLSI"))) -#' df_long %>% +#' df_wide %>% #' # given certain columns, e.g. from 'cipro' to 'genta' #' mutate_at(vars(cipro:genta), as.sir, #' mo = "bacteria", -#' ab = "antibiotic", #' guideline = "CLSI") -#' df_long %>% +#' df_wide %>% #' mutate(across(cipro:genta, #' function(x) as.sir(x, #' mo = "bacteria", -#' ab = "antibiotic", #' guideline = "CLSI"))) #' #' # for veterinary breakpoints, add 'host': @@ -227,18 +227,16 @@ #' ab = "antibiotic", #' host = "animal_species", #' guideline = "CLSI"))) -#' df_long %>% -#' # given certain columns, e.g. from AMP to TOB +#' df_wide %>% #' mutate_at(vars(cipro:genta), as.sir, #' mo = "bacteria", #' ab = "antibiotic", #' host = "animal_species", #' guideline = "CLSI") -#' df_long %>% +#' df_wide %>% #' mutate(across(cipro:genta, #' function(x) as.sir(x, #' mo = "bacteria", -#' ab = "antibiotic", #' host = "animal_species", #' guideline = "CLSI"))) #' @@ -890,6 +888,13 @@ as_sir_method <- function(method_short, guideline_coerced <- get_guideline(guideline, reference_data) + if (message_not_thrown_before("as.sir", "sir_interpretation_history")) { + message_("Run `sir_interpretation_history()` afterwards to retrieve a logbook with all the details of the breakpoint interpretations.\n\n", add_fn = font_green) + } + + current_df <- tryCatch(get_current_data(NA, 0), error = function(e) NULL) + + # get host if (breakpoint_type == "animal") { if (is.null(host)) { host <- AMR_env$host_preferred_order[1] @@ -907,17 +912,23 @@ as_sir_method <- function(method_short, host <- breakpoint_type } } - host <- convert_host(host) - - if (message_not_thrown_before("as.sir", "sir_interpretation_history")) { - message_("Run `sir_interpretation_history()` afterwards to retrieve a logbook with all the details of the breakpoint interpretations.\n\n", add_fn = font_red) + if (!is.null(current_df) && length(host) == 1 && host %in% colnames(current_df) && any(current_df[[host]] %like% "[A-Z]", na.rm = TRUE)) { + host <- current_df[[host]] + } else if (length(host) != length(x)) { + # for dplyr's across() + cur_column_dplyr <- import_fn("cur_column", "dplyr", error_on_fail = FALSE) + if (!is.null(cur_column_dplyr) && is.data.frame(current_df)) { + # try to get current column, which will only be available when in across() + host <- tryCatch(cur_column_dplyr(), + error = function(e) host + ) + } } + host <- convert_host(host) if (breakpoint_type == "animal" && message_not_thrown_before("as.sir", "host_preferred_order")) { message_("Please note that in the absence of specific veterinary breakpoints for certain animal hosts, breakpoints for dogs, cattle, swine, cats, horse, aquatic, and poultry, in that order, are used as substitutes.\n\n") } - current_df <- tryCatch(get_current_data(NA, 0), error = function(e) NULL) - # get ab if (!is.null(current_df) && length(ab) == 1 && ab %in% colnames(current_df) && any(current_df[[ab]] %like% "[A-Z]", na.rm = TRUE)) { ab <- current_df[[ab]] @@ -1166,6 +1177,12 @@ as_sir_method <- function(method_short, } else { rows <- which(df$mo == mo_current & df$ab == ab_current & df$host == host_current & df$uti == uti_current) } + if (length(rows) == 0) { + notes_current <- c(notes_current, font_red("Returned an empty result, which is unexpected. Are all of `mo`, `ab`, and `host` set and available?")) + notes <- c(notes, notes_current) + rise_warning <- TRUE + next + } values <- df[rows, "values", drop = TRUE] new_sir <- rep(NA_sir_, length(rows)) @@ -1204,7 +1221,6 @@ as_sir_method <- function(method_short, )) if (NROW(breakpoints_current) == 0) { - # no note about missing breakpoints - it's already in the header before the interpretation starts AMR_env$sir_interpretation_history <- rbind_AMR( AMR_env$sir_interpretation_history, # recycling 1 to 2 rows does not always seem to work, which is why vectorise_log_entry() was added @@ -1228,6 +1244,7 @@ as_sir_method <- function(method_short, stringsAsFactors = FALSE ) ) + notes <- c(notes, notes_current) next } @@ -1326,7 +1343,7 @@ as_sir_method <- function(method_short, TRUE ~ NA_sir_ ) } - + # write to verbose output AMR_env$sir_interpretation_history <- rbind_AMR( AMR_env$sir_interpretation_history, @@ -1358,17 +1375,19 @@ as_sir_method <- function(method_short, } close(p) - # printing messages if (has_progress_bar == TRUE) { # the progress bar has overwritten the intro text, so: message_(intro_txt, appendLF = FALSE, as_note = FALSE) } - if (isTRUE(rise_warning)) { - message(font_rose_bg(" WARNING ")) - } else if (length(notes) > 0) { - message(font_yellow_bg(" NOTES ")) - if (isTRUE(verbose) || length(notes) == 1) { + if (length(notes) > 0) { + if (isTRUE(rise_warning)) { + message(font_rose_bg(" WARNING ")) + } else { + message(font_yellow_bg(" NOTE ")) + } + notes <- unique(notes) + if (isTRUE(verbose) || length(notes) == 1 || NROW(AMR_env$sir_interpretation_history) == 0) { for (i in seq_len(length(notes))) { message(word_wrap(" ", AMR_env$bullet_icon, " ", notes[i], add_fn = font_black)) } diff --git a/_pkgdown.yml b/_pkgdown.yml index 6e4df96e..186664dc 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -242,16 +242,16 @@ reference: Some pages about our package and its external sources. Be sure to read our [How To's](./../articles/index.html) for more information about how to work with functions in this package. contents: - - "`example_isolates`" - "`microorganisms`" + - "`antibiotics`" + - "`clinical_breakpoints`" + - "`example_isolates`" - "`microorganisms.codes`" - "`microorganisms.groups`" - - "`antibiotics`" - "`intrinsic_resistant`" - "`dosage`" - "`WHOCC`" - "`example_isolates_unclean`" - - "`clinical_breakpoints`" - "`WHONET`" - title: "Other: miscellaneous functions" diff --git a/man/as.sir.Rd b/man/as.sir.Rd index bd10d5d3..f829d043 100644 --- a/man/as.sir.Rd +++ b/man/as.sir.Rd @@ -20,6 +20,7 @@ For interpretations of minimum inhibitory concentration (MIC) values and disk di \item \strong{CLSI M100: Performance Standard for Antimicrobial Susceptibility Testing}, 2011-2024, \emph{Clinical and Laboratory Standards Institute} (CLSI). \url{https://clsi.org/standards/products/microbiology/documents/m100/}. \item \strong{CLSI VET01: Performance Standards for Antimicrobial Disk and Dilution Susceptibility Tests for Bacteria Isolated From Animals}, 2019-2024, \emph{Clinical and Laboratory Standards Institute} (CLSI). \url{https://clsi.org/standards/products/veterinary-medicine/documents/vet01//}. \item \strong{EUCAST Breakpoint tables for interpretation of MICs and zone diameters}, 2011-2024, \emph{European Committee on Antimicrobial Susceptibility Testing} (EUCAST). \url{https://www.eucast.org/clinical_breakpoints}. +\item \strong{WHONET} as a source for machine-reading clinical breakpoints ((read more here)\link{https://msberends.github.io/AMR/reference/clinical_breakpoints.html#imported-from-whonet}), 1989-2024, \emph{WHO Collaborating Centre for Surveillance of Antimicrobial Resistance}. \url{https://whonet.org/}. } } \usage{ @@ -259,10 +260,10 @@ summary(example_isolates) # see all SIR results at a glance # example data sets, with combined MIC values and disk zones df_wide <- data.frame( microorganism = "Escherichia coli", - AMP = as.mic(8), - CIP = as.mic(0.256), - GEN = as.disk(18), - TOB = as.disk(16), + amoxicillin = as.mic(8), + cipro = as.mic(0.256), + tobra = as.disk(16), + genta = as.disk(18), ERY = "R" ) df_long <- data.frame( @@ -279,8 +280,8 @@ if (require("dplyr")) { 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(across(where(is.mic), as.sir)) - df_wide \%>\% mutate_at(vars(AMP:TOB), as.sir) - df_wide \%>\% mutate(across(AMP:TOB, as.sir)) + df_wide \%>\% mutate_at(vars(amoxicillin:tobra), as.sir) + df_wide \%>\% mutate(across(amoxicillin:tobra, as.sir)) # approaches that all work with additional arguments: df_long \%>\% @@ -295,17 +296,15 @@ if (require("dplyr")) { mo = "bacteria", ab = "antibiotic", guideline = "CLSI"))) - df_long \%>\% + df_wide \%>\% # given certain columns, e.g. from 'cipro' to 'genta' mutate_at(vars(cipro:genta), as.sir, mo = "bacteria", - ab = "antibiotic", guideline = "CLSI") - df_long \%>\% + df_wide \%>\% mutate(across(cipro:genta, function(x) as.sir(x, mo = "bacteria", - ab = "antibiotic", guideline = "CLSI"))) # for veterinary breakpoints, add 'host': @@ -324,18 +323,16 @@ if (require("dplyr")) { ab = "antibiotic", host = "animal_species", guideline = "CLSI"))) - df_long \%>\% - # given certain columns, e.g. from AMP to TOB + df_wide \%>\% mutate_at(vars(cipro:genta), as.sir, mo = "bacteria", ab = "antibiotic", host = "animal_species", guideline = "CLSI") - df_long \%>\% + df_wide \%>\% mutate(across(cipro:genta, function(x) as.sir(x, mo = "bacteria", - ab = "antibiotic", host = "animal_species", guideline = "CLSI"))) diff --git a/man/clinical_breakpoints.Rd b/man/clinical_breakpoints.Rd index f069ee53..72d16ba8 100644 --- a/man/clinical_breakpoints.Rd +++ b/man/clinical_breakpoints.Rd @@ -44,12 +44,12 @@ The default is \code{"human"}, which can also be set with the \link[=AMR-options \subsection{Imported from WHONET}{ -Clinical breakpoints in this package were validated through and imported from \href{https://whonet.org}{WHONET}, a free desktop Windows application developed and supported by the WHO Collaborating Centre for Surveillance of Antimicrobial Resistance. More can be read on \href{https://whonet.org}{their website}. The developers of WHONET and this \code{AMR} package have been in contact about sharing their work. We highly appreciate their development on the WHONET software. +Clinical breakpoints in this package were validated through and imported from \href{https://whonet.org}{WHONET}, a free desktop Windows application developed and supported by the WHO Collaborating Centre for Surveillance of Antimicrobial Resistance. More can be read on \href{https://whonet.org}{their website}. The developers of WHONET and this \code{AMR} package have been in contact about sharing their work. We highly appreciate their great development on the WHONET software. } \subsection{Response from CLSI and EUCAST}{ -The CEO of CLSI and the chairman of EUCAST have endorsed the work and public use of this \code{AMR} package (and consequently the use of their breakpoints) in June 2023, when future development of distributing clinical breakpoints was discussed in a meeting between CLSI, EUCAST, the WHO, and developers of WHONET and the \code{AMR} package. +The CEO of CLSI and the chairman of EUCAST have endorsed the work and public use of this \code{AMR} package (and consequently the use of their breakpoints) in June 2023, when future development of distributing clinical breakpoints was discussed in a meeting between CLSI, EUCAST, WHO, developers of WHONET software, and developers of this \code{AMR} package. } \subsection{Download}{