Skip to contents

Generate an antibiogram, and communicate the results in plots or tables. These functions follow the logic of Klinker et al. (2021, doi:10.1177/20499361211011373 ) and Barbieri et al. (2021, doi:10.1186/s13756-021-00939-2 ), and allow reporting in e.g. R Markdown and Quarto as well.

Usage

antibiogram(
  x,
  antibiotics = where(is.sir),
  mo_transform = "shortname",
  ab_transform = NULL,
  syndromic_group = NULL,
  add_total_n = TRUE,
  only_all_tested = FALSE,
  digits = 0,
  col_mo = NULL,
  language = get_AMR_locale(),
  minimum = 30,
  combine_SI = TRUE,
  sep = " + "
)

# S3 method for antibiogram
plot(x, ...)

# S3 method for antibiogram
autoplot(object, ...)

# S3 method for antibiogram
print(x, as_kable = !interactive(), ...)

Source

  • Klinker KP et al. (2021). Antimicrobial stewardship and antibiograms: importance of moving beyond traditional antibiograms. Therapeutic Advances in Infectious Disease, May 5;8:20499361211011373; doi:10.1177/20499361211011373

  • Barbieri E et al. (2021). Development of a Weighted-Incidence Syndromic Combination Antibiogram (WISCA) to guide the choice of the empiric antibiotic treatment for urinary tract infection in paediatric patients: a Bayesian approach Antimicrobial Resistance & Infection Control May 1;10(1):74; doi:10.1186/s13756-021-00939-2

  • M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 5th Edition, 2022, Clinical and Laboratory Standards Institute (CLSI). https://clsi.org/standards/products/microbiology/documents/m39/.

Arguments

x

a data.frame containing at least a column with microorganisms and columns with antibiotic results (class 'sir', see as.sir())

antibiotics

vector of column names, or (any combinations of) antibiotic selectors such as aminoglycosides() or carbapenems(). For combination antibiograms, this can also be column names separated with "+", such as "TZP+TOB" given that the data set contains columns "TZP" and "TOB". See Examples.

mo_transform

a character to transform microorganism input - must be "name", "shortname", "gramstain", or one of the column names of the microorganisms data set: "mo", "fullname", "status", "kingdom", "phylum", "class", "order", "family", "genus", "species", "subspecies", "rank", "ref", "source", "lpsn", "lpsn_parent", "lpsn_renamed_to", "gbif", "gbif_parent", "gbif_renamed_to", "prevalence" or "snomed". Can also be NULL to not transform the input.

ab_transform

a character to transform antibiotic input - must be one of the column names of the antibiotics data set: "ab", "cid", "name", "group", "atc", "atc_group1", "atc_group2", "abbreviations", "synonyms", "oral_ddd", "oral_units", "iv_ddd", "iv_units" or "loinc". Can also be NULL to not transform the input.

syndromic_group

a column name of x, or values calculated to split rows of x, e.g. by using ifelse() or case_when(). See Examples.

add_total_n

a logical to indicate whether total available numbers per pathogen should be added to the table (defaults to TRUE). This will add the lowest and highest number of available isolate per antibiotic (e.g, if for E. coli 200 isolates are available for ciprofloxacin and 150 for amoxicillin, the returned number will be "150-200").

only_all_tested

(for combination antibiograms): a logical to indicate that isolates must be tested for all antibiotics, see Details

digits

number of digits to use for rounding

col_mo

column name of the names or codes of the microorganisms (see as.mo()), defaults to the first column of class mo. Values will be coerced using as.mo().

language

language to translate text, which defaults to the system language (see get_AMR_locale())

minimum

the minimum allowed number of available (tested) isolates. Any isolate count lower than minimum will return NA with a warning. The default number of 30 isolates is advised by the Clinical and Laboratory Standards Institute (CLSI) as best practice, see Source.

combine_SI

a logical to indicate whether all susceptibility should be determined by results of either S or I, instead of only S (defaults to TRUE)

