# brendaDb

Yi Zhou1*

1Institute of Bioinformatics, University of Georgia

*Yi.Zhou@uga.edu

#### 2020-02-27

# 1 Overview

brendaDb aims to make importing and analyzing data from the BRENDA database easier. The main functions include:

- Read text file downloaded from BRENDA into an R `tibble`
- Retrieve information for specific enzymes
- Query enzymes using their synonyms, gene symbols, etc.
- Query enzyme information for specific BioCyc pathways

For bug reports or feature requests, please go to the GitHub repository.

# 2 Installation

brendaDb is a Bioconductor package and can be installed through `BiocManager::install()`.

    if (!requireNamespace("BiocManager", quietly = TRUE))
        install.packages("BiocManager")
    BiocManager::install("brendaDb", dependencies=TRUE)

Alternatively, install the development version from GitHub.

    if(!requireNamespace("brendaDb")) {
      devtools::install_github("y1zhou/brendaDb")
    }

After the package is installed, it can be loaded into the R workspace by

    library(brendaDb)

# 3 Getting Started

## 3.1 Downloading the BRENDA Text File

Download the BRENDA database as a text file here. Alternatively, download the file in R (file updated 2019-04-24):

    brenda.filepath <- DownloadBrenda()
    #> Please read the license agreement in the link below.
    #>
    #> https://www.brenda-enzymes.org/download_brenda_without_registration.php
    #>
    #> Found zip file in cache.
    #> Extracting zip file...

The function downloads the file to a local cache directory. Now the text file can be loaded into R as a `tibble`:

    df <- ReadBrenda(brenda.filepath)
    #> Reading BRENDA text file...
    #> Converting text into a list. This might take a while...
    #> Converting list to tibble and removing duplicated entries...
    #> If you're going to use this data again, consider saving this table using data.table::fwrite().

As suggested in the function output, you may save the `df` object to a text file using `data.table::fwrite()` or to an R object using `save(df)`, and load the table using `data.table::fread()` or `load()`1. Both methods should be much faster than reading the raw text file again using `ReadBrenda()`.

# 4 Making Queries

Since BRENDA is a database for enzymes, all final queries are based on EC numbers.

## 4.1 Query for Multiple Enzymes

If you already have a list of EC numbers in mind, you may call `QueryBrenda` directly:

    brenda_txt <- system.file("extdata", "brenda_download_test.txt",
                              package = "brendaDb")
    df <- ReadBrenda(brenda_txt)
    #> Reading BRENDA text file...
    #> Converting text into a list. This might take a while...
    #> Converting list to tibble and removing duplicated entries...
    #> If you're going to use this data again, consider saving this table using data.table::fwrite().
    res <- QueryBrenda(df, EC = c("1.1.1.1", "6.3.5.8"), n.core = 2)
    #> 6.3.5.8 was transferred or deleted.

    res
    #> A list of 2 brenda.entry object(s) with:
    #>  - 1 regular brenda.entry object(s)
    #>    1.1.1.1
    #> - 1 transferred or deleted object(s)
    #>    6.3.5.8

    res[["1.1.1.1"]]
    #> Entry 1.1.1.1
    #> +-- nomenclature
    #> |    +-- ec: 1.1.1.1
    #> |    +-- systematic.name: alcohol:NAD+ oxidoreductase
    #> |    +-- recommended.name: alcohol dehydrogenase
    #> |    +-- synonyms: A tibble with 128 rows
    #> |    +-- reaction: A tibble with 2 rows
    #> |    +-- reaction.type: A tibble with 3 rows
    #> +-- interactions
    #> |    +-- substrate.product: A tibble with 772 rows
    #> |    +-- natural.substrate.product: A tibble with 20 rows
    #> |    +-- cofactor: A tibble with 7 rows
    #> |    +-- metals.ions: A tibble with 20 rows
    #> |    +-- inhibitors: A tibble with 207 rows
    #> |    +-- activating.compound: A tibble with 22 rows
    #> +-- parameters
    #> |    +-- km.value: A tibble with 878 rows
    #> |    +-- turnover.number: A tibble with 495 rows
    #> |    +-- ki.value: A tibble with 34 rows
    #> |    +-- pi.value: A tibble with 11 rows
    #> |    +-- ph.optimum: A tibble with 55 rows
    #> |    +-- ph.range: A tibble with 28 rows
    #> |    +-- temperature.optimum: A tibble with 29 rows
    #> |    +-- temperature.range: A tibble with 20 rows
    #> |    +-- specific.activity: A tibble with 88 rows
    #> |    +-- ic50: A tibble with 2 rows
    #> +-- organism
    #> |    +-- organism: A tibble with 159 rows
    #> |    +-- source.tissue: A tibble with 63 rows
    #> |    +-- localization: A tibble with 9 rows
    #> +-- molecular
    #> |    +-- stability
    #> |    |    +-- general.stability: A tibble with 15 rows
    #> |    |    +-- storage.stability: A tibble with 15 rows
    #> |    |    +-- ph.stability: A tibble with 20 rows
    #> |    |    +-- organic.solvent.stability: A tibble with 25 rows
    #> |    |    +-- oxidation.stability: A tibble with 3 rows
    #> |    |    +-- temperature.stability: A tibble with 36 rows
    #> |    +-- purification: A tibble with 48 rows
    #> |    +-- cloned: A tibble with 46 rows
    #> |    +-- engineering: A tibble with 60 rows
    #> |    +-- renatured: A tibble with 1 rows
    #> |    +-- application: A tibble with 5 rows
    #> +-- structure
    #> |    +-- molecular.weight: A tibble with 119 rows
    #> |    +-- subunits: A tibble with 11 rows
    #> |    +-- posttranslational.modification: A tibble with 2 rows
    #> |    +-- crystallization: A tibble with 22 rows
    #> +-- bibliography
    #> |    +-- reference: A tibble with 285 rows

