mirror of
https://github.com/msberends/AMR.git
synced 2025-01-14 00:11:50 +01:00
Compare commits
No commits in common. "40edc16fdfb135642d7452d2e1cce1bb667fd843" and "94501371cd8013075fa710426a9f96e55762f9d2" have entirely different histories.
40edc16fdf
...
94501371cd
@ -30,6 +30,7 @@
|
||||
^vignettes/datasets\.Rmd$
|
||||
^vignettes/EUCAST\.Rmd$
|
||||
^vignettes/MDR\.Rmd$
|
||||
^vignettes/other_pkg.*\.Rmd$
|
||||
^vignettes/PCA\.Rmd$
|
||||
^vignettes/resistance_predict\.Rmd$
|
||||
^vignettes/WHONET\.Rmd$
|
||||
|
15
.github/workflows/publish-to-pypi.yml
vendored
15
.github/workflows/publish-to-pypi.yml
vendored
@ -30,7 +30,7 @@
|
||||
on:
|
||||
push:
|
||||
# only on main
|
||||
branches: "main"
|
||||
branches: 'main_UPDATE_THIS'
|
||||
|
||||
name: Publish Python Package to PyPI
|
||||
|
||||
@ -48,22 +48,19 @@ jobs:
|
||||
with:
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Install build dependencies
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install build twine wheel
|
||||
pip install build twine
|
||||
|
||||
- name: Build the Python package
|
||||
run: |
|
||||
cd data-raw/
|
||||
bash _generate_python_wrapper.sh
|
||||
- name: Build the package
|
||||
run: python -m build
|
||||
|
||||
- name: Publish to PyPI
|
||||
env:
|
||||
TWINE_USERNAME: "__token__"
|
||||
TWINE_USERNAME: "msberends"
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
||||
run: |
|
||||
cd data-raw/python_wrapper/AMR
|
||||
python -m twine upload dist/*
|
||||
# for test server:
|
||||
# python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
|
||||
|
@ -1,6 +1,6 @@
|
||||
Package: AMR
|
||||
Version: 2.1.1.9095
|
||||
Date: 2024-10-15
|
||||
Version: 2.1.1.9094
|
||||
Date: 2024-10-10
|
||||
Title: Antimicrobial Resistance Data Analysis
|
||||
Description: Functions to simplify and standardise antimicrobial resistance (AMR)
|
||||
data analysis and to work with microbial and antimicrobial properties by
|
||||
|
5
NEWS.md
5
NEWS.md
@ -1,4 +1,4 @@
|
||||
# AMR 2.1.1.9095
|
||||
# AMR 2.1.1.9094
|
||||
|
||||
*(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).)*
|
||||
|
||||
@ -28,8 +28,6 @@ This package now supports not only tools for AMR data analysis in clinical setti
|
||||
* **New forms for MIC plotting and transforming**
|
||||
* New function group `scale_*_mic()`, namely: `scale_x_mic()`, `scale_y_mic()`, `scale_colour_mic()` and `scale_fill_mic()`. They are advanced ggplot2 extensions to allow easy plotting of MIC values. They allow for manual range definition and plotting missing intermediate log2 levels.
|
||||
* New function `rescale_mic()`, which allows users to rescale MIC values to a manually set range. This is the powerhouse behind the `scale_*_mic()` functions, but it can be used independently to, for instance, compare equality in MIC distributions by rescaling them to the same range first.
|
||||
* **Support for Python**
|
||||
* While using R for the heavy lifting, [our 'AMR' Python Package](https://pypi.org/project/AMR/) was developed to run the AMR R package natively in Python. The Python package will always have the same version number as the R package, as it is built automatically with every code change.
|
||||
* **Other**
|
||||
* New function `mo_group_members()` to retrieve the member microorganisms of a microorganism group. For example, `mo_group_members("Strep group C")` returns a vector of all microorganisms that belong to that group.
|
||||
|
||||
@ -54,7 +52,6 @@ This package now supports not only tools for AMR data analysis in clinical setti
|
||||
* Comparisons of MIC values are now more strict. For example, `>32` is higher than (and never equal to) `32`. Thus, `as.mic(">32") == as.mic(32)` now returns `FALSE`, and `as.mic(">32") > as.mic(32)` now returns `TRUE`.
|
||||
* Sorting of MIC values (using `sort()`) was fixed in the same manner; `<0.001` now gets sorted before `0.001`, and `>0.001` gets sorted after `0.001`.
|
||||
* Intermediate log2 levels used for MIC plotting are now more common values instead of following a strict dilution range
|
||||
* Disks of 0 to 5 mm are now allowed, the newly allowed range for disk diffusion (`as.disk()`) is now between 0 and 50 mm
|
||||
* Updated `italicise_taxonomy()` to support HTML output
|
||||
* `custom_eucast_rules()` now supports multiple antibiotics and antibiotic groups to be affected by a single rule
|
||||
* `mo_info()` now contains an extra element `rank` and `group_members` (with the contents of the new `mo_group_members()` function)
|
||||
|
@ -822,6 +822,7 @@ meet_criteria <- function(object, # can be literally `list(...)` for `allow_argu
|
||||
is_positive = NULL,
|
||||
is_positive_or_zero = NULL,
|
||||
is_finite = NULL,
|
||||
contains_column_class = NULL,
|
||||
allow_NULL = FALSE,
|
||||
allow_NA = FALSE,
|
||||
ignore.case = FALSE,
|
||||
@ -850,11 +851,6 @@ meet_criteria <- function(object, # can be literally `list(...)` for `allow_argu
|
||||
stop_if(allow_NA == FALSE, "argument `", obj_name, "` must not be NA", call = call_depth)
|
||||
return(invisible())
|
||||
}
|
||||
|
||||
if (identical(class(object), "list") && !"list" %in% allow_class) {
|
||||
# coming from Python, possibly - turn lists (not data.frame) to the underlying data type
|
||||
object <- unlist(object)
|
||||
}
|
||||
|
||||
if (!is.null(allow_class) && !(suppressWarnings(all(is.na(object))) && allow_NA == TRUE)) {
|
||||
stop_ifnot(inherits(object, allow_class), "argument `", obj_name,
|
||||
@ -941,6 +937,21 @@ meet_criteria <- function(object, # can be literally `list(...)` for `allow_argu
|
||||
call = call_depth
|
||||
)
|
||||
}
|
||||
if (!is.null(contains_column_class)) {
|
||||
stop_ifnot(
|
||||
any(vapply(
|
||||
FUN.VALUE = logical(1),
|
||||
object,
|
||||
function(col, columns_class = contains_column_class) {
|
||||
inherits(col, columns_class)
|
||||
}
|
||||
), na.rm = TRUE),
|
||||
"the data provided in argument `", obj_name,
|
||||
"` must contain at least one column of class '", contains_column_class[1L], "'. ",
|
||||
"See `?as.", contains_column_class[1L], "`.",
|
||||
call = call_depth
|
||||
)
|
||||
}
|
||||
if (!is.null(allow_arguments_from) && !is.null(names(object))) {
|
||||
args_given <- names(object)
|
||||
if (is.function(allow_arguments_from)) {
|
||||
@ -962,20 +973,6 @@ meet_criteria <- function(object, # can be literally `list(...)` for `allow_argu
|
||||
return(invisible())
|
||||
}
|
||||
|
||||
ascertain_sir_classes <- function(x, obj_name) {
|
||||
sirs <- vapply(FUN.VALUE = logical(1), x, is.sir)
|
||||
if (!any(sirs, na.rm = TRUE)) {
|
||||
warning_("the data provided in argument `", obj_name,
|
||||
"` should contain at least one column of class 'sir'. Eligible SIR column were now guessed. ",
|
||||
"See `?as.sir`.")
|
||||
sirs_eligible <- is_sir_eligible(x)
|
||||
for (col in colnames(x)[sirs_eligible]) {
|
||||
x[[col]] <- as.sir(x[[col]])
|
||||
}
|
||||
}
|
||||
x
|
||||
}
|
||||
|
||||
get_current_data <- function(arg_name, call) {
|
||||
valid_df <- function(x) {
|
||||
!is.null(x) && is.data.frame(x)
|
||||
|
@ -313,8 +313,7 @@ antibiogram <- function(x,
|
||||
combine_SI = TRUE,
|
||||
sep = " + ",
|
||||
info = interactive()) {
|
||||
meet_criteria(x, allow_class = "data.frame")
|
||||
x <- ascertain_sir_classes(x, "x")
|
||||
meet_criteria(x, allow_class = "data.frame", contains_column_class = c("sir", "rsi"))
|
||||
meet_criteria(mo_transform, allow_class = "character", has_length = 1, is_in = c("name", "shortname", "gramstain", colnames(AMR::microorganisms)), allow_NULL = TRUE)
|
||||
meet_criteria(ab_transform, allow_class = "character", has_length = 1, is_in = colnames(AMR::antibiotics), allow_NULL = TRUE)
|
||||
meet_criteria(syndromic_group, allow_class = "character", allow_NULL = TRUE, allow_NA = TRUE)
|
||||
|
@ -71,8 +71,7 @@ bug_drug_combinations <- function(x,
|
||||
col_mo = NULL,
|
||||
FUN = mo_shortname,
|
||||
...) {
|
||||
meet_criteria(x, allow_class = "data.frame")
|
||||
x <- ascertain_sir_classes(x, "x")
|
||||
meet_criteria(x, allow_class = "data.frame", contains_column_class = c("sir", "rsi"))
|
||||
meet_criteria(col_mo, allow_class = "character", is_in = colnames(x), has_length = 1, allow_NULL = TRUE)
|
||||
meet_criteria(FUN, allow_class = "function", has_length = 1)
|
||||
|
||||
|
8
R/disk.R
8
R/disk.R
@ -29,13 +29,13 @@
|
||||
|
||||
#' Transform Input to Disk Diffusion Diameters
|
||||
#'
|
||||
#' This transforms a vector to a new class [`disk`], which is a disk diffusion growth zone size (around an antibiotic disk) in millimetres between 0 and 50.
|
||||
#' This transforms a vector to a new class [`disk`], which is a disk diffusion growth zone size (around an antibiotic disk) in millimetres between 6 and 50.
|
||||
#' @rdname as.disk
|
||||
#' @param x vector
|
||||
#' @param na.rm a [logical] indicating whether missing values should be removed
|
||||
#' @details Interpret disk values as SIR values with [as.sir()]. It supports guidelines from EUCAST and CLSI.
|
||||
#'
|
||||
#' Disk diffusion growth zone sizes must be between 0 and 50 millimetres. Values higher than 50 but lower than 100 will be maximised to 50. All others input values outside the 0-50 range will return `NA`.
|
||||
#' Disk diffusion growth zone sizes must be between 6 and 50 millimetres. Values higher than 50 but lower than 100 will be maximised to 50. All others input values outside the 6-50 range will return `NA`.
|
||||
#' @return An [integer] with additional class [`disk`]
|
||||
#' @aliases disk
|
||||
#' @export
|
||||
@ -108,8 +108,8 @@ as.disk <- function(x, na.rm = FALSE) {
|
||||
# round up and make it an integer
|
||||
x <- as.integer(ceiling(clean_double2(x)))
|
||||
|
||||
# disks can never be less than 0 mm or more than 50 mm
|
||||
x[x < 0 | x > 99] <- NA_integer_
|
||||
# disks can never be less than 6 mm (size of smallest disk) or more than 50 mm
|
||||
x[x < 6 | x > 99] <- NA_integer_
|
||||
x[x > 50] <- 50L
|
||||
na_after <- length(x[is.na(x)])
|
||||
|
||||
|
@ -193,8 +193,7 @@ ggplot_sir <- function(data,
|
||||
y.title = "Proportion",
|
||||
...) {
|
||||
stop_ifnot_installed("ggplot2")
|
||||
meet_criteria(data, allow_class = "data.frame")
|
||||
data <- ascertain_sir_classes(data, "data")
|
||||
meet_criteria(data, allow_class = "data.frame", contains_column_class = c("sir", "rsi"))
|
||||
meet_criteria(position, allow_class = "character", has_length = 1, is_in = c("fill", "stack", "dodge"), allow_NULL = TRUE)
|
||||
meet_criteria(x, allow_class = "character", has_length = 1)
|
||||
meet_criteria(fill, allow_class = "character", has_length = 1)
|
||||
|
@ -292,14 +292,14 @@ sir_confidence_interval <- function(...,
|
||||
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5)
|
||||
)
|
||||
|
||||
# this applies the Clopper-Pearson method
|
||||
if (x == 0) {
|
||||
out <- c(0, 0)
|
||||
out <- c(NA_real_, NA_real_)
|
||||
} else {
|
||||
# this applies the Clopper-Pearson method
|
||||
out <- stats::binom.test(x = x, n = n, conf.level = confidence_level)$conf.int
|
||||
}
|
||||
out <- set_clean_class(out, "numeric")
|
||||
|
||||
|
||||
if (side %in% c("left", "l", "lower", "lowest", "less", "min")) {
|
||||
out <- out[1]
|
||||
} else if (side %in% c("right", "r", "higher", "highest", "greater", "g", "max")) {
|
||||
@ -312,7 +312,7 @@ sir_confidence_interval <- function(...,
|
||||
if (is.numeric(out)) {
|
||||
out <- round(out, digits = 3)
|
||||
}
|
||||
# out[is.na(out)] <- 0
|
||||
out[is.na(out)] <- "??"
|
||||
out <- paste(out, collapse = ifelse(isTRUE(collapse), "-", collapse))
|
||||
}
|
||||
|
||||
|
6
R/sir.R
6
R/sir.R
@ -1263,7 +1263,7 @@ as_sir_method <- function(method_short,
|
||||
if (breakpoint_type == "animal" && !host_current %in% breakpoints_current$host) {
|
||||
if (guideline_coerced %like% "CLSI") {
|
||||
# VET09 says that staph/strep/enterococcus BP can be extrapolated to all Gr+ cocci except for intrinsic resistance, so take all Gr+ cocci:
|
||||
all_gram_pos_genera <- c("B_STPHY", "B_STRPT", "B_PPTST", "B_AERCC", "B_MCRCCC", "B_TRPRL")
|
||||
all_gram_pos_genera <- c("B_STPHY", "B_STRPT", "B_ENTRC", "B_PPTST", "B_AERCC", "B_MCRCCC", "B_TRPRL")
|
||||
|
||||
# HUMAN SUBSTITUTES
|
||||
if (ab_current == "AZM" && mo_current_genus %in% all_gram_pos_genera && host_current %in% c("dogs", "cats", "horse")) {
|
||||
@ -1310,9 +1310,9 @@ as_sir_method <- function(method_short,
|
||||
# vancomycin can take human breakpoints in these hosts
|
||||
breakpoints_current <- breakpoints_current %pm>% subset(host == "human")
|
||||
notes_current <- c(notes_current, paste0("Using ", font_bold("human"), " breakpoints for ", ab_formatted, " based on CLSI VET09."))
|
||||
|
||||
|
||||
} else if (host_current %in% c("dogs", "cats") && (mo_current_genus %in% c("B_AMYCS", "B_NOCRD", "B_CMPYL", "B_CRYNB", "B_ENTRC", "B_MYCBC", "B_PSDMN", "B_AERMN") | mo_current_class == "B_[CLS]_BTPRTBCT" | mo_current == "B_LISTR_MNCY")) {
|
||||
# dog breakpoints if no canine/feline
|
||||
# human breakpoints if no canine/feline
|
||||
breakpoints_current <- breakpoints_current %pm>% subset(host == "human")
|
||||
notes_current <- c(notes_current, paste0("Using ", font_bold("human"), " breakpoints for ", mo_formatted, " based on CLSI VET09."))
|
||||
|
||||
|
@ -223,8 +223,7 @@ sir_calc_df <- function(type, # "proportion", "count" or "both"
|
||||
combine_SI = TRUE,
|
||||
confidence_level = 0.95) {
|
||||
meet_criteria(type, is_in = c("proportion", "count", "both"), has_length = 1)
|
||||
meet_criteria(data, allow_class = "data.frame")
|
||||
data <- ascertain_sir_classes(data, "data")
|
||||
meet_criteria(data, allow_class = "data.frame", contains_column_class = "sir")
|
||||
meet_criteria(translate_ab, allow_class = c("character", "logical"), has_length = 1, allow_NA = TRUE)
|
||||
language <- validate_language(language)
|
||||
meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_positive_or_zero = TRUE, is_finite = TRUE)
|
||||
|
@ -29,71 +29,16 @@
|
||||
# how to conduct AMR data analysis: https://msberends.github.io/AMR/ #
|
||||
# ==================================================================== #
|
||||
|
||||
# Clean up
|
||||
rm -rf python_wrapper/AMR/*
|
||||
mkdir -p python_wrapper/AMR/AMR
|
||||
|
||||
# Output Python file
|
||||
functions_file="python_wrapper/AMR/AMR/functions.py"
|
||||
datasets_file="python_wrapper/AMR/AMR/datasets.py"
|
||||
init_file="python_wrapper/AMR/AMR/__init__.py"
|
||||
output_file="python_wrapper/amr_python_wrapper.py"
|
||||
|
||||
# Write header to the datasets Python file, including the convert_to_python function
|
||||
cat <<EOL > "$datasets_file"
|
||||
BLUE = '\033[94m'
|
||||
GREEN = '\033[32m'
|
||||
RESET = '\033[0m'
|
||||
|
||||
print(f"{BLUE}AMR:{RESET} Setting up R environment and AMR datasets...", flush=True)
|
||||
|
||||
from rpy2 import robjects
|
||||
from rpy2.robjects import pandas2ri
|
||||
from rpy2.robjects.packages import importr, isinstalled
|
||||
import pandas as pd
|
||||
|
||||
# Check if the R package is installed
|
||||
if not isinstalled('AMR'):
|
||||
utils = importr('utils')
|
||||
utils.install_packages('AMR')
|
||||
|
||||
# Activate the automatic conversion between R and pandas DataFrames
|
||||
pandas2ri.activate()
|
||||
# example_isolates
|
||||
example_isolates = pandas2ri.rpy2py(robjects.r('''
|
||||
df <- AMR::example_isolates
|
||||
df[] <- lapply(df, function(x) {
|
||||
if (inherits(x, c("Date", "POSIXt", "factor"))) {
|
||||
as.character(x)
|
||||
} else {
|
||||
x
|
||||
}
|
||||
})
|
||||
df
|
||||
'''))
|
||||
example_isolates['date'] = pd.to_datetime(example_isolates['date'])
|
||||
|
||||
# microorganisms
|
||||
microorganisms = pandas2ri.rpy2py(robjects.r('AMR::microorganisms[, !sapply(AMR::microorganisms, is.list)]'))
|
||||
antibiotics = pandas2ri.rpy2py(robjects.r('AMR::antibiotics[, !sapply(AMR::antibiotics, is.list)]'))
|
||||
clinical_breakpoints = pandas2ri.rpy2py(robjects.r('AMR::clinical_breakpoints'))
|
||||
|
||||
print(f"{BLUE}AMR:{RESET} {GREEN}Done.{RESET}", flush=True)
|
||||
EOL
|
||||
|
||||
echo "from .datasets import example_isolates" >> $init_file
|
||||
echo "from .datasets import microorganisms" >> $init_file
|
||||
echo "from .datasets import antibiotics" >> $init_file
|
||||
echo "from .datasets import clinical_breakpoints" >> $init_file
|
||||
|
||||
|
||||
# Write header to the functions Python file, including the convert_to_python function
|
||||
cat <<EOL > "$functions_file"
|
||||
# Write header to the output Python file, including the convert_to_python function
|
||||
cat <<EOL > "$output_file"
|
||||
import rpy2.robjects as robjects
|
||||
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
|
||||
from rpy2.robjects import pandas2ri
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
# Activate automatic conversion between R data frames and pandas data frames
|
||||
pandas2ri.activate()
|
||||
@ -117,15 +62,10 @@ def convert_to_python(r_output):
|
||||
# Check if it's a pandas-compatible R data frame
|
||||
elif isinstance(r_output, pd.DataFrame):
|
||||
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
|
||||
if isinstance(r_output, np.ndarray) and np.issubdtype(r_output.dtype, np.str_):
|
||||
return r_output.tolist() # Convert to a regular Python list
|
||||
|
||||
# Fall-back
|
||||
# Fallback: return the raw rpy2 object if we don't know how to convert it
|
||||
return r_output
|
||||
|
||||
EOL
|
||||
|
||||
# Directory where the .Rd files are stored (update path as needed)
|
||||
@ -170,24 +110,21 @@ for rd_file in "$rd_dir"/*.Rd; do
|
||||
# Count the number of arguments
|
||||
arg_count = split(func_args, arg_array, ",")
|
||||
|
||||
# Handle "..." arguments (convert them to *args, **kwargs in Python)
|
||||
gsub("\\.\\.\\.", "*args, **kwargs", func_args)
|
||||
# Handle "..." arguments (convert them to *args in Python)
|
||||
gsub("\\.\\.\\.", "*args", func_args)
|
||||
|
||||
# Remove default values from arguments
|
||||
gsub(/ = [^,]+/, "", func_args)
|
||||
|
||||
# If no arguments, skip the function (dont print it)
|
||||
if (arg_count == 0) {
|
||||
func_args = "*args, **kwargs"
|
||||
next
|
||||
}
|
||||
|
||||
# If more than 1 argument, replace the 2nd to nth arguments with *args, **kwargs
|
||||
# If more than 1 argument, replace the 2nd to nth arguments with *args
|
||||
if (arg_count > 1) {
|
||||
first_arg = arg_array[1]
|
||||
func_args = first_arg ", *args, **kwargs"
|
||||
}
|
||||
if (arg_array[1] == "...") {
|
||||
func_args = "*args, **kwargs"
|
||||
func_args = first_arg ", *args"
|
||||
}
|
||||
|
||||
# Skip functions where func_name_py is identical to func_args
|
||||
@ -195,31 +132,23 @@ for rd_file in "$rd_dir"/*.Rd; do
|
||||
next
|
||||
}
|
||||
|
||||
# Skip functions matching the regex pattern
|
||||
if (func_name_py ~ /^(x |facet|scale|set|get|NA_|microorganisms|antibiotics|clinical_breakpoints|example_isolates)/) {
|
||||
# Skip functions matching the regex pattern ^(x |facet|scale|set|get|NA_)
|
||||
if (func_name_py ~ /^(x |facet|scale|set|get|NA_)/) {
|
||||
next
|
||||
}
|
||||
|
||||
# Replace TRUE/FALSE/NULL
|
||||
gsub("TRUE", "True", func_args)
|
||||
gsub("FALSE", "False", func_args)
|
||||
gsub("NULL", "None", func_args)
|
||||
|
||||
# Write the Python function definition to the output file
|
||||
print "def " func_name_py "(" func_args "):" >> "'"$functions_file"'"
|
||||
print " \"\"\"See our website of the R package for the manual: https://msberends.github.io/AMR/index.html\"\"\"" >> "'"$functions_file"'"
|
||||
print " return convert_to_python(amr_r." func_name_py "(" func_args "))" >> "'"$functions_file"'"
|
||||
|
||||
print "from .functions import " func_name_py >> "'"$init_file"'"
|
||||
print "def " func_name_py "(" func_args "):" >> "'"$output_file"'"
|
||||
print " \"\"\"See our website of the R package for the manual: https://msberends.github.io/AMR/index.html\"\"\"" >> "'"$output_file"'"
|
||||
print " return convert_to_python(amr_r." func_name_py "(" func_args "))" >> "'"$output_file"'"
|
||||
}
|
||||
' "$rd_file"
|
||||
done
|
||||
|
||||
# Output completion message
|
||||
echo "Python wrapper functions generated in $functions_file."
|
||||
echo "Python wrapper functions listed in $init_file."
|
||||
echo "Python wrapper functions generated in $output_file."
|
||||
|
||||
cp ../vignettes/AMR_for_Python.Rmd python_wrapper/AMR/README.md
|
||||
cp ../README.md python_wrapper/
|
||||
echo "README copied"
|
||||
|
||||
|
||||
@ -227,25 +156,26 @@ echo "README copied"
|
||||
description_file="../DESCRIPTION"
|
||||
|
||||
# Output setup.py file
|
||||
functions_file="python_wrapper/AMR/setup.py"
|
||||
output_file="python_wrapper/setup.py"
|
||||
|
||||
# Extract the relevant fields from DESCRIPTION
|
||||
version=$(grep "^Version:" "$description_file" | awk '{print $2}')
|
||||
license=$(grep "^License:" "$description_file" | awk '{print $2}')
|
||||
|
||||
# Write the setup.py file
|
||||
cat <<EOL > "$functions_file"
|
||||
cat <<EOL > "$output_file"
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name='AMR',
|
||||
version='$version',
|
||||
#version='$version',
|
||||
version='2.1.1.1',
|
||||
packages=find_packages(),
|
||||
install_requires=[
|
||||
'rpy2',
|
||||
'numpy',
|
||||
'pandas',
|
||||
],
|
||||
author='Dr. Matthijs Berends',
|
||||
author='Matthijs Berends',
|
||||
author_email='m.s.berends@umcg.nl',
|
||||
description='A Python wrapper for the AMR R package',
|
||||
long_description=open('README.md').read(),
|
||||
@ -264,8 +194,8 @@ setup(
|
||||
EOL
|
||||
|
||||
# Output completion message
|
||||
echo "setup.py has been generated in $functions_file."
|
||||
echo "setup.py has been generated in $output_file."
|
||||
|
||||
cd python_wrapper/AMR
|
||||
cd python_wrapper
|
||||
python3 setup.py sdist bdist_wheel
|
||||
|
@ -1028,6 +1028,7 @@ meet_criteria <- function(object, # can be literally `list(...)` for `allow_argu
|
||||
is_positive = NULL,
|
||||
is_positive_or_zero = NULL,
|
||||
is_finite = NULL,
|
||||
contains_column_class = NULL,
|
||||
allow_NULL = FALSE,
|
||||
allow_NA = FALSE,
|
||||
ignore.case = FALSE,
|
||||
@ -1056,11 +1057,6 @@ meet_criteria <- function(object, # can be literally `list(...)` for `allow_argu
|
||||
stop_if(allow_NA == FALSE, "argument `", obj_name, "` must not be NA", call = call_depth)
|
||||
return(invisible())
|
||||
}
|
||||
|
||||
if (identical(class(object), "list") && !"list" %in% allow_class) {
|
||||
# coming from Python, possibly - turn lists (not data.frame) to the underlying data type
|
||||
object <- unlist(object)
|
||||
}
|
||||
|
||||
if (!is.null(allow_class) && !(suppressWarnings(all(is.na(object))) && allow_NA == TRUE)) {
|
||||
stop_ifnot(inherits(object, allow_class), "argument `", obj_name,
|
||||
@ -1147,6 +1143,21 @@ meet_criteria <- function(object, # can be literally `list(...)` for `allow_argu
|
||||
call = call_depth
|
||||
)
|
||||
}
|
||||
if (!is.null(contains_column_class)) {
|
||||
stop_ifnot(
|
||||
any(vapply(
|
||||
FUN.VALUE = logical(1),
|
||||
object,
|
||||
function(col, columns_class = contains_column_class) {
|
||||
inherits(col, columns_class)
|
||||
}
|
||||
), na.rm = TRUE),
|
||||
"the data provided in argument `", obj_name,
|
||||
"` must contain at least one column of class '", contains_column_class[1L], "'. ",
|
||||
"See `?as.", contains_column_class[1L], "`.",
|
||||
call = call_depth
|
||||
)
|
||||
}
|
||||
if (!is.null(allow_arguments_from) && !is.null(names(object))) {
|
||||
args_given <- names(object)
|
||||
if (is.function(allow_arguments_from)) {
|
||||
@ -1168,20 +1179,6 @@ meet_criteria <- function(object, # can be literally `list(...)` for `allow_argu
|
||||
return(invisible())
|
||||
}
|
||||
|
||||
ascertain_sir_classes <- function(x, obj_name) {
|
||||
sirs <- vapply(FUN.VALUE = logical(1), x, is.sir)
|
||||
if (!any(sirs, na.rm = TRUE)) {
|
||||
warning_("the data provided in argument `", obj_name,
|
||||
"` should contain at least one column of class 'sir'. Eligible SIR column were now guessed. ",
|
||||
"See `?as.sir`.")
|
||||
sirs_eligible <- is_sir_eligible(x)
|
||||
for (col in colnames(x)[sirs_eligible]) {
|
||||
x[[col]] <- as.sir(x[[col]])
|
||||
}
|
||||
}
|
||||
x
|
||||
}
|
||||
|
||||
get_current_data <- function(arg_name, call) {
|
||||
valid_df <- function(x) {
|
||||
!is.null(x) && is.data.frame(x)
|
||||
@ -5896,8 +5893,7 @@ antibiogram <- function(x,
|
||||
combine_SI = TRUE,
|
||||
sep = " + ",
|
||||
info = interactive()) {
|
||||
meet_criteria(x, allow_class = "data.frame")
|
||||
x <- ascertain_sir_classes(x, "x")
|
||||
meet_criteria(x, allow_class = "data.frame", contains_column_class = c("sir", "rsi"))
|
||||
meet_criteria(mo_transform, allow_class = "character", has_length = 1, is_in = c("name", "shortname", "gramstain", colnames(AMR::microorganisms)), allow_NULL = TRUE)
|
||||
meet_criteria(ab_transform, allow_class = "character", has_length = 1, is_in = colnames(AMR::antibiotics), allow_NULL = TRUE)
|
||||
meet_criteria(syndromic_group, allow_class = "character", allow_NULL = TRUE, allow_NA = TRUE)
|
||||
@ -7663,8 +7659,7 @@ bug_drug_combinations <- function(x,
|
||||
col_mo = NULL,
|
||||
FUN = mo_shortname,
|
||||
...) {
|
||||
meet_criteria(x, allow_class = "data.frame")
|
||||
x <- ascertain_sir_classes(x, "x")
|
||||
meet_criteria(x, allow_class = "data.frame", contains_column_class = c("sir", "rsi"))
|
||||
meet_criteria(col_mo, allow_class = "character", is_in = colnames(x), has_length = 1, allow_NULL = TRUE)
|
||||
meet_criteria(FUN, allow_class = "function", has_length = 1)
|
||||
|
||||
@ -9278,13 +9273,13 @@ THE NEXT PART CONTAINS CONTENTS FROM FILE ../R/disk.R
|
||||
|
||||
#' Transform Input to Disk Diffusion Diameters
|
||||
#'
|
||||
#' This transforms a vector to a new class [`disk`], which is a disk diffusion growth zone size (around an antibiotic disk) in millimetres between 0 and 50.
|
||||
#' This transforms a vector to a new class [`disk`], which is a disk diffusion growth zone size (around an antibiotic disk) in millimetres between 6 and 50.
|
||||
#' @rdname as.disk
|
||||
#' @param x vector
|
||||
#' @param na.rm a [logical] indicating whether missing values should be removed
|
||||
#' @details Interpret disk values as SIR values with [as.sir()]. It supports guidelines from EUCAST and CLSI.
|
||||
#'
|
||||
#' Disk diffusion growth zone sizes must be between 0 and 50 millimetres. Values higher than 50 but lower than 100 will be maximised to 50. All others input values outside the 0-50 range will return `NA`.
|
||||
#' Disk diffusion growth zone sizes must be between 6 and 50 millimetres. Values higher than 50 but lower than 100 will be maximised to 50. All others input values outside the 6-50 range will return `NA`.
|
||||
#' @return An [integer] with additional class [`disk`]
|
||||
#' @aliases disk
|
||||
#' @export
|
||||
@ -9357,8 +9352,8 @@ as.disk <- function(x, na.rm = FALSE) {
|
||||
# round up and make it an integer
|
||||
x <- as.integer(ceiling(clean_double2(x)))
|
||||
|
||||
# disks can never be less than 0 mm or more than 50 mm
|
||||
x[x < 0 | x > 99] <- NA_integer_
|
||||
# disks can never be less than 6 mm (size of smallest disk) or more than 50 mm
|
||||
x[x < 6 | x > 99] <- NA_integer_
|
||||
x[x > 50] <- 50L
|
||||
na_after <- length(x[is.na(x)])
|
||||
|
||||
@ -12483,8 +12478,7 @@ ggplot_sir <- function(data,
|
||||
y.title = "Proportion",
|
||||
...) {
|
||||
stop_ifnot_installed("ggplot2")
|
||||
meet_criteria(data, allow_class = "data.frame")
|
||||
data <- ascertain_sir_classes(data, "data")
|
||||
meet_criteria(data, allow_class = "data.frame", contains_column_class = c("sir", "rsi"))
|
||||
meet_criteria(position, allow_class = "character", has_length = 1, is_in = c("fill", "stack", "dodge"), allow_NULL = TRUE)
|
||||
meet_criteria(x, allow_class = "character", has_length = 1)
|
||||
meet_criteria(fill, allow_class = "character", has_length = 1)
|
||||
@ -20728,31 +20722,26 @@ sir_confidence_interval <- function(...,
|
||||
),
|
||||
error = function(e) stop_(gsub("in sir_calc(): ", "", e$message, fixed = TRUE), call = -5)
|
||||
)
|
||||
|
||||
if (x == 0) {
|
||||
out <- c(0, 0)
|
||||
} else {
|
||||
# this applies the Clopper-Pearson method
|
||||
out <- stats::binom.test(x = x, n = n, conf.level = confidence_level)$conf.int
|
||||
}
|
||||
|
||||
# this applies the Clopper-Pearson method
|
||||
out <- stats::binom.test(x = x, n = n, conf.level = confidence_level)$conf.int
|
||||
out <- set_clean_class(out, "numeric")
|
||||
|
||||
|
||||
if (side %in% c("left", "l", "lower", "lowest", "less", "min")) {
|
||||
out <- out[1]
|
||||
} else if (side %in% c("right", "r", "higher", "highest", "greater", "g", "max")) {
|
||||
out <- out[2]
|
||||
}
|
||||
if (isTRUE(as_percent)) {
|
||||
out <- trimws(percentage(out, digits = 1))
|
||||
out <- percentage(out, digits = 1)
|
||||
}
|
||||
if (!isFALSE(collapse) && length(out) > 1) {
|
||||
if (is.numeric(out)) {
|
||||
out <- round(out, digits = 3)
|
||||
}
|
||||
# out[is.na(out)] <- 0
|
||||
out <- paste(out, collapse = ifelse(isTRUE(collapse), "-", collapse))
|
||||
}
|
||||
|
||||
|
||||
if (n < minimum) {
|
||||
warning_("Introducing NA: ",
|
||||
ifelse(n == 0, "no", paste("only", n)),
|
||||
@ -20765,6 +20754,7 @@ sir_confidence_interval <- function(...,
|
||||
return(NA_real_)
|
||||
}
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
@ -22251,31 +22241,29 @@ convert_host <- function(x, lang = get_AMR_locale()) {
|
||||
x_out[trimws2(tolower(x)) == "human"] <- "human"
|
||||
x_out[trimws2(tolower(x)) == "ecoff"] <- "ecoff"
|
||||
# this order is based on: clinical_breakpoints |> filter(type == "animal") |> count(host, sort = TRUE)
|
||||
x_out[is.na(x_out) & (x %like% "dog|canine|Canis lupus" | x %like% translate_AMR("dog|dogs|canine", lang))] <- "dogs"
|
||||
x_out[is.na(x_out) & (x %like% "cattle|bovine|Bos taurus" | x %like% translate_AMR("cattle|bovine", lang))] <- "cattle"
|
||||
x_out[is.na(x_out) & (x %like% "swine|suida(e)?|Sus scrofa" | x %like% translate_AMR("swine|swines", lang))] <- "swine"
|
||||
x_out[is.na(x_out) & (x %like% "cat|feline|Felis catus" | x %like% translate_AMR("cat|cats|feline", lang))] <- "cats"
|
||||
x_out[is.na(x_out) & (x %like% "horse|equine|Equus ferus" | x %like% translate_AMR("horse|horses|equine", lang))] <- "horse"
|
||||
x_out[is.na(x_out) & (x %like% "aqua|fish|Pisces" | x %like% translate_AMR("aquatic|fish", lang))] <- "aquatic"
|
||||
x_out[is.na(x_out) & (x %like% "bird|chicken|poultry|avia|Gallus gallus" | x %like% translate_AMR("bird|birds|poultry", lang))] <- "poultry"
|
||||
|
||||
x_out[is.na(x_out) & (x %like% "dog|canine" | x %like% translate_AMR("dog|dogs|canine", lang))] <- "dogs"
|
||||
x_out[is.na(x_out) & (x %like% "cattle|bovine" | x %like% translate_AMR("cattle|bovine", lang))] <- "cattle"
|
||||
x_out[is.na(x_out) & (x %like% "swine|suida(e)?" | x %like% translate_AMR("swine|swines", lang))] <- "swine"
|
||||
x_out[is.na(x_out) & (x %like% "cat|feline" | x %like% translate_AMR("cat|cats|feline", lang))] <- "cats"
|
||||
x_out[is.na(x_out) & (x %like% "horse|equine" | x %like% translate_AMR("horse|horses|equine", lang))] <- "horse"
|
||||
x_out[is.na(x_out) & (x %like% "aqua|fish" | x %like% translate_AMR("aquatic|fish", lang))] <- "aquatic"
|
||||
x_out[is.na(x_out) & (x %like% "bird|chicken|poultry|avia" | x %like% translate_AMR("bird|birds|poultry", lang))] <- "poultry"
|
||||
# additional animals, not necessarily currently in breakpoint guidelines:
|
||||
x_out[is.na(x_out) & (x %like% "camel|camelid|Camelus dromedarius" | x %like% translate_AMR("camel|camels|camelid", lang))] <- "camels"
|
||||
x_out[is.na(x_out) & (x %like% "deer|cervine|Cervidae" | x %like% translate_AMR("deer|deers|cervine", lang))] <- "deer"
|
||||
x_out[is.na(x_out) & (x %like% "donkey|asinine|Equus africanus" | x %like% translate_AMR("donkey|donkeys|asinine", lang))] <- "donkeys"
|
||||
x_out[is.na(x_out) & (x %like% "ferret|musteline|Mustela putorius" | x %like% translate_AMR("ferret|ferrets|musteline", lang))] <- "ferrets"
|
||||
x_out[is.na(x_out) & (x %like% "goat|caprine|Capra aegagrus" | x %like% translate_AMR("goat|goats|caprine", lang))] <- "goats"
|
||||
x_out[is.na(x_out) & (x %like% "guinea pig|caviine|Cavia porcellus" | x %like% translate_AMR("guinea pig|guinea pigs|caviine", lang))] <- "guinea pigs"
|
||||
x_out[is.na(x_out) & (x %like% "hamster|cricetine|Cricetinae" | x %like% translate_AMR("hamster|hamsters|cricetine", lang))] <- "hamsters"
|
||||
x_out[is.na(x_out) & (x %like% "monkey|simian|Simia" | x %like% translate_AMR("monkey|monkeys|simian", lang))] <- "monkeys"
|
||||
x_out[is.na(x_out) & (x %like% "mouse|murine|Mus musculus" | x %like% translate_AMR("mouse|mice|murine", lang))] <- "mice"
|
||||
x_out[is.na(x_out) & (x %like% "pig|porcine|Sus scrofa" | x %like% translate_AMR("pig|pigs|porcine", lang))] <- "pigs"
|
||||
x_out[is.na(x_out) & (x %like% "rabbit|leporine|Oryctolagus cuniculus" | x %like% translate_AMR("rabbit|rabbits|leporine", lang))] <- "rabbits"
|
||||
x_out[is.na(x_out) & (x %like% "rat|ratine|Rattus" | x %like% translate_AMR("rat|rats|ratine", lang))] <- "rats"
|
||||
x_out[is.na(x_out) & (x %like% "sheep|ovine|Ovis aries" | x %like% translate_AMR("sheep|sheeps|ovine", lang))] <- "sheep"
|
||||
x_out[is.na(x_out) & (x %like% "snake|serpentine|Serpentes" | x %like% translate_AMR("snake|snakes|serpentine", lang))] <- "snakes"
|
||||
x_out[is.na(x_out) & (x %like% "turkey|meleagrine|Meleagris gallopavo" | x %like% translate_AMR("turkey|turkeys|meleagrine", lang))] <- "turkey"
|
||||
|
||||
x_out[is.na(x_out) & (x %like% "camel|camelid" | x %like% translate_AMR("camel|camels|camelid", lang))] <- "camels"
|
||||
x_out[is.na(x_out) & (x %like% "deer|cervine" | x %like% translate_AMR("deer|deers|cervine", lang))] <- "deer"
|
||||
x_out[is.na(x_out) & (x %like% "donkey|asinine" | x %like% translate_AMR("donkey|donkeys|asinine", lang))] <- "donkeys"
|
||||
x_out[is.na(x_out) & (x %like% "ferret|musteline" | x %like% translate_AMR("ferret|ferrets|musteline", lang))] <- "ferrets"
|
||||
x_out[is.na(x_out) & (x %like% "goat|caprine" | x %like% translate_AMR("goat|goats|caprine", lang))] <- "goats"
|
||||
x_out[is.na(x_out) & (x %like% "guinea pig|caviine" | x %like% translate_AMR("guinea pig|guinea pigs|caviine", lang))] <- "guinea pigs"
|
||||
x_out[is.na(x_out) & (x %like% "hamster|cricetine" | x %like% translate_AMR("hamster|hamsters|cricetine", lang))] <- "hamsters"
|
||||
x_out[is.na(x_out) & (x %like% "monkey|simian" | x %like% translate_AMR("monkey|monkeys|simian", lang))] <- "monkeys"
|
||||
x_out[is.na(x_out) & (x %like% "mouse|murine" | x %like% translate_AMR("mouse|mice|murine", lang))] <- "mice"
|
||||
x_out[is.na(x_out) & (x %like% "pig|porcine" | x %like% translate_AMR("pig|pigs|porcine", lang))] <- "pigs"
|
||||
x_out[is.na(x_out) & (x %like% "rabbit|leporine" | x %like% translate_AMR("rabbit|rabbits|leporine", lang))] <- "rabbits"
|
||||
x_out[is.na(x_out) & (x %like% "rat|ratine" | x %like% translate_AMR("rat|rats|ratine", lang))] <- "rats"
|
||||
x_out[is.na(x_out) & (x %like% "sheep|ovine" | x %like% translate_AMR("sheep|sheeps|ovine", lang))] <- "sheep"
|
||||
x_out[is.na(x_out) & (x %like% "snake|serpentine" | x %like% translate_AMR("snake|snakes|serpentine", lang))] <- "snakes"
|
||||
x_out[is.na(x_out) & (x %like% "turkey|meleagrine" | x %like% translate_AMR("turkey|turkeys|meleagrine", lang))] <- "turkey"
|
||||
|
||||
x_out[x_out == "ecoff"] <- "ECOFF"
|
||||
x_out
|
||||
@ -22672,7 +22660,7 @@ as_sir_method <- function(method_short,
|
||||
if (breakpoint_type == "animal" && !host_current %in% breakpoints_current$host) {
|
||||
if (guideline_coerced %like% "CLSI") {
|
||||
# VET09 says that staph/strep/enterococcus BP can be extrapolated to all Gr+ cocci except for intrinsic resistance, so take all Gr+ cocci:
|
||||
all_gram_pos_genera <- c("B_STPHY", "B_STRPT", "B_PPTST", "B_AERCC", "B_MCRCCC", "B_TRPRL")
|
||||
all_gram_pos_genera <- c("B_STPHY", "B_STRPT", "B_ENTRC", "B_PPTST", "B_AERCC", "B_MCRCCC", "B_TRPRL")
|
||||
|
||||
# HUMAN SUBSTITUTES
|
||||
if (ab_current == "AZM" && mo_current_genus %in% all_gram_pos_genera && host_current %in% c("dogs", "cats", "horse")) {
|
||||
@ -22719,9 +22707,9 @@ as_sir_method <- function(method_short,
|
||||
# vancomycin can take human breakpoints in these hosts
|
||||
breakpoints_current <- breakpoints_current %pm>% subset(host == "human")
|
||||
notes_current <- c(notes_current, paste0("Using ", font_bold("human"), " breakpoints for ", ab_formatted, " based on CLSI VET09."))
|
||||
|
||||
|
||||
} else if (host_current %in% c("dogs", "cats") && (mo_current_genus %in% c("B_AMYCS", "B_NOCRD", "B_CMPYL", "B_CRYNB", "B_ENTRC", "B_MYCBC", "B_PSDMN", "B_AERMN") | mo_current_class == "B_[CLS]_BTPRTBCT" | mo_current == "B_LISTR_MNCY")) {
|
||||
# dog breakpoints if no canine/feline
|
||||
# human breakpoints if no canine/feline
|
||||
breakpoints_current <- breakpoints_current %pm>% subset(host == "human")
|
||||
notes_current <- c(notes_current, paste0("Using ", font_bold("human"), " breakpoints for ", mo_formatted, " based on CLSI VET09."))
|
||||
|
||||
@ -23361,8 +23349,7 @@ sir_calc_df <- function(type, # "proportion", "count" or "both"
|
||||
combine_SI = TRUE,
|
||||
confidence_level = 0.95) {
|
||||
meet_criteria(type, is_in = c("proportion", "count", "both"), has_length = 1)
|
||||
meet_criteria(data, allow_class = "data.frame")
|
||||
data <- ascertain_sir_classes(data, "data")
|
||||
meet_criteria(data, allow_class = "data.frame", contains_column_class = "sir")
|
||||
meet_criteria(translate_ab, allow_class = c("character", "logical"), has_length = 1, allow_NA = TRUE)
|
||||
language <- validate_language(language)
|
||||
meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_positive_or_zero = TRUE, is_finite = TRUE)
|
||||
@ -24734,183 +24721,166 @@ knitr::opts_chunk$set(
|
||||
|
||||
# Introduction
|
||||
|
||||
The `AMR` package for R is a powerful tool for antimicrobial resistance (AMR) analysis. It provides extensive features for handling microbial and antimicrobial data. However, for those who work primarily in Python, we now have a more intuitive option available: the `AMR` Python package, which uses `rpy2` internally. This package allows Python users to access all the functions from the R `AMR` package without the need to set up `rpy2` themselves. Since this Python package is not a true 'port' (which would require all R functions to be rewritten into Python), R and the AMR R package are still required to be installed. Yet, Python users can now easily work with AMR data directly through Python code.
|
||||
The `AMR` package for R is an incredible tool for antimicrobial resistance (AMR) data analysis, providing extensive functionality for working with microbial and antimicrobial properties. But what if you're working in Python and still want to benefit from the robust features of `AMR`?
|
||||
|
||||
In this document, we explain how this works and provide simple examples of using the `AMR` Python package.
|
||||
The best way is to access R directly from Python with the help of `rpy2`, a simple yet powerful Python package. You can easily call functions from the `AMR` package to process your own data in your own Python environment. This post will guide you through setting up `rpy2` and show you how to use R functions from `AMR` in Python to supercharge your antimicrobial resistance analysis.
|
||||
|
||||
## How It Works
|
||||
<a href="https://chatgpt.com/g/g-M4UNLwFi5-amr-for-r-assistant"><img src="../AMRforRGPT.svg" style="min-width: 300px; width: 10%;" /></a>
|
||||
|
||||
The `AMR` Python package acts as a wrapper around the functions in the `AMR` R package. The package simplifies the process of calling R functions in Python, eliminating the need to manually manage the `rpy2` setup, which Python uses internally to be able to work with the R package. By just using `import AMR`, Python users can directly use the functions from the `AMR` R package as if they were native Python functions.
|
||||
# What is `rpy2`?
|
||||
|
||||
Internally, `rpy2` is still being used, but all complexity is hidden from the user. This approach keeps the Python code clean and Pythonic, while still leveraging the full power of the R `AMR` package.
|
||||
`rpy2` is a Python library that allows Python users to run R code within their Python scripts. Essentially, it acts as a bridge between the two languages, allowing you to tap into the rich ecosystem of R libraries (like `AMR`) while maintaining the flexibility of Python.
|
||||
|
||||
## Example of Usage
|
||||
## Key Features of `rpy2`:
|
||||
- Seamlessly call R functions from Python.
|
||||
- Convert R data structures into Python data structures like pandas DataFrames.
|
||||
- Leverage the full power of R libraries without leaving your Python environment.
|
||||
|
||||
Here’s an example that demonstrates how to clean microorganism and drug names using the `AMR` Python package:
|
||||
# Setting Up `rpy2`
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import AMR
|
||||
Before diving into the examples, you’ll need to install both R and `rpy2`. Here's a step-by-step guide on setting things up.
|
||||
|
||||
# Sample data
|
||||
data = {
|
||||
"MOs": ['E. coli', 'ESCCOL', 'esco', 'Esche coli'],
|
||||
"Drug": ['Cipro', 'CIP', 'J01MA02', 'Ciproxin']
|
||||
}
|
||||
df = pd.DataFrame(data)
|
||||
## Step 1: Install R
|
||||
|
||||
# Use AMR functions to clean microorganism and drug names
|
||||
df['MO_clean'] = AMR.mo_name(df['MOs'])
|
||||
df['Drug_clean'] = AMR.ab_name(df['Drug'])
|
||||
Ensure that R is installed on your system. R has minimal dependencies and is very simple to install:
|
||||
|
||||
# Display the results
|
||||
print(df)
|
||||
```
|
||||
* **Linux**
|
||||
* Ubuntu / Debian:
|
||||
`sudo apt install r-base`
|
||||
* Fedora:
|
||||
`sudo dnf install R`
|
||||
* CentOS/RHEL:
|
||||
`sudo yum install R`
|
||||
* Arch Linux:
|
||||
`sudo pacman -S r`
|
||||
* **macOS** (with Homebrew):
|
||||
`brew install r`
|
||||
* **Other Systems:**
|
||||
Visit the [CRAN download page](https://cran.r-project.org).
|
||||
|
||||
| MOs | Drug | MO_clean | Drug_clean |
|
||||
|-------------|-----------|--------------------|---------------|
|
||||
| E. coli | Cipro | Escherichia coli | Ciprofloxacin |
|
||||
| ESCCOL | CIP | Escherichia coli | Ciprofloxacin |
|
||||
| esco | J01MA02 | Escherichia coli | Ciprofloxacin |
|
||||
| Esche coli | Ciproxin | Escherichia coli | Ciprofloxacin |
|
||||
## Step 2: Install the `AMR` package in R
|
||||
|
||||
### Explanation
|
||||
|
||||
* **mo_name:** This function standardises microorganism names. Here, different variations of *Escherichia coli* (such as "E. coli", "ESCCOL", "esco", and "Esche coli") are all converted into the correct, standardised form, "Escherichia coli".
|
||||
|
||||
* **ab_name**: Similarly, this function standardises antimicrobial names. The different representations of ciprofloxacin (e.g., "Cipro", "CIP", "J01MA02", and "Ciproxin") are all converted to the standard name, "Ciprofloxacin".
|
||||
|
||||
### Taxonomic Data Sets Now in Python!
|
||||
|
||||
As a Python user, you might like that the most important data sets of the `AMR` R package, `microorganisms`, `antibiotics`, `clinical_breakpoints`, and `example_isolates`, are now available as regular Python data frames:
|
||||
|
||||
```python
|
||||
AMR.microorganisms
|
||||
```
|
||||
|
||||
| mo | fullname | status | kingdom | gbif | gbif_parent | gbif_renamed_to | prevalence |
|
||||
|--------------|------------------------------------|----------|----------|-----------|-------------|-----------------|------------|
|
||||
| B_GRAMN | (unknown Gram-negatives) | unknown | Bacteria | None | None | None | 2.0 |
|
||||
| B_GRAMP | (unknown Gram-positives) | unknown | Bacteria | None | None | None | 2.0 |
|
||||
| B_ANAER-NEG | (unknown anaerobic Gram-negatives) | unknown | Bacteria | None | None | None | 2.0 |
|
||||
| B_ANAER-POS | (unknown anaerobic Gram-positives) | unknown | Bacteria | None | None | None | 2.0 |
|
||||
| B_ANAER | (unknown anaerobic bacteria) | unknown | Bacteria | None | None | None | 2.0 |
|
||||
| ... | ... | ... | ... | ... | ... | ... | ... |
|
||||
| B_ZYMMN_POMC | Zymomonas pomaceae | accepted | Bacteria | 10744418 | 3221412 | None | 2.0 |
|
||||
| B_ZYMPH | Zymophilus | synonym | Bacteria | None | 9475166 | None | 2.0 |
|
||||
| B_ZYMPH_PCVR | Zymophilus paucivorans | synonym | Bacteria | None | None | None | 2.0 |
|
||||
| B_ZYMPH_RFFN | Zymophilus raffinosivorans | synonym | Bacteria | None | None | None | 2.0 |
|
||||
| F_ZYZYG | Zyzygomyces | unknown | Fungi | None | 7581 | None | 2.0 |
|
||||
|
||||
```python
|
||||
AMR.antibiotics
|
||||
```
|
||||
|
||||
| ab | cid | name | group | oral_ddd | oral_units | iv_ddd | iv_units |
|
||||
|-----|-------------|----------------------|----------------------------|----------|------------|--------|----------|
|
||||
| AMA | 4649.0 | 4-aminosalicylic acid| Antimycobacterials | 12.00 | g | NaN | None |
|
||||
| ACM | 6450012.0 | Acetylmidecamycin | Macrolides/lincosamides | NaN | None | NaN | None |
|
||||
| ASP | 49787020.0 | Acetylspiramycin | Macrolides/lincosamides | NaN | None | NaN | None |
|
||||
| ALS | 8954.0 | Aldesulfone sodium | Other antibacterials | 0.33 | g | NaN | None |
|
||||
| AMK | 37768.0 | Amikacin | Aminoglycosides | NaN | None | 1.0 | g |
|
||||
| ... | ... | ... | ... | ... | ... | ... | ... |
|
||||
| VIR | 11979535.0 | Virginiamycine | Other antibacterials | NaN | None | NaN | None |
|
||||
| VOR | 71616.0 | Voriconazole | Antifungals/antimycotics | 0.40 | g | 0.4 | g |
|
||||
| XBR | 72144.0 | Xibornol | Other antibacterials | NaN | None | NaN | None |
|
||||
| ZID | 77846445.0 | Zidebactam | Other antibacterials | NaN | None | NaN | None |
|
||||
| ZFD | NaN | Zoliflodacin | None | NaN | None | NaN | None |
|
||||
|
||||
|
||||
# Installation
|
||||
|
||||
To be able to use the `AMR` Python package, it is required to install both R and the `AMR` R package.
|
||||
|
||||
### Preparation: Install R and `AMR` R package
|
||||
|
||||
For Linux and macOS, this is just:
|
||||
On Linux and macOS, open Terminal and run:
|
||||
|
||||
```bash
|
||||
# Ubuntu / Debian
|
||||
sudo apt install r-base && Rscript -e 'install.packages("AMR")'
|
||||
# Fedora:
|
||||
sudo dnf install R && Rscript -e 'install.packages("AMR")'
|
||||
# CentOS/RHEL
|
||||
sudo yum install R && Rscript -e 'install.packages("AMR")'
|
||||
# Arch Linux
|
||||
sudo pacman -S r && Rscript -e 'install.packages("AMR")'
|
||||
# macOS
|
||||
brew install r && Rscript -e 'install.packages("AMR")'
|
||||
Rscript -e 'install.packages("AMR")'
|
||||
```
|
||||
|
||||
For Windows, visit the [CRAN download page](https://cran.r-project.org) in install R, then afterwards install the 'AMR' package manually.
|
||||
For other systems, open your R console and install the `AMR` package by running:
|
||||
|
||||
### Install `AMR` Python Package
|
||||
```r
|
||||
install.packages("AMR")
|
||||
```
|
||||
|
||||
Since the Python package is available on the official [Python Package Index](https://pypi.org/project/AMR/), you can just run:
|
||||
On any system, you can also install the latest development version of the `AMR` package by setting `repos` to our beta channel:
|
||||
|
||||
```r
|
||||
install.packages("AMR", repos = "https://msberends.r-universe.dev")
|
||||
```
|
||||
|
||||
## Step 3: Install `rpy2` in Python
|
||||
|
||||
To install `rpy2`, simply run the following command in your terminal:
|
||||
|
||||
```bash
|
||||
pip install AMR
|
||||
pip install rpy2
|
||||
```
|
||||
|
||||
## Step 4: Test `rpy2` Installation
|
||||
|
||||
To ensure everything is set up correctly, you can test your installation by running the following Python script, which essentially runs R in the background:
|
||||
|
||||
```python
|
||||
import rpy2.robjects as ro
|
||||
|
||||
# Test a simple R function from Python
|
||||
ro.r('1 + 1')
|
||||
```
|
||||
|
||||
If this returns `2`, you're good to go!
|
||||
|
||||
# Working with `AMR` in Python
|
||||
|
||||
Now that we have everything set up, let’s walk through some practical examples of using the `AMR` package within Python.
|
||||
Now that we have `rpy2` set up, let’s walk through some practical examples of using the `AMR` package within Python.
|
||||
|
||||
## Example 1: Calculating AMR
|
||||
## Example 1: Converting Taxonomic Data
|
||||
|
||||
Let’s start by converting taxonomic user input to valid taxonomy using the `AMR` package, from within Python:
|
||||
|
||||
```python
|
||||
import AMR
|
||||
import pandas as pd
|
||||
import rpy2.robjects as ro
|
||||
from rpy2.robjects.packages import importr
|
||||
from rpy2.robjects import pandas2ri
|
||||
|
||||
df = AMR.example_isolates
|
||||
result = AMR.resistance(df["AMX"])
|
||||
# Load the AMR package from R
|
||||
amr = importr('AMR')
|
||||
|
||||
# Example user dataset in Python
|
||||
data = pd.DataFrame({
|
||||
'microorganism': ['E. coli', 'S. aureus', 'P. aeruginosa', 'K. pneumoniae']
|
||||
})
|
||||
|
||||
# Apply mo_name() from the AMR package to the 'microorganism' column
|
||||
ro.globalenv['r_data'] = data
|
||||
ro.r('r_data$mo_name <- mo_name(r_data$microorganism)')
|
||||
|
||||
# Retrieve and print the modified R DataFrame in Python
|
||||
result = ro.r('r_data')
|
||||
result = pandas2ri.rpy2py(result)
|
||||
print(result)
|
||||
```
|
||||
|
||||
```
|
||||
[0.59555556]
|
||||
```
|
||||
In this example, a Python dataset with microorganism names like *E. coli* and *S. aureus* is passed to the R function `mo_name()`. The result is an updated `DataFrame` that includes the standardised microorganism names based on the `mo_name()` function from the `AMR` package.
|
||||
|
||||
## Example 2: Generating Antibiograms
|
||||
## Example 2: Generating an Antibiogram
|
||||
|
||||
One of the core functions of the `AMR` package is generating an antibiogram, a table that summarises the antimicrobial susceptibility of bacterial isolates. Here’s how you can generate an antibiogram from Python:
|
||||
|
||||
```python
|
||||
result2a = AMR.antibiogram(df[["mo", "AMX", "CIP", "TZP"]])
|
||||
print(result2a)
|
||||
# Run an antibiogram in R from Python
|
||||
ro.r('result <- antibiogram(example_isolates, antibiotics = c(aminoglycosides(), carbapenems()))')
|
||||
|
||||
# Retrieve the result in Python
|
||||
result = ro.r('as.data.frame(result)')
|
||||
print(result)
|
||||
```
|
||||
|
||||
| Pathogen | Amoxicillin | Ciprofloxacin | Piperacillin/tazobactam |
|
||||
|-----------------|-----------------|-----------------|--------------------------|
|
||||
| CoNS | 7% (10/142) | 73% (183/252) | 30% (10/33) |
|
||||
| E. coli | 50% (196/392) | 88% (399/456) | 94% (393/416) |
|
||||
| K. pneumoniae | 0% (0/58) | 96% (53/55) | 89% (47/53) |
|
||||
| P. aeruginosa | 0% (0/30) | 100% (30/30) | None |
|
||||
| P. mirabilis | None | 94% (34/36) | None |
|
||||
| S. aureus | 6% (8/131) | 90% (171/191) | None |
|
||||
| S. epidermidis | 1% (1/91) | 64% (87/136) | None |
|
||||
| S. hominis | None | 80% (56/70) | None |
|
||||
| S. pneumoniae | 100% (112/112) | None | 100% (112/112) |
|
||||
In this example, we generate an antibiogram by selecting aminoglycosides and carbapenems, two classes of antibiotics, and then convert the resulting R data frame into a Python-readable format.
|
||||
|
||||
## Example 3: Filtering Data Based on Gram-Negative Bacteria
|
||||
|
||||
Let’s say you want to filter the dataset for Gram-negative bacteria and display their resistance to certain antibiotics:
|
||||
|
||||
```python
|
||||
result2b = AMR.antibiogram(df[["mo", "AMX", "CIP", "TZP"]], mo_transform = "gramstain")
|
||||
print(result2b)
|
||||
# Filter for Gram-negative bacteria with intrinsic resistance to cefotaxime
|
||||
ro.r('result <- example_isolates[which(mo_is_gram_negative() & mo_is_intrinsic_resistant(ab = "cefotax")), c("bacteria", aminoglycosides(), carbapenems())]')
|
||||
|
||||
# Retrieve the filtered result in Python
|
||||
result = ro.r('as.data.frame(result)')
|
||||
print(result)
|
||||
```
|
||||
|
||||
| Pathogen | Amoxicillin | Ciprofloxacin | Piperacillin/tazobactam |
|
||||
|----------------|-----------------|------------------|--------------------------|
|
||||
| Gram-negative | 36% (226/631) | 91% (621/684) | 88% (565/641) |
|
||||
| Gram-positive | 43% (305/703) | 77% (560/724) | 86% (296/345) |
|
||||
This example uses the AMR functions `mo_is_gram_negative()` and `mo_is_intrinsic_resistant()` to filter the dataset and returns a subset of bacteria with resistance data.
|
||||
|
||||
## Example 4: Customising the Antibiogram
|
||||
|
||||
In this example, we generate an antibiogram by selecting various antibiotics.
|
||||
You can easily customise the antibiogram by passing different antibiotics or microorganism transformations, as shown below:
|
||||
|
||||
```python
|
||||
# Customise the antibiogram with different settings
|
||||
ro.r('result <- antibiogram(example_isolates, antibiotics = c("TZP", "TZP+TOB", "TZP+GEN"), mo_transform = "gramstain")')
|
||||
|
||||
# Retrieve and print the result
|
||||
result = ro.r('as.data.frame(result)')
|
||||
print(result)
|
||||
```
|
||||
|
||||
Here, we use piperacillin/tazobactam (TZP) in combination with tobramycin (TOB) and gentamicin (GEN) to see how they perform against various Gram-negative bacteria.
|
||||
|
||||
# Conclusion
|
||||
|
||||
With the `AMR` Python package, Python users can now effortlessly call R functions from the `AMR` R package. This eliminates the need for complex `rpy2` configurations and provides a clean, easy-to-use interface for antimicrobial resistance analysis. The examples provided above demonstrate how this can be applied to typical workflows, such as standardising microorganism and antimicrobial names or calculating resistance.
|
||||
|
||||
By using `import AMR`, you can seamlessly integrate the robust features of the R `AMR` package into your Python workflows. Whether you're cleaning data or analysing resistance patterns, the `AMR` Python package makes it easy to work with AMR data in Python.
|
||||
Using `rpy2`, you can easily integrate the power of R's `AMR` package into your Python workflows. Whether you are generating antibiograms, analyzing resistance data, or performing complex filtering, `rpy2` gives you the flexibility to run R code without leaving the Python environment. This makes it a perfect solution for teams working across both R and Python.
|
||||
|
||||
|
||||
|
||||
@ -25773,6 +25743,38 @@ microorganisms.codes %>%
|
||||
|
||||
|
||||
|
||||
THE NEXT PART CONTAINS CONTENTS FROM FILE ../vignettes/other_pkg.Rmd
|
||||
|
||||
|
||||
|
||||
---
|
||||
title: "Using AMR with other packages: AMR & dplyr/tidyverse"
|
||||
output:
|
||||
rmarkdown::html_vignette:
|
||||
toc: true
|
||||
toc_depth: 3
|
||||
vignette: >
|
||||
%\VignetteIndexEntry{How to conduct AMR data analysis}
|
||||
%\VignetteEncoding{UTF-8}
|
||||
%\VignetteEngine{knitr::rmarkdown}
|
||||
editor_options:
|
||||
chunk_output_type: console
|
||||
---
|
||||
|
||||
```{r setup, include = FALSE, results = 'markup'}
|
||||
knitr::opts_chunk$set(
|
||||
warning = FALSE,
|
||||
collapse = TRUE,
|
||||
comment = "#>",
|
||||
fig.width = 7.5,
|
||||
fig.height = 5
|
||||
)
|
||||
```
|
||||
|
||||
This page will be updated shortly, to give explicit examples of how to work ideally with the `AMR` package, for those who are used to working in `dplyr` or other tidyverse packages.
|
||||
|
||||
|
||||
|
||||
THE NEXT PART CONTAINS CONTENTS FROM FILE ../vignettes/resistance_predict.Rmd
|
||||
|
||||
|
||||
@ -25989,8 +25991,8 @@ THE NEXT PART CONTAINS CONTENTS FROM FILE ../DESCRIPTION
|
||||
|
||||
|
||||
Package: AMR
|
||||
Version: 2.1.1.9094
|
||||
Date: 2024-10-10
|
||||
Version: 2.1.1.9087
|
||||
Date: 2024-10-02
|
||||
Title: Antimicrobial Resistance Data Analysis
|
||||
Description: Functions to simplify and standardise antimicrobial resistance (AMR)
|
||||
data analysis and to work with microbial and antimicrobial properties by
|
||||
@ -26429,8 +26431,6 @@ THE NEXT PART CONTAINS CONTENTS FROM FILE ../index.md
|
||||
* Integrates with **WHONET**, ATC, **EARS-Net**, PubChem, **LOINC**, **SNOMED CT**, and **NCBI**
|
||||
* 100% free of costs and dependencies, highly suitable for places with **limited resources**
|
||||
|
||||
> Now available for Python too! [Click here](./articles/AMR_for_Python.html) to read more.
|
||||
|
||||
<div style="display: flex; font-size: 0.8em;">
|
||||
<p style="text-align:left; width: 50%;"><small><a href="https://msberends.github.io/AMR/">https://msberends.github.io/AMR</a></small></p>
|
||||
<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></p>
|
||||
|
2
index.md
2
index.md
@ -9,8 +9,6 @@
|
||||
* Integrates with **WHONET**, ATC, **EARS-Net**, PubChem, **LOINC**, **SNOMED CT**, and **NCBI**
|
||||
* 100% free of costs and dependencies, highly suitable for places with **limited resources**
|
||||
|
||||
> Now available for Python too! [Click here](./articles/AMR_for_Python.html) to read more.
|
||||
|
||||
<div style="display: flex; font-size: 0.8em;">
|
||||
<p style="text-align:left; width: 50%;"><small><a href="https://msberends.github.io/AMR/">https://msberends.github.io/AMR</a></small></p>
|
||||
<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></p>
|
||||
|
@ -26,12 +26,12 @@ is.disk(x)
|
||||
An \link{integer} with additional class \code{\link{disk}}
|
||||
}
|
||||
\description{
|
||||
This transforms a vector to a new class \code{\link{disk}}, which is a disk diffusion growth zone size (around an antibiotic disk) in millimetres between 0 and 50.
|
||||
This transforms a vector to a new class \code{\link{disk}}, which is a disk diffusion growth zone size (around an antibiotic disk) in millimetres between 6 and 50.
|
||||
}
|
||||
\details{
|
||||
Interpret disk values as SIR values with \code{\link[=as.sir]{as.sir()}}. It supports guidelines from EUCAST and CLSI.
|
||||
|
||||
Disk diffusion growth zone sizes must be between 0 and 50 millimetres. Values higher than 50 but lower than 100 will be maximised to 50. All others input values outside the 0-50 range will return \code{NA}.
|
||||
Disk diffusion growth zone sizes must be between 6 and 50 millimetres. Values higher than 50 but lower than 100 will be maximised to 50. All others input values outside the 6-50 range will return \code{NA}.
|
||||
|
||||
\code{NA_disk_} is a missing value of the new \code{disk} class.
|
||||
}
|
||||
|
@ -24,180 +24,161 @@ knitr::opts_chunk$set(
|
||||
|
||||
# Introduction
|
||||
|
||||
The `AMR` package for R is a powerful tool for antimicrobial resistance (AMR) analysis. It provides extensive features for handling microbial and antimicrobial data. However, for those who work primarily in Python, we now have a more intuitive option available: the `AMR` Python package, which uses `rpy2` internally. This package allows Python users to access all the functions from the R `AMR` package without the need to set up `rpy2` themselves. Since this Python package is not a true 'port' (which would require all R functions to be rewritten into Python), R and the AMR R package are still required to be installed. Yet, Python users can now easily work with AMR data directly through Python code.
|
||||
The `AMR` package for R is an incredible tool for antimicrobial resistance (AMR) data analysis, providing extensive functionality for working with microbial and antimicrobial properties. But what if you're working in Python and still want to benefit from the robust features of `AMR`?
|
||||
|
||||
In this document, we explain how this works and provide simple examples of using the `AMR` Python package.
|
||||
The best way is to access R directly from Python with the help of `rpy2`, a simple yet powerful Python package. You can easily call functions from the `AMR` package to process your own data in your own Python environment. This post will guide you through setting up `rpy2` and show you how to use R functions from `AMR` in Python to supercharge your antimicrobial resistance analysis.
|
||||
|
||||
## How It Works
|
||||
# What is `rpy2`?
|
||||
|
||||
The `AMR` Python package acts as a wrapper around the functions in the `AMR` R package. The package simplifies the process of calling R functions in Python, eliminating the need to manually manage the `rpy2` setup, which Python uses internally to be able to work with the R package. By just using `import AMR`, Python users can directly use the functions from the `AMR` R package as if they were native Python functions.
|
||||
`rpy2` is a Python library that allows Python users to run R code within their Python scripts. Essentially, it acts as a bridge between the two languages, allowing you to tap into the rich ecosystem of R libraries (like `AMR`) while maintaining the flexibility of Python.
|
||||
|
||||
Internally, `rpy2` is still being used, but all complexity is hidden from the user. This approach keeps the Python code clean and Pythonic, while still leveraging the full power of the R `AMR` package.
|
||||
## Key Features of `rpy2`:
|
||||
- Seamlessly call R functions from Python.
|
||||
- Convert R data structures into Python data structures like pandas DataFrames.
|
||||
- Leverage the full power of R libraries without leaving your Python environment.
|
||||
|
||||
## Example of Usage
|
||||
# Setting Up `rpy2`
|
||||
|
||||
Here’s an example that demonstrates how to clean microorganism and drug names using the `AMR` Python package:
|
||||
Before diving into the examples, you’ll need to install both R and `rpy2`. Here's a step-by-step guide on setting things up.
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import AMR
|
||||
## Step 1: Install R
|
||||
|
||||
# Sample data
|
||||
data = {
|
||||
"MOs": ['E. coli', 'ESCCOL', 'esco', 'Esche coli'],
|
||||
"Drug": ['Cipro', 'CIP', 'J01MA02', 'Ciproxin']
|
||||
}
|
||||
df = pd.DataFrame(data)
|
||||
Ensure that R is installed on your system. R has minimal dependencies and is very simple to install:
|
||||
|
||||
# Use AMR functions to clean microorganism and drug names
|
||||
df['MO_clean'] = AMR.mo_name(df['MOs'])
|
||||
df['Drug_clean'] = AMR.ab_name(df['Drug'])
|
||||
* **Linux**
|
||||
* Ubuntu / Debian:
|
||||
`sudo apt install r-base`
|
||||
* Fedora:
|
||||
`sudo dnf install R`
|
||||
* CentOS/RHEL:
|
||||
`sudo yum install R`
|
||||
* Arch Linux:
|
||||
`sudo pacman -S r`
|
||||
* **macOS** (with Homebrew):
|
||||
`brew install r`
|
||||
* **Other Systems:**
|
||||
Visit the [CRAN download page](https://cran.r-project.org).
|
||||
|
||||
# Display the results
|
||||
print(df)
|
||||
```
|
||||
## Step 2: Install the `AMR` package in R
|
||||
|
||||
| MOs | Drug | MO_clean | Drug_clean |
|
||||
|-------------|-----------|--------------------|---------------|
|
||||
| E. coli | Cipro | Escherichia coli | Ciprofloxacin |
|
||||
| ESCCOL | CIP | Escherichia coli | Ciprofloxacin |
|
||||
| esco | J01MA02 | Escherichia coli | Ciprofloxacin |
|
||||
| Esche coli | Ciproxin | Escherichia coli | Ciprofloxacin |
|
||||
|
||||
### Explanation
|
||||
|
||||
* **mo_name:** This function standardises microorganism names. Here, different variations of *Escherichia coli* (such as "E. coli", "ESCCOL", "esco", and "Esche coli") are all converted into the correct, standardised form, "Escherichia coli".
|
||||
|
||||
* **ab_name**: Similarly, this function standardises antimicrobial names. The different representations of ciprofloxacin (e.g., "Cipro", "CIP", "J01MA02", and "Ciproxin") are all converted to the standard name, "Ciprofloxacin".
|
||||
|
||||
### Taxonomic Data Sets Now in Python!
|
||||
|
||||
As a Python user, you might like that the most important data sets of the `AMR` R package, `microorganisms`, `antibiotics`, `clinical_breakpoints`, and `example_isolates`, are now available as regular Python data frames:
|
||||
|
||||
```python
|
||||
AMR.microorganisms
|
||||
```
|
||||
|
||||
| mo | fullname | status | kingdom | gbif | gbif_parent | gbif_renamed_to | prevalence |
|
||||
|--------------|------------------------------------|----------|----------|-----------|-------------|-----------------|------------|
|
||||
| B_GRAMN | (unknown Gram-negatives) | unknown | Bacteria | None | None | None | 2.0 |
|
||||
| B_GRAMP | (unknown Gram-positives) | unknown | Bacteria | None | None | None | 2.0 |
|
||||
| B_ANAER-NEG | (unknown anaerobic Gram-negatives) | unknown | Bacteria | None | None | None | 2.0 |
|
||||
| B_ANAER-POS | (unknown anaerobic Gram-positives) | unknown | Bacteria | None | None | None | 2.0 |
|
||||
| B_ANAER | (unknown anaerobic bacteria) | unknown | Bacteria | None | None | None | 2.0 |
|
||||
| ... | ... | ... | ... | ... | ... | ... | ... |
|
||||
| B_ZYMMN_POMC | Zymomonas pomaceae | accepted | Bacteria | 10744418 | 3221412 | None | 2.0 |
|
||||
| B_ZYMPH | Zymophilus | synonym | Bacteria | None | 9475166 | None | 2.0 |
|
||||
| B_ZYMPH_PCVR | Zymophilus paucivorans | synonym | Bacteria | None | None | None | 2.0 |
|
||||
| B_ZYMPH_RFFN | Zymophilus raffinosivorans | synonym | Bacteria | None | None | None | 2.0 |
|
||||
| F_ZYZYG | Zyzygomyces | unknown | Fungi | None | 7581 | None | 2.0 |
|
||||
|
||||
```python
|
||||
AMR.antibiotics
|
||||
```
|
||||
|
||||
| ab | cid | name | group | oral_ddd | oral_units | iv_ddd | iv_units |
|
||||
|-----|-------------|----------------------|----------------------------|----------|------------|--------|----------|
|
||||
| AMA | 4649.0 | 4-aminosalicylic acid| Antimycobacterials | 12.00 | g | NaN | None |
|
||||
| ACM | 6450012.0 | Acetylmidecamycin | Macrolides/lincosamides | NaN | None | NaN | None |
|
||||
| ASP | 49787020.0 | Acetylspiramycin | Macrolides/lincosamides | NaN | None | NaN | None |
|
||||
| ALS | 8954.0 | Aldesulfone sodium | Other antibacterials | 0.33 | g | NaN | None |
|
||||
| AMK | 37768.0 | Amikacin | Aminoglycosides | NaN | None | 1.0 | g |
|
||||
| ... | ... | ... | ... | ... | ... | ... | ... |
|
||||
| VIR | 11979535.0 | Virginiamycine | Other antibacterials | NaN | None | NaN | None |
|
||||
| VOR | 71616.0 | Voriconazole | Antifungals/antimycotics | 0.40 | g | 0.4 | g |
|
||||
| XBR | 72144.0 | Xibornol | Other antibacterials | NaN | None | NaN | None |
|
||||
| ZID | 77846445.0 | Zidebactam | Other antibacterials | NaN | None | NaN | None |
|
||||
| ZFD | NaN | Zoliflodacin | None | NaN | None | NaN | None |
|
||||
|
||||
|
||||
# Installation
|
||||
|
||||
To be able to use the `AMR` Python package, it is required to install both R and the `AMR` R package.
|
||||
|
||||
### Preparation: Install R and `AMR` R package
|
||||
|
||||
For Linux and macOS, this is just:
|
||||
On Linux and macOS, open Terminal and run:
|
||||
|
||||
```bash
|
||||
# Ubuntu / Debian
|
||||
sudo apt install r-base && Rscript -e 'install.packages("AMR")'
|
||||
# Fedora:
|
||||
sudo dnf install R && Rscript -e 'install.packages("AMR")'
|
||||
# CentOS/RHEL
|
||||
sudo yum install R && Rscript -e 'install.packages("AMR")'
|
||||
# Arch Linux
|
||||
sudo pacman -S r && Rscript -e 'install.packages("AMR")'
|
||||
# macOS
|
||||
brew install r && Rscript -e 'install.packages("AMR")'
|
||||
Rscript -e 'install.packages("AMR")'
|
||||
```
|
||||
|
||||
For Windows, visit the [CRAN download page](https://cran.r-project.org) in install R, then afterwards install the 'AMR' package manually.
|
||||
For other systems, open your R console and install the `AMR` package by running:
|
||||
|
||||
### Install `AMR` Python Package
|
||||
```r
|
||||
install.packages("AMR")
|
||||
```
|
||||
|
||||
Since the Python package is available on the official [Python Package Index](https://pypi.org/project/AMR/), you can just run:
|
||||
On any system, you can also install the latest development version of the `AMR` package by setting `repos` to our beta channel:
|
||||
|
||||
```r
|
||||
install.packages("AMR", repos = "https://msberends.r-universe.dev")
|
||||
```
|
||||
|
||||
## Step 3: Install `rpy2` in Python
|
||||
|
||||
To install `rpy2`, simply run the following command in your terminal:
|
||||
|
||||
```bash
|
||||
pip install AMR
|
||||
pip install rpy2
|
||||
```
|
||||
|
||||
## Step 4: Test `rpy2` Installation
|
||||
|
||||
To ensure everything is set up correctly, you can test your installation by running the following Python script, which essentially runs R in the background:
|
||||
|
||||
```python
|
||||
import rpy2.robjects as ro
|
||||
|
||||
# Test a simple R function from Python
|
||||
ro.r('1 + 1')
|
||||
```
|
||||
|
||||
If this returns `2`, you're good to go!
|
||||
|
||||
# Working with `AMR` in Python
|
||||
|
||||
Now that we have everything set up, let’s walk through some practical examples of using the `AMR` package within Python.
|
||||
Now that we have `rpy2` set up, let’s walk through some practical examples of using the `AMR` package within Python.
|
||||
|
||||
## Example 1: Calculating AMR
|
||||
## Example 1: Converting Taxonomic Data
|
||||
|
||||
Let’s start by converting taxonomic user input to valid taxonomy using the `AMR` package, from within Python:
|
||||
|
||||
```python
|
||||
import AMR
|
||||
import pandas as pd
|
||||
import rpy2.robjects as ro
|
||||
from rpy2.robjects.packages import importr
|
||||
from rpy2.robjects import pandas2ri
|
||||
|
||||
df = AMR.example_isolates
|
||||
result = AMR.resistance(df["AMX"])
|
||||
# Load the AMR package from R
|
||||
amr = importr('AMR')
|
||||
|
||||
# Example user dataset in Python
|
||||
data = pd.DataFrame({
|
||||
'microorganism': ['E. coli', 'S. aureus', 'P. aeruginosa', 'K. pneumoniae']
|
||||
})
|
||||
|
||||
# Apply mo_name() from the AMR package to the 'microorganism' column
|
||||
ro.globalenv['r_data'] = data
|
||||
ro.r('r_data$mo_name <- mo_name(r_data$microorganism)')
|
||||
|
||||
# Retrieve and print the modified R DataFrame in Python
|
||||
result = ro.r('r_data')
|
||||
result = pandas2ri.rpy2py(result)
|
||||
print(result)
|
||||
```
|
||||
|
||||
```
|
||||
[0.59555556]
|
||||
```
|
||||
In this example, a Python dataset with microorganism names like *E. coli* and *S. aureus* is passed to the R function `mo_name()`. The result is an updated `DataFrame` that includes the standardised microorganism names based on the `mo_name()` function from the `AMR` package.
|
||||
|
||||
## Example 2: Generating Antibiograms
|
||||
## Example 2: Generating an Antibiogram
|
||||
|
||||
One of the core functions of the `AMR` package is generating an antibiogram, a table that summarises the antimicrobial susceptibility of bacterial isolates. Here’s how you can generate an antibiogram from Python:
|
||||
|
||||
```python
|
||||
result2a = AMR.antibiogram(df[["mo", "AMX", "CIP", "TZP"]])
|
||||
print(result2a)
|
||||
# Run an antibiogram in R from Python
|
||||
ro.r('result <- antibiogram(example_isolates, antibiotics = c(aminoglycosides(), carbapenems()))')
|
||||
|
||||
# Retrieve the result in Python
|
||||
result = ro.r('as.data.frame(result)')
|
||||
print(result)
|
||||
```
|
||||
|
||||
| Pathogen | Amoxicillin | Ciprofloxacin | Piperacillin/tazobactam |
|
||||
|-----------------|-----------------|-----------------|--------------------------|
|
||||
| CoNS | 7% (10/142) | 73% (183/252) | 30% (10/33) |
|
||||
| E. coli | 50% (196/392) | 88% (399/456) | 94% (393/416) |
|
||||
| K. pneumoniae | 0% (0/58) | 96% (53/55) | 89% (47/53) |
|
||||
| P. aeruginosa | 0% (0/30) | 100% (30/30) | None |
|
||||
| P. mirabilis | None | 94% (34/36) | None |
|
||||
| S. aureus | 6% (8/131) | 90% (171/191) | None |
|
||||
| S. epidermidis | 1% (1/91) | 64% (87/136) | None |
|
||||
| S. hominis | None | 80% (56/70) | None |
|
||||
| S. pneumoniae | 100% (112/112) | None | 100% (112/112) |
|
||||
In this example, we generate an antibiogram by selecting aminoglycosides and carbapenems, two classes of antibiotics, and then convert the resulting R data frame into a Python-readable format.
|
||||
|
||||
## Example 3: Filtering Data Based on Gram-Negative Bacteria
|
||||
|
||||
Let’s say you want to filter the dataset for Gram-negative bacteria and display their resistance to certain antibiotics:
|
||||
|
||||
```python
|
||||
result2b = AMR.antibiogram(df[["mo", "AMX", "CIP", "TZP"]], mo_transform = "gramstain")
|
||||
print(result2b)
|
||||
# Filter for Gram-negative bacteria with intrinsic resistance to cefotaxime
|
||||
ro.r('result <- example_isolates[which(mo_is_gram_negative() & mo_is_intrinsic_resistant(ab = "cefotax")), c("bacteria", aminoglycosides(), carbapenems())]')
|
||||
|
||||
# Retrieve the filtered result in Python
|
||||
result = ro.r('as.data.frame(result)')
|
||||
print(result)
|
||||
```
|
||||
|
||||
| Pathogen | Amoxicillin | Ciprofloxacin | Piperacillin/tazobactam |
|
||||
|----------------|-----------------|------------------|--------------------------|
|
||||
| Gram-negative | 36% (226/631) | 91% (621/684) | 88% (565/641) |
|
||||
| Gram-positive | 43% (305/703) | 77% (560/724) | 86% (296/345) |
|
||||
This example uses the AMR functions `mo_is_gram_negative()` and `mo_is_intrinsic_resistant()` to filter the dataset and returns a subset of bacteria with resistance data.
|
||||
|
||||
## Example 4: Customising the Antibiogram
|
||||
|
||||
In this example, we generate an antibiogram by selecting various antibiotics.
|
||||
You can easily customise the antibiogram by passing different antibiotics or microorganism transformations, as shown below:
|
||||
|
||||
```python
|
||||
# Customise the antibiogram with different settings
|
||||
ro.r('result <- antibiogram(example_isolates, antibiotics = c("TZP", "TZP+TOB", "TZP+GEN"), mo_transform = "gramstain")')
|
||||
|
||||
# Retrieve and print the result
|
||||
result = ro.r('as.data.frame(result)')
|
||||
print(result)
|
||||
```
|
||||
|
||||
Here, we use piperacillin/tazobactam (TZP) in combination with tobramycin (TOB) and gentamicin (GEN) to see how they perform against various Gram-negative bacteria.
|
||||
|
||||
# Conclusion
|
||||
|
||||
With the `AMR` Python package, Python users can now effortlessly call R functions from the `AMR` R package. This eliminates the need for complex `rpy2` configurations and provides a clean, easy-to-use interface for antimicrobial resistance analysis. The examples provided above demonstrate how this can be applied to typical workflows, such as standardising microorganism and antimicrobial names or calculating resistance.
|
||||
|
||||
By using `import AMR`, you can seamlessly integrate the robust features of the R `AMR` package into your Python workflows. Whether you're cleaning data or analysing resistance patterns, the `AMR` Python package makes it easy to work with AMR data in Python.
|
||||
Using `rpy2`, you can easily integrate the power of R's `AMR` package into your Python workflows. Whether you are generating antibiograms, analyzing resistance data, or performing complex filtering, `rpy2` gives you the flexibility to run R code without leaving the Python environment. This makes it a perfect solution for teams working across both R and Python.
|
||||
|
25
vignettes/other_pkg.Rmd
Executable file
25
vignettes/other_pkg.Rmd
Executable file
@ -0,0 +1,25 @@
|
||||
---
|
||||
title: "Using AMR with other packages: AMR & dplyr/tidyverse"
|
||||
output:
|
||||
rmarkdown::html_vignette:
|
||||
toc: true
|
||||
toc_depth: 3
|
||||
vignette: >
|
||||
%\VignetteIndexEntry{How to conduct AMR data analysis}
|
||||
%\VignetteEncoding{UTF-8}
|
||||
%\VignetteEngine{knitr::rmarkdown}
|
||||
editor_options:
|
||||
chunk_output_type: console
|
||||
---
|
||||
|
||||
```{r setup, include = FALSE, results = 'markup'}
|
||||
knitr::opts_chunk$set(
|
||||
warning = FALSE,
|
||||
collapse = TRUE,
|
||||
comment = "#>",
|
||||
fig.width = 7.5,
|
||||
fig.height = 5
|
||||
)
|
||||
```
|
||||
|
||||
This page will be updated shortly, to give explicit examples of how to work ideally with the `AMR` package, for those who are used to working in `dplyr` or other tidyverse packages.
|
Loading…
Reference in New Issue
Block a user