sep

a separating character for antibiotic columns in combination antibiograms

...

method extensions

object

an antibiogram() object

as_kable

a logical to indicate whether the printing should be done using knitr::kable() (which is the default in non-interactive sessions)

Details

This function returns a table with values between 0 and 100 for susceptibility, not resistance.

Remember that you should filter your data to let it contain only first isolates! This is needed to exclude duplicates and to reduce selection bias. Use first_isolate() to determine them in your data set with one of the four available algorithms.

There are four antibiogram types, as proposed by Klinker et al. (2021, doi:10.1177/20499361211011373 ), and they are all supported by antibiogram():

  1. Traditional Antibiogram

    Case example: Susceptibility of Pseudomonas aeruginosa to piperacillin/tazobactam (TZP)

    Code example:

    antibiogram(your_data,
                antibiotics = "TZP")

  2. Combination Antibiogram

    Case example: Additional susceptibility of Pseudomonas aeruginosa to TZP + tobramycin versus TZP alone

    Code example:

    antibiogram(your_data,
                antibiotics = c("TZP", "TZP+TOB", "TZP+GEN"))

  3. Syndromic Antibiogram

    Case example: Susceptibility of Pseudomonas aeruginosa to TZP among respiratory specimens (obtained among ICU patients only)

    Code example:

    antibiogram(your_data,
                antibiotics = penicillins(),
                syndromic_group = "ward")

  4. Weighted-Incidence Syndromic Combination Antibiogram (WISCA)

    Case example: Susceptibility of Pseudomonas aeruginosa to TZP among respiratory specimens (obtained among ICU patients only) for male patients age >=65 years with heart failure

    Code example:

    antibiogram(your_data,
                antibiotics = c("TZP", "TZP+TOB", "TZP+GEN"),
                syndromic_group = ifelse(your_data$age >= 65 & your_data$gender == "Male",
                                         "Group 1", "Group 2"))

All types of antibiograms can be generated with the functions as described on this page, and can be plotted (using ggplot2::autoplot() or base R plot()/barplot()) or printed into R Markdown / Quarto formats for reports. Use functions from specific 'table reporting' packages to transform the output of antibiogram() to your needs, e.g. flextable::as_flextable() or gt::gt().

Note that for combination antibiograms, it is important to realise that susceptibility can be calculated in two ways, which can be set with the only_all_tested argument (defaults to FALSE). See this example for two antibiotics, Drug A and Drug B, about how antibiogram() works to calculate the %SI:

--------------------------------------------------------------------
                    only_all_tested = FALSE  only_all_tested = TRUE
                    -----------------------  -----------------------
 Drug A    Drug B   include as  include as   include as  include as
                    numerator   denominator  numerator   denominator
--------  --------  ----------  -----------  ----------  -----------
 S or I    S or I       X            X            X            X
   R       S or I       X            X            X            X
  <NA>     S or I       X            X            -            -
 S or I      R          X            X            X            X
   R         R          -            X            -            X
  <NA>       R          -            -            -            -
 S or I     <NA>        X            X            -            -
   R        <NA>        -            -            -            -
  <NA>      <NA>        -            -            -            -
--------------------------------------------------------------------

Printing the antibiogram in non-interactive sessions will be done by knitr::kable(), with support for all their implemented formats, such as "markdown". The knitr format will be automatically determined if printed inside a knitr document (LaTeX, HTML, etc.).

Examples