## 4.2 Query Specific Fields

You can also query for certain fields to reduce the size of the returned object.

    ShowFields(df)
    #> # A tibble: 40 x 2
    #>    field                     acronym
    #>    <chr>                     <chr>
    #>  1 PROTEIN                   PR
    #>  2 RECOMMENDED_NAME          RN
    #>  3 SYSTEMATIC_NAME           SN
    #>  4 SYNONYMS                  SY
    #>  5 REACTION                  RE
    #>  6 REACTION_TYPE             RT
    #>  7 SOURCE_TISSUE             ST
    #>  8 LOCALIZATION              LO
    #>  9 NATURAL_SUBSTRATE_PRODUCT NSP
    #> 10 SUBSTRATE_PRODUCT         SP
    #> # ... with 30 more rows

    res <- QueryBrenda(df, EC = "1.1.1.1", fields = c("PROTEIN", "SUBSTRATE_PRODUCT"))
    res[["1.1.1.1"]][["interactions"]][["substrate.product"]]
    #> # A tibble: 772 x 7
    #>    proteinID substrate product commentarySubst~ commentaryProdu~ reversibility
    #>    <chr>     <chr>     <chr>   <chr>            <chr>            <chr>
    #>  1 10        n-propan~ n-prop~ <NA>             <NA>             r
    #>  2 10        2-propan~ aceton~ <NA>             <NA>             <NA>
    #>  3 10        n-hexano~ n-hexa~ <NA>             <NA>             r
    #>  4 10        (S)-2-bu~ 2-buta~ <NA>             <NA>             r
    #>  5 10        ethyleng~ ? + NA~ <NA>             <NA>             r
    #>  6 10        n-butano~ butyra~ <NA>             <NA>             <NA>
    #>  7 10        n-decano~ n-deca~ <NA>             <NA>             r
    #>  8 10        Tris + N~ ? + NA~ <NA>             <NA>             r
    #>  9 10        isopropa~ aceton~ <NA>             <NA>             <NA>
    #> 10 10        5-hydrox~ (furan~ #10# mutant enz~ <NA>             <NA>
    #> # ... with 762 more rows, and 1 more variable: refID <chr>

It should be noted that most fields contain a `fieldInfo` column and a `commentary` column. The `fieldInfo` column is what’s extracted by BRENDA from the literature, and the `commentary` column is usually some context from the original paper. `#` symbols in the commentary correspond to the `proteinID`s, and `<>` enclose the corresponding `refID`s. For further information, please see the README file from BRENDA.

## 4.3 Query Specific Organisms

