From f025253deb11c652ea3188151a97e53fd1509a78 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 9 Jul 2026 15:21:55 +0000 Subject: [PATCH] Python wrapper update --- AMR.egg-info/PKG-INFO | 254 +++++++ AMR.egg-info/SOURCES.txt | 12 + AMR.egg-info/dependency_links.txt | 1 + AMR.egg-info/requires.txt | 3 + AMR.egg-info/top_level.txt | 1 + AMR/__init__.py | 249 +++++++ AMR/_engine.py | 93 +++ AMR/beta.py | 22 + AMR/datasets.py | 54 ++ AMR/functions.py | 984 +++++++++++++++++++++++++++ README.md | 226 ++++++ dist/amr-3.0.1.9084-py3-none-any.whl | Bin 0 -> 13408 bytes dist/amr-3.0.1.9084.tar.gz | Bin 0 -> 12653 bytes setup.py | 27 + 14 files changed, 1926 insertions(+) create mode 100644 AMR.egg-info/PKG-INFO create mode 100644 AMR.egg-info/SOURCES.txt create mode 100644 AMR.egg-info/dependency_links.txt create mode 100644 AMR.egg-info/requires.txt create mode 100644 AMR.egg-info/top_level.txt create mode 100644 AMR/__init__.py create mode 100644 AMR/_engine.py create mode 100644 AMR/beta.py create mode 100644 AMR/datasets.py create mode 100644 AMR/functions.py create mode 100755 README.md create mode 100644 dist/amr-3.0.1.9084-py3-none-any.whl create mode 100644 dist/amr-3.0.1.9084.tar.gz create mode 100644 setup.py diff --git a/AMR.egg-info/PKG-INFO b/AMR.egg-info/PKG-INFO new file mode 100644 index 000000000..23fc783f3 --- /dev/null +++ b/AMR.egg-info/PKG-INFO @@ -0,0 +1,254 @@ +Metadata-Version: 2.4 +Name: AMR +Version: 3.0.1.9084 +Summary: A Python wrapper for the AMR R package +Home-page: https://github.com/msberends/AMR +Author: Matthijs Berends +Author-email: m.s.berends@umcg.nl +License: GPL 2 +Project-URL: Bug Tracker, https://github.com/msberends/AMR/issues +Classifier: Programming Language :: Python :: 3 +Classifier: Operating System :: OS Independent +Requires-Python: >=3.6 +Description-Content-Type: text/markdown +Requires-Dist: rpy2 +Requires-Dist: numpy +Requires-Dist: pandas +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: description-content-type +Dynamic: home-page +Dynamic: license +Dynamic: project-url +Dynamic: requires-dist +Dynamic: requires-python +Dynamic: summary + + +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](https://pypi.org/project/AMR/). + +This Python package is a wrapper around the `AMR` R package. It uses the `rpy2` package internally. Despite the need to have R installed, Python users can now easily work with AMR data directly through Python code. + +# Prerequisites + +This package was only tested with a [virtual environment (venv)](https://docs.python.org/3/library/venv.html). You can set up such an environment by running: + +```python +# linux and macOS: +python -m venv /path/to/new/virtual/environment + +# Windows: +python -m venv C:\path\to\new\virtual\environment +``` + +Then you can [activate the environment](https://docs.python.org/3/library/venv.html#how-venvs-work), after which the venv is ready to work with. + +# Install AMR + +1. Since the Python package is available on the official [Python Package Index](https://pypi.org/project/AMR/), you can just run: + + ```bash + pip install AMR + ``` + +2. Make sure you have R installed. There is **no need to install the `AMR` R package**, as it will be installed automatically. + + For Linux: + + ```bash + # Ubuntu / Debian + sudo apt install r-base + # Fedora: + sudo dnf install R + # CentOS/RHEL + sudo yum install R + ``` + + For macOS (using [Homebrew](https://brew.sh)): + + ```bash + brew install r + ``` + + For Windows, visit the [CRAN download page](https://cran.r-project.org) to download and install R. + +# Examples of Usage + +## Cleaning Taxonomy + +Here’s an example that demonstrates how to clean microorganism and drug names using the `AMR` Python package: + +```python +import pandas as pd +import AMR + +# Sample data +data = { + "MOs": ['E. coli', 'ESCCOL', 'esco', 'Esche coli'], + "Drug": ['Cipro', 'CIP', 'J01MA02', 'Ciproxin'] +} +df = pd.DataFrame(data) + +# 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']) + +# Display the results +print(df) +``` + +| 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". + +## Calculating AMR + +```python +import AMR +import pandas as pd + +df = AMR.example_isolates +result = AMR.resistance(df["AMX"]) +print(result) +``` + +``` +[0.59555556] +``` + +## Generating Antibiograms + +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) +``` + +| 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) | + + +```python +result2b = AMR.antibiogram(df[["mo", "AMX", "CIP", "TZP"]], mo_transform = "gramstain") +print(result2b) +``` + +| 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) | + + +In this example, we generate an antibiogram by selecting various antibiotics. + +## 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`, `antimicrobials`, `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.antimicrobials +``` + +| 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 Channels + +## Stable Release (CRAN) + +The default `AMR` Python package uses the latest stable version of the `AMR` R package, published on CRAN. After running `pip install AMR`, import it as usual: + +```python +import AMR + +AMR.example_isolates +``` + +## Development Version (GitHub) + +To use the latest development version of the `AMR` R package (sourced directly from GitHub), import the `beta` sub-package and alias it as `AMR`: + +```python +import AMR.beta as AMR + +AMR.example_isolates +``` + +Aliasing with `as AMR` keeps all downstream code identical to the stable import. Switching between the stable release and the development version requires changing only the import line — nothing else in your script needs to change. + +# SIR Classification with `as_sir()` + +## Using `enforce_method` + +The `as_sir()` function in R uses S3 method dispatch to select the correct calculation method based on the input class: `` for MIC values and `` for disk diffusion values. Because Python objects do not carry R class attributes through the `rpy2` bridge, this automatic dispatch may not resolve correctly. + +To explicitly specify the input type, use the `enforce_method` argument: + +```python +# Treat the column as MIC values — maps to R's as.sir.mic() +AMR.as_sir(df["MIC_col"], mo="E. coli", ab="AMX", guideline="EUCAST", enforce_method="mic") + +# Treat the column as disk diffusion values — maps to R's as.sir.disk() +AMR.as_sir(df["disk_col"], mo="E. coli", ab="AMX", guideline="EUCAST", enforce_method="disk") +``` + +Without `enforce_method`, R falls back to class-based dispatch on the raw Python input, which may fail or return unexpected results. Always supply `enforce_method` when calling `as_sir()` from Python. + +# 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 just running `import AMR`, users can seamlessly integrate the robust features of the R `AMR` package into 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. diff --git a/AMR.egg-info/SOURCES.txt b/AMR.egg-info/SOURCES.txt new file mode 100644 index 000000000..617d18f78 --- /dev/null +++ b/AMR.egg-info/SOURCES.txt @@ -0,0 +1,12 @@ +README.md +setup.py +AMR/__init__.py +AMR/_engine.py +AMR/beta.py +AMR/datasets.py +AMR/functions.py +AMR.egg-info/PKG-INFO +AMR.egg-info/SOURCES.txt +AMR.egg-info/dependency_links.txt +AMR.egg-info/requires.txt +AMR.egg-info/top_level.txt \ No newline at end of file diff --git a/AMR.egg-info/dependency_links.txt b/AMR.egg-info/dependency_links.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/AMR.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/AMR.egg-info/requires.txt b/AMR.egg-info/requires.txt new file mode 100644 index 000000000..fb2bcf682 --- /dev/null +++ b/AMR.egg-info/requires.txt @@ -0,0 +1,3 @@ +rpy2 +numpy +pandas diff --git a/AMR.egg-info/top_level.txt b/AMR.egg-info/top_level.txt new file mode 100644 index 000000000..18f3926f7 --- /dev/null +++ b/AMR.egg-info/top_level.txt @@ -0,0 +1 @@ +AMR diff --git a/AMR/__init__.py b/AMR/__init__.py new file mode 100644 index 000000000..741874607 --- /dev/null +++ b/AMR/__init__.py @@ -0,0 +1,249 @@ +import sys + +_DATASETS = frozenset({ + 'example_isolates', 'microorganisms', + 'antimicrobials', 'clinical_breakpoints' +}) + +class _AMRModule(type(sys.modules[__name__])): + """Lazy-loading module: nothing runs until an attribute is accessed.""" + + def __getattr__(self, name): + if name in _DATASETS: + from .datasets import get + return get(name, source="cran") + try: + from . import functions + return getattr(functions, name) + except AttributeError: + raise AttributeError( + f"module 'AMR' has no attribute '{name}'") + +sys.modules[__name__].__class__ = _AMRModule +from .functions import custom_eucast_rules +from .functions import ab_class +from .functions import ab_selector +from .functions import ab_from_text +from .functions import ab_name +from .functions import ab_cid +from .functions import ab_synonyms +from .functions import ab_tradenames +from .functions import ab_group +from .functions import ab_atc +from .functions import ab_atc_group1 +from .functions import ab_atc_group2 +from .functions import ab_loinc +from .functions import ab_ddd +from .functions import ab_ddd_units +from .functions import ab_info +from .functions import ab_url +from .functions import ab_property +from .functions import add_custom_antimicrobials +from .functions import clear_custom_antimicrobials +from .functions import add_custom_microorganisms +from .functions import clear_custom_microorganisms +from .functions import age +from .functions import age_groups +from .functions import all_sir +from .functions import all_sir_predictors +from .functions import all_mic +from .functions import all_mic_predictors +from .functions import all_disk +from .functions import all_disk_predictors +from .functions import step_mic_log2 +from .functions import step_sir_numeric +from .functions import amr_course +from .functions import wisca +from .functions import antibiogram +from .functions import retrieve_wisca_parameters +from .functions import wisca_plot +from .functions import aminoglycosides +from .functions import aminopenicillins +from .functions import antifungals +from .functions import antimycobacterials +from .functions import betalactams +from .functions import betalactams_with_inhibitor +from .functions import carbapenems +from .functions import cephalosporins +from .functions import cephalosporins_1st +from .functions import cephalosporins_2nd +from .functions import cephalosporins_3rd +from .functions import cephalosporins_4th +from .functions import cephalosporins_5th +from .functions import fluoroquinolones +from .functions import glycopeptides +from .functions import ionophores +from .functions import isoxazolylpenicillins +from .functions import lincosamides +from .functions import lipoglycopeptides +from .functions import macrolides +from .functions import monobactams +from .functions import nitrofurans +from .functions import oxazolidinones +from .functions import penicillins +from .functions import peptides +from .functions import phenicols +from .functions import phosphonics +from .functions import polymyxins +from .functions import quinolones +from .functions import rifamycins +from .functions import spiropyrimidinetriones +from .functions import streptogramins +from .functions import sulfonamides +from .functions import tetracyclines +from .functions import trimethoprims +from .functions import ureidopenicillins +from .functions import amr_class +from .functions import amr_selector +from .functions import administrable_per_os +from .functions import administrable_iv +from .functions import not_intrinsic_resistant +from .functions import as_ab +from .functions import is_ab +from .functions import ab_reset_session +from .functions import as_av +from .functions import is_av +from .functions import as_disk +from .functions import is_disk +from .functions import as_mic +from .functions import is_mic +from .functions import rescale_mic +from .functions import mic_p50 +from .functions import mic_p90 +from .functions import as_mo +from .functions import is_mo +from .functions import mo_uncertainties +from .functions import mo_renamed +from .functions import mo_failures +from .functions import mo_reset_session +from .functions import mo_cleaning_regex +from .functions import as_sir +from .functions import is_sir +from .functions import is_sir_eligible +from .functions import sir_interpretation_history +from .functions import atc_online_property +from .functions import atc_online_groups +from .functions import atc_online_ddd +from .functions import atc_online_ddd_units +from .functions import av_from_text +from .functions import av_name +from .functions import av_cid +from .functions import av_synonyms +from .functions import av_tradenames +from .functions import av_group +from .functions import av_atc +from .functions import av_loinc +from .functions import av_ddd +from .functions import av_ddd_units +from .functions import av_info +from .functions import av_url +from .functions import av_property +from .functions import availability +from .functions import bug_drug_combinations +from .functions import count_resistant +from .functions import count_susceptible +from .functions import count_S +from .functions import count_SI +from .functions import count_I +from .functions import count_IR +from .functions import count_R +from .functions import count_all +from .functions import n_sir +from .functions import count_df +from .functions import custom_interpretive_rules +from .functions import custom_mdro_guideline +from .functions import export_ncbi_biosample +from .functions import first_isolate +from .functions import filter_first_isolate +from .functions import g_test +from .functions import is_new_episode +from .functions import ggplot_pca +from .functions import ggplot_sir +from .functions import geom_sir +from .functions import guess_ab_col +from .functions import interpretive_rules +from .functions import eucast_rules +from .functions import clsi_rules +from .functions import eucast_dosage +from .functions import italicise_taxonomy +from .functions import italicize_taxonomy +from .functions import inner_join_microorganisms +from .functions import left_join_microorganisms +from .functions import right_join_microorganisms +from .functions import full_join_microorganisms +from .functions import semi_join_microorganisms +from .functions import anti_join_microorganisms +from .functions import key_antimicrobials +from .functions import all_antimicrobials +from .functions import kurtosis +from .functions import like +from .functions import mdro +from .functions import brmo +from .functions import mrgn +from .functions import mdr_tb +from .functions import mdr_cmi2012 +from .functions import eucast_exceptional_phenotypes +from .functions import mean_amr_distance +from .functions import amr_distance_from_row +from .functions import mo_matching_score +from .functions import mo_name +from .functions import mo_fullname +from .functions import mo_shortname +from .functions import mo_subspecies +from .functions import mo_species +from .functions import mo_genus +from .functions import mo_family +from .functions import mo_order +from .functions import mo_class +from .functions import mo_phylum +from .functions import mo_kingdom +from .functions import mo_domain +from .functions import mo_type +from .functions import mo_status +from .functions import mo_pathogenicity +from .functions import mo_gramstain +from .functions import mo_is_gram_negative +from .functions import mo_is_gram_positive +from .functions import mo_is_yeast +from .functions import mo_is_intrinsic_resistant +from .functions import mo_oxygen_tolerance +from .functions import mo_is_anaerobic +from .functions import mo_morphology +from .functions import mo_snomed +from .functions import mo_ref +from .functions import mo_authors +from .functions import mo_year +from .functions import mo_lpsn +from .functions import mo_mycobank +from .functions import mo_gbif +from .functions import mo_rank +from .functions import mo_taxonomy +from .functions import mo_synonyms +from .functions import mo_current +from .functions import mo_group_members +from .functions import mo_info +from .functions import mo_url +from .functions import mo_property +from .functions import pca +from .functions import theme_sir +from .functions import labels_sir_count +from .functions import resistance +from .functions import susceptibility +from .functions import sir_confidence_interval +from .functions import proportion_R +from .functions import proportion_IR +from .functions import proportion_I +from .functions import proportion_SI +from .functions import proportion_S +from .functions import proportion_df +from .functions import sir_df +from .functions import random_mic +from .functions import random_disk +from .functions import random_sir +from .functions import resistance_predict +from .functions import sir_predict +from .functions import ggplot_sir_predict +from .functions import skewness +from .functions import top_n_microorganisms +from .functions import reset_AMR_locale +from .functions import translate_AMR diff --git a/AMR/_engine.py b/AMR/_engine.py new file mode 100644 index 000000000..cc6c5d9ff --- /dev/null +++ b/AMR/_engine.py @@ -0,0 +1,93 @@ +import os +import sys +import importlib.metadata as metadata + +# Get the path to the virtual environment +venv_path = sys.prefix +r_lib_path = os.path.join(venv_path, "R_libs") +os.makedirs(r_lib_path, exist_ok=True) + +# Set environment variable before importing rpy2 +os.environ['R_LIBS_SITE'] = r_lib_path + +from rpy2 import robjects +from rpy2.robjects.vectors import StrVector +from rpy2.robjects.packages import importr, isinstalled + +# Import base and utils once +base = importr('base') +utils = importr('utils') + +# Silence R console output entirely +robjects.r('suppressMessages(suppressWarnings(sink(tempfile())))') +base._libPaths(r_lib_path) + +_installed_source = None + +def _r_version(): + """Return the currently installed AMR R package version, or None.""" + try: + return str(robjects.r( + f'as.character(packageVersion("AMR", lib.loc = "{r_lib_path}"))')[0]) + except Exception: + return None + +def _py_version(): + """Return the Python AMR package version from metadata, or empty string.""" + try: + return str(metadata.version('AMR')) + except metadata.PackageNotFoundError: + return '' + +def _install_cran(): + """Install AMR from CRAN into the isolated library.""" + print("AMR: Installing from CRAN...", flush=True) + utils.install_packages( + 'AMR', + repos='https://cloud.r-project.org', + lib=r_lib_path, + quiet=True + ) + +def _install_github(): + """Install AMR development version from GitHub into the isolated library.""" + print("AMR: Installing development version from GitHub...", flush=True) + utils.install_packages( + StrVector(['remotes', 'desc']), + repos='https://cloud.r-project.org', + lib=r_lib_path, + quiet=True + ) + remotes = importr('remotes', lib_loc=r_lib_path) + remotes.install_github('msberends/AMR', lib=r_lib_path, quiet=True) + +def ensure_amr(source="cran"): + """Ensure AMR is installed from the requested source. Idempotent per source.""" + global _installed_source + + if _installed_source == source: + return + + install_fn = _install_github if source == "github" else _install_cran + + if not isinstalled('AMR', lib_loc=r_lib_path): + install_fn() + else: + # Check for version mismatch and update if needed + r_ver = _r_version() + py_ver = _py_version() + if r_ver != py_ver: + try: + install_fn() + except Exception as e: + print(f"AMR: Could not update ({e})", flush=True) + + print(f"AMR: R package version {_r_version()} ready.", flush=True) + _installed_source = source + +def restore_sink(): + """Restore R console output after setup is complete.""" + try: + robjects.r('sink()') + except Exception: + pass diff --git a/AMR/beta.py b/AMR/beta.py new file mode 100644 index 000000000..df55d4f81 --- /dev/null +++ b/AMR/beta.py @@ -0,0 +1,22 @@ +import sys + +_DATASETS = frozenset({ + 'example_isolates', 'microorganisms', + 'antimicrobials', 'clinical_breakpoints' +}) + +class _BetaModule(type(sys.modules[__name__])): + """Lazy-loading module: installs AMR from GitHub on first access.""" + + def __getattr__(self, name): + if name in _DATASETS: + from .datasets import get + return get(name, source="github") + try: + from . import functions + return getattr(functions, name) + except AttributeError: + raise AttributeError( + f"module 'AMR.beta' has no attribute '{name}'") + +sys.modules[__name__].__class__ = _BetaModule diff --git a/AMR/datasets.py b/AMR/datasets.py new file mode 100644 index 000000000..1c84065e7 --- /dev/null +++ b/AMR/datasets.py @@ -0,0 +1,54 @@ +import pandas as pd +from rpy2 import robjects +from rpy2.robjects.conversion import localconverter +from rpy2.robjects import default_converter, numpy2ri, pandas2ri + +from ._engine import ensure_amr, restore_sink + +_cache = {} +_loaded_source = None + +def _load_datasets(source="cran"): + """Load all AMR datasets into the module cache.""" + global _loaded_source + + if _cache and _loaded_source == source: + return + + if _cache and _loaded_source != source: + _cache.clear() + + ensure_amr(source) + + with localconverter(default_converter + numpy2ri.converter + pandas2ri.converter): + _cache['example_isolates'] = _load_example_isolates() + _cache['microorganisms'] = robjects.r( + 'AMR::microorganisms[, !sapply(AMR::microorganisms, is.list)]') + _cache['antimicrobials'] = robjects.r( + 'AMR::antimicrobials[, !sapply(AMR::antimicrobials, is.list)]') + _cache['clinical_breakpoints'] = robjects.r( + 'AMR::clinical_breakpoints[, !sapply(AMR::clinical_breakpoints, is.list)]') + + restore_sink() + _loaded_source = source + +def _load_example_isolates(): + df = robjects.r(''' + df <- AMR::example_isolates + df[] <- lapply(df, function(x) { + if (inherits(x, c("Date", "POSIXt", "factor"))) { + as.character(x) + } else { + x + } + }) + df <- df[, !sapply(df, is.list)] + df + ''') + df['date'] = pd.to_datetime(df['date']) + return df + +def get(name, source="cran"): + """Retrieve a dataset by name, installing AMR if needed.""" + _load_datasets(source) + return _cache[name] diff --git a/AMR/functions.py b/AMR/functions.py new file mode 100644 index 000000000..d8eef8f9b --- /dev/null +++ b/AMR/functions.py @@ -0,0 +1,984 @@ +import functools +import rpy2.robjects as robjects +from rpy2.robjects.packages import importr +from rpy2.robjects.vectors import StrVector, FactorVector, IntVector, FloatVector, DataFrame +from rpy2.robjects.conversion import localconverter +from rpy2.robjects import default_converter, numpy2ri, pandas2ri +import pandas as pd +import numpy as np + +from ._engine import ensure_amr + +# Ensure AMR is available before importing it in R +ensure_amr("cran") +amr_r = importr('AMR') + +def convert_to_r(value): + """Convert Python lists/tuples to typed R vectors. + + rpy2's default_converter passes Python lists to R as R lists, not as + character/numeric vectors. This causes element-wise type-check functions + such as is.mic(), is.sir(), and is.disk() to return a logical vector + rather than a single logical, breaking R's scalar && operator. + + This helper converts Python lists and tuples to the appropriate R vector + type based on the element types, so R always receives a proper vector.""" + if isinstance(value, (list, tuple)): + if len(value) == 0: + return StrVector([]) + # bool must be checked before int because bool is a subclass of int + if all(isinstance(v, bool) for v in value): + return robjects.vectors.BoolVector(value) + if all(isinstance(v, int) for v in value): + return IntVector(value) + if all(isinstance(v, float) for v in value): + return FloatVector(value) + if all(isinstance(v, str) for v in value): + return StrVector(value) + # Mixed types: coerce all to string + return StrVector([str(v) for v in value]) + return value + +def convert_to_python(r_output): + # Check if it's a StrVector (R character vector) + if isinstance(r_output, StrVector): + return list(r_output) # Convert to a Python list of strings + + # Check if it's a FactorVector (R factor) + elif isinstance(r_output, FactorVector): + return list(r_output) # Convert to a list of integers (factor levels) + + # Check if it's an IntVector or FloatVector (numeric R vectors) + elif isinstance(r_output, (IntVector, FloatVector)): + return list(r_output) # Convert to a Python list of integers or floats + + # Check if it's a pandas-compatible R data frame + elif isinstance(r_output, (pd.DataFrame, DataFrame)): + return r_output # Return as pandas DataFrame (already converted by pandas2ri) + + # 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 + return r_output + +def r_to_python(r_func): + """Decorator that converts Python list/tuple inputs to typed R vectors, + runs the rpy2 function under a localconverter, and converts the output + to a Python type.""" + @functools.wraps(r_func) + def wrapper(*args, **kwargs): + args = tuple(convert_to_r(a) for a in args) + kwargs = {k: convert_to_r(v) for k, v in kwargs.items()} + with localconverter(default_converter + numpy2ri.converter + pandas2ri.converter): + return convert_to_python(r_func(*args, **kwargs)) + return wrapper +@r_to_python +def custom_eucast_rules(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.custom_eucast_rules(*args, **kwargs) +@r_to_python +def ab_class(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_class(*args, **kwargs) +@r_to_python +def ab_selector(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_selector(*args, **kwargs) +@r_to_python +def ab_from_text(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_from_text(*args, **kwargs) +@r_to_python +def ab_name(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_name(x, *args, **kwargs) +@r_to_python +def ab_cid(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_cid(x, *args, **kwargs) +@r_to_python +def ab_synonyms(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_synonyms(x, *args, **kwargs) +@r_to_python +def ab_tradenames(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_tradenames(x, *args, **kwargs) +@r_to_python +def ab_group(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_group(x, *args, **kwargs) +@r_to_python +def ab_atc(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_atc(x, *args, **kwargs) +@r_to_python +def ab_atc_group1(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_atc_group1(x, *args, **kwargs) +@r_to_python +def ab_atc_group2(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_atc_group2(x, *args, **kwargs) +@r_to_python +def ab_loinc(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_loinc(x, *args, **kwargs) +@r_to_python +def ab_ddd(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_ddd(x, *args, **kwargs) +@r_to_python +def ab_ddd_units(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_ddd_units(x, *args, **kwargs) +@r_to_python +def ab_info(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_info(x, *args, **kwargs) +@r_to_python +def ab_url(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_url(x, *args, **kwargs) +@r_to_python +def ab_property(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_property(x, *args, **kwargs) +@r_to_python +def add_custom_antimicrobials(x): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.add_custom_antimicrobials(x) +@r_to_python +def clear_custom_antimicrobials(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.clear_custom_antimicrobials(*args, **kwargs) +@r_to_python +def add_custom_microorganisms(x): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.add_custom_microorganisms(x) +@r_to_python +def clear_custom_microorganisms(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.clear_custom_microorganisms(*args, **kwargs) +@r_to_python +def age(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.age(x, *args, **kwargs) +@r_to_python +def age_groups(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.age_groups(x, *args, **kwargs) +@r_to_python +def all_sir(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.all_sir(*args, **kwargs) +@r_to_python +def all_sir_predictors(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.all_sir_predictors(*args, **kwargs) +@r_to_python +def all_mic(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.all_mic(*args, **kwargs) +@r_to_python +def all_mic_predictors(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.all_mic_predictors(*args, **kwargs) +@r_to_python +def all_disk(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.all_disk(*args, **kwargs) +@r_to_python +def all_disk_predictors(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.all_disk_predictors(*args, **kwargs) +@r_to_python +def step_mic_log2(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.step_mic_log2(*args, **kwargs) +@r_to_python +def step_sir_numeric(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.step_sir_numeric(*args, **kwargs) +@r_to_python +def amr_course(github_repo, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.amr_course(github_repo, *args, **kwargs) +@r_to_python +def wisca(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.wisca(*args, **kwargs) +@r_to_python +def antibiogram(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.antibiogram(*args, **kwargs) +@r_to_python +def retrieve_wisca_parameters(wisca_model, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.retrieve_wisca_parameters(wisca_model, *args, **kwargs) +@r_to_python +def wisca_plot(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.wisca_plot(*args, **kwargs) +@r_to_python +def aminoglycosides(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.aminoglycosides(*args, **kwargs) +@r_to_python +def aminopenicillins(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.aminopenicillins(only_sir_columns = False, *args, **kwargs) +@r_to_python +def antifungals(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.antifungals(only_sir_columns = False, *args, **kwargs) +@r_to_python +def antimycobacterials(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.antimycobacterials(only_sir_columns = False, *args, **kwargs) +@r_to_python +def betalactams(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.betalactams(*args, **kwargs) +@r_to_python +def betalactams_with_inhibitor(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.betalactams_with_inhibitor(only_sir_columns = False, *args, **kwargs) +@r_to_python +def carbapenems(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.carbapenems(*args, **kwargs) +@r_to_python +def cephalosporins(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.cephalosporins(*args, **kwargs) +@r_to_python +def cephalosporins_1st(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.cephalosporins_1st(only_sir_columns = False, *args, **kwargs) +@r_to_python +def cephalosporins_2nd(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.cephalosporins_2nd(only_sir_columns = False, *args, **kwargs) +@r_to_python +def cephalosporins_3rd(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.cephalosporins_3rd(*args, **kwargs) +@r_to_python +def cephalosporins_4th(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.cephalosporins_4th(only_sir_columns = False, *args, **kwargs) +@r_to_python +def cephalosporins_5th(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.cephalosporins_5th(only_sir_columns = False, *args, **kwargs) +@r_to_python +def fluoroquinolones(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.fluoroquinolones(*args, **kwargs) +@r_to_python +def glycopeptides(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.glycopeptides(only_sir_columns = False, *args, **kwargs) +@r_to_python +def ionophores(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ionophores(only_sir_columns = False, *args, **kwargs) +@r_to_python +def isoxazolylpenicillins(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.isoxazolylpenicillins(*args, **kwargs) +@r_to_python +def lincosamides(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.lincosamides(*args, **kwargs) +@r_to_python +def lipoglycopeptides(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.lipoglycopeptides(only_sir_columns = False, *args, **kwargs) +@r_to_python +def macrolides(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.macrolides(only_sir_columns = False, *args, **kwargs) +@r_to_python +def monobactams(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.monobactams(only_sir_columns = False, *args, **kwargs) +@r_to_python +def nitrofurans(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.nitrofurans(only_sir_columns = False, *args, **kwargs) +@r_to_python +def oxazolidinones(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.oxazolidinones(only_sir_columns = False, *args, **kwargs) +@r_to_python +def penicillins(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.penicillins(only_sir_columns = False, *args, **kwargs) +@r_to_python +def peptides(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.peptides(only_sir_columns = False, *args, **kwargs) +@r_to_python +def phenicols(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.phenicols(only_sir_columns = False, *args, **kwargs) +@r_to_python +def phosphonics(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.phosphonics(only_sir_columns = False, *args, **kwargs) +@r_to_python +def polymyxins(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.polymyxins(*args, **kwargs) +@r_to_python +def quinolones(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.quinolones(*args, **kwargs) +@r_to_python +def rifamycins(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.rifamycins(only_sir_columns = False, *args, **kwargs) +@r_to_python +def spiropyrimidinetriones(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.spiropyrimidinetriones(only_sir_columns = False, *args, **kwargs) +@r_to_python +def streptogramins(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.streptogramins(only_sir_columns = False, *args, **kwargs) +@r_to_python +def sulfonamides(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.sulfonamides(only_sir_columns = False, *args, **kwargs) +@r_to_python +def tetracyclines(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.tetracyclines(*args, **kwargs) +@r_to_python +def trimethoprims(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.trimethoprims(only_sir_columns = False, *args, **kwargs) +@r_to_python +def ureidopenicillins(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ureidopenicillins(only_sir_columns = False, *args, **kwargs) +@r_to_python +def amr_class(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.amr_class(*args, **kwargs) +@r_to_python +def amr_selector(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.amr_selector(*args, **kwargs) +@r_to_python +def administrable_per_os(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.administrable_per_os(only_sir_columns = False, *args, **kwargs) +@r_to_python +def administrable_iv(only_sir_columns = False, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.administrable_iv(only_sir_columns = False, *args, **kwargs) +@r_to_python +def not_intrinsic_resistant(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.not_intrinsic_resistant(*args, **kwargs) +@r_to_python +def as_ab(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.as_ab(*args, **kwargs) +@r_to_python +def is_ab(x): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.is_ab(x) +@r_to_python +def ab_reset_session(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ab_reset_session(*args, **kwargs) +@r_to_python +def as_av(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.as_av(x, *args, **kwargs) +@r_to_python +def is_av(x): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.is_av(x) +@r_to_python +def as_disk(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.as_disk(x, *args, **kwargs) +@r_to_python +def is_disk(x): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.is_disk(x) +@r_to_python +def as_mic(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.as_mic(x, *args, **kwargs) +@r_to_python +def is_mic(x): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.is_mic(x) +@r_to_python +def rescale_mic(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.rescale_mic(*args, **kwargs) +@r_to_python +def mic_p50(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mic_p50(x, *args, **kwargs) +@r_to_python +def mic_p90(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mic_p90(x, *args, **kwargs) +@r_to_python +def as_mo(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.as_mo(*args, **kwargs) +@r_to_python +def is_mo(x): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.is_mo(x) +@r_to_python +def mo_uncertainties(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_uncertainties(*args, **kwargs) +@r_to_python +def mo_renamed(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_renamed(*args, **kwargs) +@r_to_python +def mo_failures(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_failures(*args, **kwargs) +@r_to_python +def mo_reset_session(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_reset_session(*args, **kwargs) +@r_to_python +def mo_cleaning_regex(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_cleaning_regex(*args, **kwargs) +@r_to_python +def as_sir(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.as_sir(x, *args, **kwargs) +@r_to_python +def is_sir(x): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.is_sir(x) +@r_to_python +def is_sir_eligible(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.is_sir_eligible(x, *args, **kwargs) +@r_to_python +def sir_interpretation_history(clean): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.sir_interpretation_history(clean) +@r_to_python +def atc_online_property(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.atc_online_property(*args, **kwargs) +@r_to_python +def atc_online_groups(atc_code, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.atc_online_groups(atc_code, *args, **kwargs) +@r_to_python +def atc_online_ddd(atc_code, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.atc_online_ddd(atc_code, *args, **kwargs) +@r_to_python +def atc_online_ddd_units(atc_code, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.atc_online_ddd_units(atc_code, *args, **kwargs) +@r_to_python +def av_from_text(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_from_text(*args, **kwargs) +@r_to_python +def av_name(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_name(x, *args, **kwargs) +@r_to_python +def av_cid(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_cid(x, *args, **kwargs) +@r_to_python +def av_synonyms(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_synonyms(x, *args, **kwargs) +@r_to_python +def av_tradenames(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_tradenames(x, *args, **kwargs) +@r_to_python +def av_group(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_group(x, *args, **kwargs) +@r_to_python +def av_atc(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_atc(x, *args, **kwargs) +@r_to_python +def av_loinc(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_loinc(x, *args, **kwargs) +@r_to_python +def av_ddd(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_ddd(x, *args, **kwargs) +@r_to_python +def av_ddd_units(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_ddd_units(x, *args, **kwargs) +@r_to_python +def av_info(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_info(x, *args, **kwargs) +@r_to_python +def av_url(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_url(x, *args, **kwargs) +@r_to_python +def av_property(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.av_property(x, *args, **kwargs) +@r_to_python +def availability(tbl, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.availability(tbl, *args, **kwargs) +@r_to_python +def bug_drug_combinations(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.bug_drug_combinations(*args, **kwargs) +@r_to_python +def count_resistant(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.count_resistant(*args, **kwargs) +@r_to_python +def count_susceptible(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.count_susceptible(*args, **kwargs) +@r_to_python +def count_S(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.count_S(*args, **kwargs) +@r_to_python +def count_SI(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.count_SI(*args, **kwargs) +@r_to_python +def count_I(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.count_I(*args, **kwargs) +@r_to_python +def count_IR(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.count_IR(*args, **kwargs) +@r_to_python +def count_R(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.count_R(*args, **kwargs) +@r_to_python +def count_all(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.count_all(*args, **kwargs) +@r_to_python +def n_sir(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.n_sir(*args, **kwargs) +@r_to_python +def count_df(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.count_df(*args, **kwargs) +@r_to_python +def custom_interpretive_rules(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.custom_interpretive_rules(*args, **kwargs) +@r_to_python +def custom_mdro_guideline(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.custom_mdro_guideline(*args, **kwargs) +@r_to_python +def export_ncbi_biosample(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.export_ncbi_biosample(*args, **kwargs) +@r_to_python +def first_isolate(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.first_isolate(*args, **kwargs) +@r_to_python +def filter_first_isolate(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.filter_first_isolate(*args, **kwargs) +@r_to_python +def g_test(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.g_test(x, *args, **kwargs) +@r_to_python +def is_new_episode(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.is_new_episode(x, *args, **kwargs) +@r_to_python +def ggplot_pca(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ggplot_pca(*args, **kwargs) +@r_to_python +def ggplot_sir(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ggplot_sir(*args, **kwargs) +@r_to_python +def geom_sir(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.geom_sir(*args, **kwargs) +@r_to_python +def guess_ab_col(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.guess_ab_col(*args, **kwargs) +@r_to_python +def interpretive_rules(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.interpretive_rules(*args, **kwargs) +@r_to_python +def eucast_rules(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.eucast_rules(*args, **kwargs) +@r_to_python +def clsi_rules(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.clsi_rules(*args, **kwargs) +@r_to_python +def eucast_dosage(ab, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.eucast_dosage(ab, *args, **kwargs) +@r_to_python +def italicise_taxonomy(string, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.italicise_taxonomy(string, *args, **kwargs) +@r_to_python +def italicize_taxonomy(string, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.italicize_taxonomy(string, *args, **kwargs) +@r_to_python +def inner_join_microorganisms(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.inner_join_microorganisms(x, *args, **kwargs) +@r_to_python +def left_join_microorganisms(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.left_join_microorganisms(x, *args, **kwargs) +@r_to_python +def right_join_microorganisms(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.right_join_microorganisms(x, *args, **kwargs) +@r_to_python +def full_join_microorganisms(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.full_join_microorganisms(x, *args, **kwargs) +@r_to_python +def semi_join_microorganisms(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.semi_join_microorganisms(x, *args, **kwargs) +@r_to_python +def anti_join_microorganisms(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.anti_join_microorganisms(x, *args, **kwargs) +@r_to_python +def key_antimicrobials(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.key_antimicrobials(*args, **kwargs) +@r_to_python +def all_antimicrobials(x = None, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.all_antimicrobials(x = None, *args, **kwargs) +@r_to_python +def kurtosis(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.kurtosis(x, *args, **kwargs) +@r_to_python +def like(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.like(x, *args, **kwargs) +@r_to_python +def mdro(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mdro(*args, **kwargs) +@r_to_python +def brmo(x = None, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.brmo(x = None, *args, **kwargs) +@r_to_python +def mrgn(x = None, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mrgn(x = None, *args, **kwargs) +@r_to_python +def mdr_tb(x = None, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mdr_tb(x = None, *args, **kwargs) +@r_to_python +def mdr_cmi2012(x = None, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mdr_cmi2012(x = None, *args, **kwargs) +@r_to_python +def eucast_exceptional_phenotypes(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.eucast_exceptional_phenotypes(*args, **kwargs) +@r_to_python +def mean_amr_distance(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mean_amr_distance(x, *args, **kwargs) +@r_to_python +def amr_distance_from_row(amr_distance, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.amr_distance_from_row(amr_distance, *args, **kwargs) +@r_to_python +def mo_matching_score(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_matching_score(x, *args, **kwargs) +@r_to_python +def mo_name(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_name(*args, **kwargs) +@r_to_python +def mo_fullname(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_fullname(*args, **kwargs) +@r_to_python +def mo_shortname(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_shortname(*args, **kwargs) +@r_to_python +def mo_subspecies(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_subspecies(*args, **kwargs) +@r_to_python +def mo_species(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_species(*args, **kwargs) +@r_to_python +def mo_genus(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_genus(*args, **kwargs) +@r_to_python +def mo_family(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_family(*args, **kwargs) +@r_to_python +def mo_order(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_order(*args, **kwargs) +@r_to_python +def mo_class(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_class(*args, **kwargs) +@r_to_python +def mo_phylum(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_phylum(*args, **kwargs) +@r_to_python +def mo_kingdom(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_kingdom(*args, **kwargs) +@r_to_python +def mo_domain(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_domain(*args, **kwargs) +@r_to_python +def mo_type(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_type(*args, **kwargs) +@r_to_python +def mo_status(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_status(*args, **kwargs) +@r_to_python +def mo_pathogenicity(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_pathogenicity(*args, **kwargs) +@r_to_python +def mo_gramstain(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_gramstain(*args, **kwargs) +@r_to_python +def mo_is_gram_negative(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_is_gram_negative(*args, **kwargs) +@r_to_python +def mo_is_gram_positive(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_is_gram_positive(*args, **kwargs) +@r_to_python +def mo_is_yeast(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_is_yeast(*args, **kwargs) +@r_to_python +def mo_is_intrinsic_resistant(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_is_intrinsic_resistant(*args, **kwargs) +@r_to_python +def mo_oxygen_tolerance(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_oxygen_tolerance(*args, **kwargs) +@r_to_python +def mo_is_anaerobic(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_is_anaerobic(*args, **kwargs) +@r_to_python +def mo_morphology(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_morphology(*args, **kwargs) +@r_to_python +def mo_snomed(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_snomed(*args, **kwargs) +@r_to_python +def mo_ref(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_ref(*args, **kwargs) +@r_to_python +def mo_authors(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_authors(*args, **kwargs) +@r_to_python +def mo_year(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_year(*args, **kwargs) +@r_to_python +def mo_lpsn(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_lpsn(*args, **kwargs) +@r_to_python +def mo_mycobank(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_mycobank(*args, **kwargs) +@r_to_python +def mo_gbif(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_gbif(*args, **kwargs) +@r_to_python +def mo_rank(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_rank(*args, **kwargs) +@r_to_python +def mo_taxonomy(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_taxonomy(*args, **kwargs) +@r_to_python +def mo_synonyms(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_synonyms(*args, **kwargs) +@r_to_python +def mo_current(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_current(x, *args, **kwargs) +@r_to_python +def mo_group_members(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_group_members(*args, **kwargs) +@r_to_python +def mo_info(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_info(*args, **kwargs) +@r_to_python +def mo_url(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_url(*args, **kwargs) +@r_to_python +def mo_property(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.mo_property(*args, **kwargs) +@r_to_python +def pca(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.pca(*args, **kwargs) +@r_to_python +def theme_sir(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.theme_sir(*args, **kwargs) +@r_to_python +def labels_sir_count(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.labels_sir_count(*args, **kwargs) +@r_to_python +def resistance(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.resistance(*args, **kwargs) +@r_to_python +def susceptibility(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.susceptibility(*args, **kwargs) +@r_to_python +def sir_confidence_interval(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.sir_confidence_interval(*args, **kwargs) +@r_to_python +def proportion_R(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.proportion_R(*args, **kwargs) +@r_to_python +def proportion_IR(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.proportion_IR(*args, **kwargs) +@r_to_python +def proportion_I(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.proportion_I(*args, **kwargs) +@r_to_python +def proportion_SI(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.proportion_SI(*args, **kwargs) +@r_to_python +def proportion_S(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.proportion_S(*args, **kwargs) +@r_to_python +def proportion_df(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.proportion_df(*args, **kwargs) +@r_to_python +def sir_df(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.sir_df(*args, **kwargs) +@r_to_python +def random_mic(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.random_mic(*args, **kwargs) +@r_to_python +def random_disk(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.random_disk(*args, **kwargs) +@r_to_python +def random_sir(size = None, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.random_sir(size = None, *args, **kwargs) +@r_to_python +def resistance_predict(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.resistance_predict(*args, **kwargs) +@r_to_python +def sir_predict(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.sir_predict(*args, **kwargs) +@r_to_python +def ggplot_sir_predict(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.ggplot_sir_predict(*args, **kwargs) +@r_to_python +def skewness(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.skewness(x, *args, **kwargs) +@r_to_python +def top_n_microorganisms(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.top_n_microorganisms(*args, **kwargs) +@r_to_python +def reset_AMR_locale(*args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.reset_AMR_locale(*args, **kwargs) +@r_to_python +def translate_AMR(x, *args, **kwargs): + """Please see our website of the R package for the full manual: https://amr-for-r.org""" + return amr_r.translate_AMR(x, *args, **kwargs) diff --git a/README.md b/README.md new file mode 100755 index 000000000..0e944d21f --- /dev/null +++ b/README.md @@ -0,0 +1,226 @@ + +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](https://pypi.org/project/AMR/). + +This Python package is a wrapper around the `AMR` R package. It uses the `rpy2` package internally. Despite the need to have R installed, Python users can now easily work with AMR data directly through Python code. + +# Prerequisites + +This package was only tested with a [virtual environment (venv)](https://docs.python.org/3/library/venv.html). You can set up such an environment by running: + +```python +# linux and macOS: +python -m venv /path/to/new/virtual/environment + +# Windows: +python -m venv C:\path\to\new\virtual\environment +``` + +Then you can [activate the environment](https://docs.python.org/3/library/venv.html#how-venvs-work), after which the venv is ready to work with. + +# Install AMR + +1. Since the Python package is available on the official [Python Package Index](https://pypi.org/project/AMR/), you can just run: + + ```bash + pip install AMR + ``` + +2. Make sure you have R installed. There is **no need to install the `AMR` R package**, as it will be installed automatically. + + For Linux: + + ```bash + # Ubuntu / Debian + sudo apt install r-base + # Fedora: + sudo dnf install R + # CentOS/RHEL + sudo yum install R + ``` + + For macOS (using [Homebrew](https://brew.sh)): + + ```bash + brew install r + ``` + + For Windows, visit the [CRAN download page](https://cran.r-project.org) to download and install R. + +# Examples of Usage + +## Cleaning Taxonomy + +Here’s an example that demonstrates how to clean microorganism and drug names using the `AMR` Python package: + +```python +import pandas as pd +import AMR + +# Sample data +data = { + "MOs": ['E. coli', 'ESCCOL', 'esco', 'Esche coli'], + "Drug": ['Cipro', 'CIP', 'J01MA02', 'Ciproxin'] +} +df = pd.DataFrame(data) + +# 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']) + +# Display the results +print(df) +``` + +| 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". + +## Calculating AMR + +```python +import AMR +import pandas as pd + +df = AMR.example_isolates +result = AMR.resistance(df["AMX"]) +print(result) +``` + +``` +[0.59555556] +``` + +## Generating Antibiograms + +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) +``` + +| 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) | + + +```python +result2b = AMR.antibiogram(df[["mo", "AMX", "CIP", "TZP"]], mo_transform = "gramstain") +print(result2b) +``` + +| 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) | + + +In this example, we generate an antibiogram by selecting various antibiotics. + +## 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`, `antimicrobials`, `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.antimicrobials +``` + +| 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 Channels + +## Stable Release (CRAN) + +The default `AMR` Python package uses the latest stable version of the `AMR` R package, published on CRAN. After running `pip install AMR`, import it as usual: + +```python +import AMR + +AMR.example_isolates +``` + +## Development Version (GitHub) + +To use the latest development version of the `AMR` R package (sourced directly from GitHub), import the `beta` sub-package and alias it as `AMR`: + +```python +import AMR.beta as AMR + +AMR.example_isolates +``` + +Aliasing with `as AMR` keeps all downstream code identical to the stable import. Switching between the stable release and the development version requires changing only the import line — nothing else in your script needs to change. + +# SIR Classification with `as_sir()` + +## Using `enforce_method` + +The `as_sir()` function in R uses S3 method dispatch to select the correct calculation method based on the input class: `` for MIC values and `` for disk diffusion values. Because Python objects do not carry R class attributes through the `rpy2` bridge, this automatic dispatch may not resolve correctly. + +To explicitly specify the input type, use the `enforce_method` argument: + +```python +# Treat the column as MIC values — maps to R's as.sir.mic() +AMR.as_sir(df["MIC_col"], mo="E. coli", ab="AMX", guideline="EUCAST", enforce_method="mic") + +# Treat the column as disk diffusion values — maps to R's as.sir.disk() +AMR.as_sir(df["disk_col"], mo="E. coli", ab="AMX", guideline="EUCAST", enforce_method="disk") +``` + +Without `enforce_method`, R falls back to class-based dispatch on the raw Python input, which may fail or return unexpected results. Always supply `enforce_method` when calling `as_sir()` from Python. + +# 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 just running `import AMR`, users can seamlessly integrate the robust features of the R `AMR` package into 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. diff --git a/dist/amr-3.0.1.9084-py3-none-any.whl b/dist/amr-3.0.1.9084-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..270258551fe30b0ff389b4f194338d01531e8ec5 GIT binary patch literal 13408 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