# example_isolates is a data set available in the AMR package.
# run ?example_isolates for more info.
example_isolates
#> # A tibble: 2,000 × 46
#>    date       patient   age gender ward     mo           PEN   OXA   FLC   AMX  
#>    <date>     <chr>   <dbl> <chr>  <chr>    <mo>         <sir> <sir> <sir> <sir>
#>  1 2002-01-02 A77334     65 F      Clinical B_ESCHR_COLI R     NA    NA    NA   
#>  2 2002-01-03 A77334     65 F      Clinical B_ESCHR_COLI R     NA    NA    NA   
#>  3 2002-01-07 067927     45 F      ICU      B_STPHY_EPDR R     NA    R     NA   
#>  4 2002-01-07 067927     45 F      ICU      B_STPHY_EPDR R     NA    R     NA   
#>  5 2002-01-13 067927     45 F      ICU      B_STPHY_EPDR R     NA    R     NA   
#>  6 2002-01-13 067927     45 F      ICU      B_STPHY_EPDR R     NA    R     NA   
#>  7 2002-01-14 462729     78 M      Clinical B_STPHY_AURS R     NA    S     R    
#>  8 2002-01-14 462729     78 M      Clinical B_STPHY_AURS R     NA    S     R    
#>  9 2002-01-16 067927     45 F      ICU      B_STPHY_EPDR R     NA    R     NA   
#> 10 2002-01-17 858515     79 F      ICU      B_STPHY_EPDR R     NA    S     NA   
#> # … with 1,990 more rows, and 36 more variables: AMC <sir>, AMP <sir>,
#> #   TZP <sir>, CZO <sir>, FEP <sir>, CXM <sir>, FOX <sir>, CTX <sir>,
#> #   CAZ <sir>, CRO <sir>, GEN <sir>, TOB <sir>, AMK <sir>, KAN <sir>,
#> #   TMP <sir>, SXT <sir>, NIT <sir>, FOS <sir>, LNZ <sir>, CIP <sir>,
#> #   MFX <sir>, VAN <sir>, TEC <sir>, TCY <sir>, TGC <sir>, DOX <sir>,
#> #   ERY <sir>, CLI <sir>, AZM <sir>, IPM <sir>, MEM <sir>, MTR <sir>,
#> #   CHL <sir>, COL <sir>, MUP <sir>, RIF <sir>


# Traditional antibiogram ----------------------------------------------

antibiogram(example_isolates,
            antibiotics = c(aminoglycosides(), carbapenems()))
#> ℹ For aminoglycosides() using columns 'GEN' (gentamicin), 'TOB'
#>   (tobramycin), 'AMK' (amikacin) and 'KAN' (kanamycin)
#> ℹ For carbapenems() using columns 'IPM' (imipenem) and 'MEM' (meropenem)
#> ℹ 502 combinations had less than minimum = 30 results and were ignored
#> # A tibble: 10 × 7
#>    `Pathogen (N min-max)`     S    S1    S2    S3    S4    S5
#>  * <chr>                  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#>  1 CoNS (43-309)             86    22     0     0    52    52
#>  2 E. coli (0-462)           98    97   100    NA   100   100
#>  3 E. faecalis (0-39)         0     0     0     0   100    NA
#>  4 K. pneumoniae (0-58)      90    90    NA    NA   100   100
#>  5 P. aeruginosa (17-30)    100   100    NA     0    NA    NA
#>  6 P. mirabilis (0-34)       94    94    NA    NA    94    NA
#>  7 S. aureus (2-233)         99    98    NA    NA    NA    NA
#>  8 S. epidermidis (8-163)    79    51     0     0    NA    NA
#>  9 S. hominis (3-80)         92    85    NA    NA    NA    NA
#> 10 S. pneumoniae (11-117)     0     0     0     0    NA    NA
            
antibiogram(example_isolates,
            antibiotics = aminoglycosides(),
            ab_transform = "atc",
            mo_transform = "gramstain")
#> ℹ For aminoglycosides() using columns 'GEN' (gentamicin), 'TOB'
#>   (tobramycin), 'AMK' (amikacin) and 'KAN' (kanamycin)
#> ℹ 4 combinations had less than minimum = 30 results and were ignored
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S1".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S2".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S3".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S1".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S2".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S3".
#> Warning: there are records with missing times, which will be dropped.
#> Warning: multiple rows match for ab=NA: first taken
#> # A tibble: 2 × 2
#>   `Pathogen (N min-max)`    `NA`
#> * <chr>                    <dbl>
#> 1 Gram-negative (35-686)      96
#> 2 Gram-positive (436-1170)    63
            