Note the difference in row numbers in the following example and in the one where we queried for all organisms.

    res <- QueryBrenda(df, EC = "1.1.1.1", organisms = "Homo sapiens")
    res$`1.1.1.1`
    #> Entry 1.1.1.1
    #> +-- nomenclature
    #> |    +-- ec: 1.1.1.1
    #> |    +-- systematic.name: alcohol:NAD+ oxidoreductase
    #> |    +-- recommended.name: alcohol dehydrogenase
    #> |    +-- synonyms: A tibble with 41 rows
    #> |    +-- reaction: A tibble with 2 rows
    #> |    +-- reaction.type: A tibble with 3 rows
    #> +-- interactions
    #> |    +-- substrate.product: A tibble with 102 rows
    #> |    +-- natural.substrate.product: A tibble with 9 rows
    #> |    +-- cofactor: A tibble with 2 rows
    #> |    +-- metals.ions: A tibble with 2 rows
    #> |    +-- inhibitors: A tibble with 36 rows
    #> +-- parameters
    #> |    +-- km.value: A tibble with 163 rows
    #> |    +-- turnover.number: A tibble with 64 rows
    #> |    +-- ki.value: A tibble with 8 rows
    #> |    +-- ph.optimum: A tibble with 15 rows
    #> |    +-- ph.range: A tibble with 2 rows
    #> |    +-- temperature.optimum: A tibble with 2 rows
    #> |    +-- specific.activity: A tibble with 5 rows
    #> +-- organism
    #> |    +-- organism: A tibble with 3 rows
    #> |    +-- source.tissue: A tibble with 21 rows
    #> |    +-- localization: A tibble with 1 rows
    #> +-- molecular
    #> |    +-- stability
    #> |    |    +-- general.stability: A tibble with 1 rows
    #> |    |    +-- storage.stability: A tibble with 4 rows
    #> |    |    +-- ph.stability: A tibble with 1 rows
    #> |    |    +-- organic.solvent.stability: A tibble with 1 rows
    #> |    |    +-- temperature.stability: A tibble with 2 rows
    #> |    +-- purification: A tibble with 7 rows
    #> |    +-- cloned: A tibble with 5 rows
    #> |    +-- engineering: A tibble with 3 rows
    #> |    +-- application: A tibble with 1 rows
    #> +-- structure
    #> |    +-- molecular.weight: A tibble with 12 rows
    #> |    +-- subunits: A tibble with 3 rows
    #> |    +-- crystallization: A tibble with 2 rows
    #> +-- bibliography
    #> |    +-- reference: A tibble with 285 rows

## 4.4 Extract Information in Query Results

To transform the `brenda.entries` structure into a table, use the helper function `ExtractField()`.

    res <- QueryBrenda(df, EC = c("1.1.1.1", "6.3.5.8"), n.core = 2)
    #> 6.3.5.8 was transferred or deleted.
    ExtractField(res, field = "parameters$ph.optimum")
    #> Deprecated entries in the res object will be removed.
    #> # A tibble: 158 x 9
    #>    ec    organism proteinID uniprot org.commentary description fieldInfo
    #>    <chr> <chr>    <chr>     <chr>   <chr>          <chr>       <lgl>
    #>  1 1.1.~ Acetoba~ 60        <NA>    <NA>           5.5         NA
    #>  2 1.1.~ Acetoba~ 60        <NA>    <NA>           6           NA
    #>  3 1.1.~ Acetoba~ 60        <NA>    <NA>           8.5         NA
    #>  4 1.1.~ Acineto~ 28        <NA>    <NA>           5.9         NA
    #>  5 1.1.~ Aeropyr~ 131       Q9Y9P9  <NA>           10.5        NA
    #>  6 1.1.~ Aeropyr~ 131       Q9Y9P9  <NA>           8           NA
    #>  7 1.1.~ Arabido~ 20        <NA>    <NA>           10.5        NA
    #>  8 1.1.~ Aspergi~ 14        <NA>    <NA>           8.1         NA
    #>  9 1.1.~ Breviba~ 46        <NA>    <NA>           10.4        NA
    #> 10 1.1.~ Breviba~ 46        <NA>    <NA>           6           NA
    #> # ... with 148 more rows, and 2 more variables: commentary <chr>, refID <chr>

As shown above, the returned table consists of three parts: the EC number, organism-related information (organism, protein ID, uniprot ID, and commentary on the organism), and extracted field information (description, commentary, etc.).

# 5 Foreign ID Retrieval

## 5.1 Querying Synonyms

