biobouncer validates biological identifiers and inputs. It answers one question, “is this a valid identifier?”, with the same verdict in R and Python. This vignette walks through the sources, the checking modes, and the validation adapters using only offline data, so every chunk here runs without a network.
sources() lists the source databases biobouncer knows
about, and source_info() returns a table with a short
description of each.
sources()
#> [1] "bto" "cdd" "chebi" "chembl"
#> [5] "cl" "clinvar" "complexportal" "cosmic"
#> [9] "dbsnp" "doid" "drugbank" "ec"
#> [13] "eco" "efo" "ensembl" "go"
#> [17] "hgnc" "hgvs" "hp" "inchikey"
#> [21] "interpro" "mirbase" "mirbase_hairpin" "mondo"
#> [25] "mp" "ncbifam" "ncbitaxon" "ncit"
#> [29] "opentargets" "orphanet" "panther" "pato"
#> [33] "pdb" "pfam" "pharmgkb" "prints"
#> [37] "prosite" "reactome" "refseq" "rfam"
#> [41] "smart" "so" "uberon" "uniparc"
#> [45] "uniprot" "wikipathways"pattern mode is offline and deterministic. It checks the
shape of an identifier against the source’s pattern. It does not check
that the identifier exists.
check_id() returns a tibble with one row per input. Note
that it preserves the order and length of the input, and never collapses
an invalid value into a bare FALSE: the row tells you
why.
check_id(
c("MONDO:0005148", "mondo:5148", "GO:0006915"),
source_db = "mondo"
)
#> # A tibble: 3 × 9
#> input valid normalized suggestion source_db version species how error
#> <chr> <lgl> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 MONDO:00051… TRUE MONDO:000… <NA> mondo <NA> <NA> patt… <NA>
#> 2 mondo:5148 FALSE <NA> MONDO:000… mondo <NA> <NA> patt… <NA>
#> 3 GO:0006915 FALSE <NA> <NA> mondo <NA> <NA> patt… <NA>The normalized column holds the canonical form of a
valid input. The suggestion column holds a best-effort
correction for an invalid but mappable input, such as the lowercase
prefix above.
For just the verdict, use is_valid_id(), which returns a
logical vector.
cache mode checks existence against a pinned, offline
snapshot. A small sample snapshot ships with the package,
so the examples below need no downloads. A real analysis pins a dated
snapshot instead.
check_id(
c("MONDO:0005148", "MONDO:9999999"),
source_db = "mondo",
how = "cache",
version = "sample"
)
#> # A tibble: 2 × 9
#> input valid normalized suggestion source_db version species how error
#> <chr> <lgl> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 MONDO:00051… TRUE MONDO:000… <NA> mondo sample <NA> cache <NA>
#> 2 MONDO:99999… FALSE <NA> <NA> mondo sample <NA> cache <NA>MONDO:9999999 is well-formed, so it passes
pattern mode, but it is not in the snapshot, so it fails
cache mode. Choosing the mode is choosing how strict you
want the check to be.
Snapshots are managed with a few helpers:
biobouncer_snapshots()
#> # A tibble: 14 × 4
#> source version n_ids location
#> <chr> <chr> <int> <chr>
#> 1 bto sample 7 bundled
#> 2 chebi sample 5 bundled
#> 3 cl sample 7 bundled
#> 4 doid sample 7 bundled
#> 5 efo sample 5 bundled
#> 6 go sample 6 bundled
#> 7 hgnc 2026-07-07 45019 bundled
#> 8 hgnc sample 7 bundled
#> 9 hp sample 7 bundled
#> 10 mondo sample 6 bundled
#> 11 mp sample 7 bundled
#> 12 pato sample 7 bundled
#> 13 so sample 7 bundled
#> 14 uberon sample 7 bundledremote mode checks existence live against a source API.
It needs a network, so it is not run in this vignette, but the call
looks like this:
# Live check against the Ensembl REST API.
check_id("ENSG00000139618", source_db = "ensembl", how = "remote")
# existence mode uses a snapshot when one is available and otherwise
# falls back to remote.
check_id("MONDO:0005148", source_db = "mondo", how = "existence")A network failure in remote mode raises an error. It
never returns a silent FALSE, so a failed lookup cannot be
mistaken for an absent identifier.
Some sources are species-aware. For Ensembl, the species is encoded
in the id, so pattern mode can reject a well-formed id that
belongs to the wrong species.
# ENSMUSG is a mouse gene id.
is_valid_id("ENSMUSG00000059552", source_db = "ensembl", species = "mus_musculus")
#> [1] TRUE
is_valid_id("ENSMUSG00000059552", source_db = "ensembl", species = "homo_sapiens")
#> [1] FALSEspecies accepts a name such as
"homo_sapiens" or an NCBI taxon id such as
9606. A source that is not species-aware ignores the
argument.
The hgvs source checks the syntax of an HGVS sequence
variant name. This is a grammar check in pattern mode. It
confirms the shape of the variant. It does not check coordinates or that
the variant exists.
is_valid_id(
c(
"NM_004006.2:c.4375C>T",
"NP_003997.1:p.(Gly56Ala)",
"NM_004006.2:c.76insG"
),
source_db = "hgvs"
)
#> [1] TRUE TRUE FALSEThe last one is invalid: an insertion must sit between two flanking
positions, so it needs a range such as c.76_77insG.
The most common job is not “is this one id valid” but “here is a
column, which values are wrong, and can you fix the ones you can”.
report_id() runs a check over a whole column and returns a
table that prints with a one-line summary of how many values are valid,
repairable, invalid, or missing.
genes <- c("TP53", "MLL", "notagene", NA)
report_id(genes, "hgnc", how = "cache")
#> # biobouncer report on hgnc (cache mode): 1 valid, 1 repairable, 1 invalid, 1 missing of 4
#> # A tibble: 4 × 9
#> input valid normalized suggestion source_db version species how error
#> <chr> <lgl> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 TP53 TRUE TP53 <NA> hgnc 2026-07-07 <NA> cache <NA>
#> 2 MLL FALSE <NA> KMT2A hgnc 2026-07-07 <NA> cache <NA>
#> 3 notagene FALSE <NA> <NA> hgnc 2026-07-07 <NA> cache <NA>
#> 4 <NA> NA <NA> <NA> hgnc 2026-07-07 <NA> cache <NA>MLL is a withdrawn gene symbol, so it is invalid but
repairable: its successor is KMT2A.
repair_id() substitutes the fixable values and leaves
valid, unmappable, and missing values untouched, so it keeps the
column’s length and order and drops into
dplyr::mutate():
Calling summary() on a report returns the counts as a
one-row table.
The adapters wrap the core classifier so it plugs into common validation frameworks. They never reimplement any checks. The checkmate-style adapters work out of the box:
# TRUE when all are valid, otherwise a message.
check_valid_id(c("MONDO:0005148", "mondo:5148"), "mondo")
#> [1] "Must be valid mondo identifiers (pattern mode), but 1 of 2 failed, for example 'mondo:5148'"
# A single logical.
test_valid_id("MONDO:0005148", "mondo")
#> [1] TRUEid_predicate() returns an elementwise predicate for
data-frame validation with assertr or validate:
is_mondo <- id_predicate("mondo")
ids <- c("MONDO:0005148", "mondo:5148", "MONDO:0018076")
ids[is_mondo(ids)]
#> [1] "MONDO:0005148" "MONDO:0018076"For Shiny apps, sv_biobouncer() returns a shinyvalidate
rule. The rule returns NULL for a valid input and a message
otherwise:
synthesize_ids() builds a labeled “messy column” for any
source, so you can exercise a validation pipeline without hand-writing
test ids. Each row carries the input, its category (valid, repairable,
invalid, or missing), and the verdict fields the checker returned for
it.
rows <- synthesize_ids("mondo")
rows[, c("input", "category", "suggestion")]
#> # A tibble: 5 × 3
#> input category suggestion
#> <chr> <chr> <chr>
#> 1 MONDO:0005148 valid <NA>
#> 2 mondo:0005148 repairable MONDO:0005148
#> 3 MONDO:0005148! invalid <NA>
#> 4 <NA> missing <NA>
#> 5 MONDO:0005149 valid <NA>
# Feed the column straight into a report.
report_id(rows$input, "mondo")
#> # biobouncer report on mondo (pattern mode): 2 valid, 1 repairable, 1 invalid, 1 missing of 5
#> # A tibble: 5 × 9
#> input valid normalized suggestion source_db version species how error
#> <chr> <lgl> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 MONDO:00051… TRUE MONDO:000… <NA> mondo <NA> <NA> patt… <NA>
#> 2 mondo:00051… FALSE <NA> MONDO:000… mondo <NA> <NA> patt… <NA>
#> 3 MONDO:00051… FALSE <NA> <NA> mondo <NA> <NA> patt… <NA>
#> 4 <NA> NA <NA> <NA> mondo <NA> <NA> patt… <NA>
#> 5 MONDO:00051… TRUE MONDO:000… <NA> mondo <NA> <NA> patt… <NA>The column is deterministic and offline, and the Python
synthesize() produces the same one. ec,
hgvs, and hgnc have no repairable form, so
they omit that category. Pass how = "cache" for a
snapshot-mode column, where a repairable value can be a retired id that
maps to its successor.
pattern mode checks shape, cache and
remote check existence, and existence uses a
snapshot first and remote as a fallback.report_id() and repair_id() validate and
clean a whole column in one call.