antibiogram(example_isolates,
            antibiotics = carbapenems(),
            ab_transform = "name",
            mo_transform = "name")
#> ℹ For carbapenems() using columns 'IPM' (imipenem) and 'MEM' (meropenem)
#> ℹ 172 combinations had less than minimum = 30 results and were ignored
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S1".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S1".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S1".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: there are records with missing times, which will be dropped.
#> Warning: multiple rows match for ab=NA: first taken
#> # A tibble: 5 × 2
#>   `Pathogen (N min-max)`                            `NA`
#> * <chr>                                            <dbl>
#> 1 Coagulase-negative Staphylococcus (CoNS) (48-48)    52
#> 2 Enterococcus faecalis (0-38)                       100
#> 3 Escherichia coli (418-422)                         100
#> 4 Klebsiella pneumoniae (51-53)                      100
#> 5 Proteus mirabilis (27-32)                           94


# Combined antibiogram -------------------------------------------------

# combined antibiotics yield higher empiric coverage
antibiogram(example_isolates,
            antibiotics = c("TZP", "TZP+TOB", "TZP+GEN"),
            mo_transform = "gramstain")
#> ℹ 3 combinations had less than minimum = 30 results and were ignored
#> # A tibble: 2 × 4
#>   `Pathogen (N min-max)`       S    S1    S2
#> * <chr>                    <dbl> <dbl> <dbl>
#> 1 Gram-negative (641-693)     88    98    99
#> 2 Gram-positive (345-1044)    86    95    98
            
antibiogram(example_isolates,
            antibiotics = c("TZP", "TZP+TOB"),
            mo_transform = "gramstain",
            ab_transform = "name",
            sep = " & ")
#> ℹ 2 combinations had less than minimum = 30 results and were ignored
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S1".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S1".
#> Warning: there are records with missing times, which will be dropped.
#> Warning: multiple rows match for ab=NA: first taken
#> # A tibble: 2 × 2
#>   `Pathogen (N min-max)`   `NA`
#> * <chr>                   <dbl>
#> 1 Gram-negative (641-693)    88
#> 2 Gram-positive (345-550)    86


# Syndromic antibiogram ------------------------------------------------

# the data set could contain a filter for e.g. respiratory specimens
antibiogram(example_isolates,
            antibiotics = c(aminoglycosides(), carbapenems()),
            syndromic_group = "ward")
#> ℹ For aminoglycosides() using columns 'GEN' (gentamicin), 'TOB'
#>   (tobramycin), 'AMK' (amikacin) and 'KAN' (kanamycin)
#> ℹ For carbapenems() using columns 'IPM' (imipenem) and 'MEM' (meropenem)
#> ℹ 1581 combinations had less than minimum = 30 results and were ignored
#> # A tibble: 14 × 8
#>    `Syndromic Group` `Pathogen (N min-max)`     S    S1    S2    S3    S4    S5
#>  * <chr>             <chr>                  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#>  1 Clinical          CoNS (23-205)             89    26    NA    NA    57    57
#>  2 ICU               CoNS (10-73)              79    NA    NA    NA    NA    NA
#>  3 Outpatient        CoNS (3-31)               84    NA    NA    NA    NA    NA
#>  4 Clinical          E. coli (0-299)           98    98   100    NA   100   100
#>  5 ICU               E. coli (0-137)           99    96   100    NA   100   100
#>  6 Clinical          K. pneumoniae (0-51)      92    92    NA    NA   100   100
#>  7 Clinical          P. mirabilis (0-30)      100   100    NA    NA    NA    NA
#>  8 Clinical          S. aureus (2-150)         99    97    NA    NA    NA    NA
#>  9 ICU               S. aureus (0-66)         100    NA    NA    NA    NA    NA
#> 10 Clinical          S. epidermidis (4-79)     82    55    NA    NA    NA    NA
#> 11 ICU               S. epidermidis (4-75)     72    41    NA    NA    NA    NA
#> 12 Clinical          S. hominis (1-45)         96    94    NA    NA    NA    NA
#> 13 Clinical          S. pneumoniae (5-78)       0     0     0     0    NA    NA
#> 14 ICU               S. pneumoniae (5-30)       0     0     0     0    NA    NA