A lot of the times we have a list of gene symbols or enzyme names instead of EC numbers. In this case, a helper function can be used to find the corresponding EC numbers:

    ID2Enzyme(brenda = df, ids = c("ADH4", "CD38", "pyruvate dehydrogenase"))
    #> # A tibble: 4 x 5
    #>   ID       EC     RECOMMENDED_NAME      SYNONYMS          SYSTEMATIC_NAME
    #>   <chr>    <chr>  <chr>                 <chr>             <chr>
    #> 1 ADH4     1.1.1~ <NA>                  "aldehyde reduct~ <NA>
    #> 2 CD38     2.4.9~ <NA>                  "#1,3,4,6# CD38 ~ <NA>
    #> 3 pyruvat~ 1.2.1~ pyruvate dehydrogena~ "#1,2# pyruvate:~ <NA>
    #> 4 pyruvat~ 2.7.1~ [pyruvate dehydrogen~ "kinase (phospho~ ATP:[pyruvate dehydro~

The `EC` column can be then handpicked and used in `QueryBrenda()`.

## 5.2 BioCyc Pathways

Often we are interested in the enzymes involved in a specific BioCyc pathway. Functions `BioCycPathwayEnzymes()` and `BiocycPathwayGenes()` can be used in this case:

    BiocycPathwayEnzymes(org.id = "HUMAN", pathway = "PWY66-400")
    #> Found 10 reactions for HUMAN pathway PWY66-400.
    #> # A tibble: 11 x 5
    #>    RxnID          EC      ReactionDirection  LHS            RHS
    #>    <chr>          <chr>   <chr>              <chr>          <chr>
    #>  1 PGLUCISOM-RXN  5.3.1.9 REVERSIBLE         D-glucopyrano~ FRUCTOSE-6P
    #>  2 GLUCOKIN-RXN   2.7.1.1 LEFT-TO-RIGHT      Glucopyranose~ D-glucopyranose-6-p~
    #>  3 GLUCOKIN-RXN   2.7.1.2 LEFT-TO-RIGHT      Glucopyranose~ D-glucopyranose-6-p~
    #>  4 PEPDEPHOS-RXN  2.7.1.~ PHYSIOL-RIGHT-TO-~ PYRUVATE + ATP PROTON + PHOSPHO-EN~
    #>  5 2PGADEHYDRAT-~ 4.2.1.~ REVERSIBLE         2-PG           PHOSPHO-ENOL-PYRUVA~
    #>  6 RXN-15513      5.4.2.~ REVERSIBLE         2-PG           G3P
    #>  7 PHOSGLYPHOS-R~ 2.7.2.3 REVERSIBLE         G3P + ATP      DPG + ADP
    #>  8 GAPOXNPHOSPHN~ 1.2.1.~ REVERSIBLE         GAP + Pi + NAD PROTON + DPG + NADH
    #>  9 TRIOSEPISOMER~ 5.3.1.1 REVERSIBLE         GAP            DIHYDROXY-ACETONE-P~
    #> 10 F16ALDOLASE-R~ 4.1.2.~ REVERSIBLE         FRUCTOSE-16-D~ DIHYDROXY-ACETONE-P~
    #> 11 6PFRUCTPHOS-R~ 2.7.1.~ LEFT-TO-RIGHT      ATP + FRUCTOS~ PROTON + ADP + FRUC~

    BiocycPathwayGenes(org.id = "HUMAN", pathway = "TRYPTOPHAN-DEGRADATION-1")
    #> Found 16 genes in HUMAN pathway TRYPTOPHAN-DEGRADATION-1.
    #> # A tibble: 16 x 4
    #>    BiocycGene BiocycProtein         Symbol  Ensembl
    #>    <chr>      <chr>                 <chr>   <chr>
    #>  1 HS14455    HS14455-MONOMER       ACMSD   ENSG00000153086
    #>  2 HS04229    ENSG00000118514-MONO~ ALDH8A1 ENSG00000118514
    #>  3 HS11585    HS11585-MONOMER       DHTKD1  ENSG00000181192
    #>  4 G66-33844  G66-33844-MONOMER     AFMID   ENSG00000183077,ENST00000409257,ENS~
    #>  5 HS04082    HS04082-MONOMER       KMO     ENSG00000117009
    #>  6 HS03952    HS03952-MONOMER       KYNU    ENSG00000115919
    #>  7 HS08749    HS08749-MONOMER       HAAO    ENSG00000162882
    #>  8 HS05502    HS05502-MONOMER       IDO1    ENSG00000131203
    #>  9 G66-37884  MONOMER66-34407       IDO2    ENSG00000188676
    #> 10 HS07771    HS07771-MONOMER       TDO2    ENSG00000151790
    #> 11 HS02769    HS02769-MONOMER       GCDH    ENSG00000105607
    #> 12 HS01167    HS01167-MONOMER       ACAT1   ENSG00000075239
    #> 13 HS04399    ENSG00000120437-MONO~ ACAT2   ENSG00000120437
    #> 14 HS01071    HS01071-MONOMER       HSD17B~ ENSG00000072506
    #> 15 HS06563    HS06563-MONOMER       HADH    ENSG00000138796
    #> 16 HS05132    HS05132-MONOMER       ECHS1   ENSG00000127884