# now define a data set with only E. coli
ex1 <- example_isolates[which(mo_genus() == "Escherichia"), ]
#> ℹ Using column 'mo' as input for mo_genus()

# with a custom language, though this will be determined automatically
# (i.e., this table will be in Spanish on Spanish systems)
antibiogram(ex1,
            antibiotics = aminoglycosides(),
            ab_transform = "name",
            syndromic_group = ifelse(ex1$ward == "ICU",
                                     "UCI", "No UCI"),
            language = "es")
#> ℹ For aminoglycosides() using columns 'GEN' (gentamicin), 'TOB'
#>   (tobramycin), 'AMK' (amikacin) and 'KAN' (kanamycin)
#> ℹ 2 combinations had less than minimum = 30 results and were ignored
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S1".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S2".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S1".
#> Warning: in as.ab(): these values could not be coerced to a valid antimicrobial
#> ID: "S2".
#> Warning: there are records with missing times, which will be dropped.
#> Warning: multiple rows match for ab=NA: first taken
#> Warning: there are records with missing times, which will be dropped.
#> Warning: multiple rows match for ab=NA: first taken
#> # A tibble: 2 × 3
#>   `Grupo sindrómico` `Patógeno (N min-max)`  `NA`
#> * <chr>              <chr>                  <dbl>
#> 1 No UCI             E. coli (0-325)           98
#> 2 UCI                E. coli (0-137)           99


# Weighted-incidence syndromic combination antibiogram (WISCA) ---------

# the data set could contain a filter for e.g. respiratory specimens
antibiogram(example_isolates,
            antibiotics = c("AMC", "AMC+CIP", "TZP", "TZP+TOB"),
            mo_transform = "gramstain",
            minimum = 10, # this should be >= 30, but now just as example
            syndromic_group = ifelse(example_isolates$age >= 65 &
                                       example_isolates$gender == "M",
                                     "WISCA Group 1", "WISCA Group 2"))
#> ℹ 8 combinations had less than minimum = 10 results and were ignored
#> # A tibble: 4 × 6
#>   `Syndromic Group` `Pathogen (N min-max)`      S    S1    S2    S3
#> * <chr>             <chr>                   <dbl> <dbl> <dbl> <dbl>
#> 1 WISCA Group 1     Gram-negative (261-285)    76    95    89    99
#> 2 WISCA Group 2     Gram-negative (380-442)    76    98    88    98
#> 3 WISCA Group 1     Gram-positive (123-406)    76    89    81    95
#> 4 WISCA Group 2     Gram-positive (222-732)    76    89    88    95


# Generate plots with ggplot2 or base R --------------------------------

ab1 <- antibiogram(example_isolates,
                   antibiotics = c("AMC", "CIP", "TZP", "TZP+TOB"),
                   mo_transform = "gramstain")
#> ℹ 4 combinations had less than minimum = 30 results and were ignored
ab2 <- antibiogram(example_isolates,
                   antibiotics = c("AMC", "CIP", "TZP", "TZP+TOB"),
                   mo_transform = "gramstain",
                   syndromic_group = "ward")
#> ℹ 16 combinations had less than minimum = 30 results and were ignored
                   
plot(ab1)


if (requireNamespace("ggplot2")) {
  ggplot2::autoplot(ab1)
}


plot(ab2)


if (requireNamespace("ggplot2")) {
  ggplot2::autoplot(ab2)
}