Similarly, the EC numbers returned from `BiocycPathwayEnzymes` can be used in the function `QueryBrenda`, and the gene IDs2 can be used to find corresponding EC numbers with other packages such as biomaRt and clusterProfiler.

# Additional Information

By default `QueryBrenda` uses all available cores, but often limiting `n.core` could give better performance as it reduces the overhead. The following are results produced on a machine with 40 cores (2 Intel Xeon CPU E5-2640 v4 @ 3.4GHz), and 256G of RAM:

    EC.numbers <- head(unique(df$ID), 100)
    system.time(QueryBrenda(df, EC = EC.numbers, n.core = 0))  # default
    #  user  system elapsed
    # 4.528   7.856  34.567
    system.time(QueryBrenda(df, EC = EC.numbers, n.core = 1))
    #  user  system elapsed
    # 22.080   0.360  22.438
    system.time(QueryBrenda(df, EC = EC.numbers, n.core = 2))
    #  user  system elapsed
    # 0.552   0.400  13.597
    system.time(QueryBrenda(df, EC = EC.numbers, n.core = 4))
    #  user  system elapsed
    # 0.688   0.832   9.517
    system.time(QueryBrenda(df, EC = EC.numbers, n.core = 8))
    #  user  system elapsed
    # 1.112   1.476  10.000

    sessionInfo()
    #> R Under development (unstable) (2020-01-27 r77730)
    #> Platform: x86_64-w64-mingw32/x64 (64-bit)
    #> Running under: Windows Server 2012 R2 x64 (build 9600)
    #>
    #> Matrix products: default
    #>
    #> locale:
    #> [1] LC_COLLATE=C
    #> [2] LC_CTYPE=English_United States.1252
    #> [3] LC_MONETARY=English_United States.1252
    #> [4] LC_NUMERIC=C
    #> [5] LC_TIME=English_United States.1252
    #>
    #> attached base packages:
    #> [1] stats     graphics  grDevices utils     datasets  methods   base
    #>
    #> other attached packages:
    #> [1] brendaDb_1.1.3   BiocStyle_2.15.6
    #>
    #> loaded via a namespace (and not attached):
    #>  [1] Rcpp_1.0.3           compiler_4.0.0       pillar_1.4.3
    #>  [4] BiocManager_1.30.10  dbplyr_1.4.2         tools_4.0.0
    #>  [7] digest_0.6.25        bit_1.1-15.2         lifecycle_0.1.0
    #> [10] BiocFileCache_1.11.4 RSQLite_2.2.0        evaluate_0.14
    #> [13] memoise_1.1.0        tibble_2.1.3         pkgconfig_2.0.3
    #> [16] rlang_0.4.4          cli_2.0.1            DBI_1.1.0
    #> [19] curl_4.3             yaml_2.2.1           parallel_4.0.0
    #> [22] xfun_0.12            xml2_1.2.2           dplyr_0.8.4
    #> [25] stringr_1.4.0        httr_1.4.1           knitr_1.28
    #> [28] vctrs_0.2.3          rappdirs_0.3.1       bit64_0.9-7
    #> [31] tidyselect_1.0.0     glue_1.3.1           R6_2.4.1
    #> [34] snow_0.4-3           fansi_0.4.1          BiocParallel_1.21.2
    #> [37] rmarkdown_2.1        bookdown_0.17        tidyr_1.0.2
    #> [40] purrr_0.3.3          blob_1.2.1           magrittr_1.5
    #> [43] htmltools_0.4.0      assertthat_0.2.1     utf8_1.1.4
    #> [46] stringi_1.4.6        crayon_1.3.4