| Title: | Tools to Reshape and Manipulate Dichotomous Keys Used in Taxonomic Identification |
|---|---|
| Description: | Transforms between dichotomous identification keys and a variety of phenotype formats, including feature matrices, and generates interactive dichotomous key wizards. Imports keys from 'FishBase' <https://www.fishbase.se/keys/allkeys.php> and includes PhyloTree Build 17, the human mitochondrial DNA phylogeny (van Oven 2015, <doi:10.1016/j.fsigss.2015.09.155>), as distributed by 'Haplogrep' 3. |
| Authors: | Jeremy Leipzig [aut, cre] (ORCID: <https://orcid.org/0000-0001-7224-9620>) |
| Maintainer: | Jeremy Leipzig <[email protected]> |
| License: | GPL |
| Version: | 0.1.0 |
| Built: | 2026-10-09 16:44:56 UTC |
| Source: | https://github.com/leipzig/dimoose |
Computes the tests of a keyFromAlignment() key for each sequence, for
classify(). The sequences must be aligned to the same coordinates the
key was built with: the same alignment columns or, for a key built with a
reference, an alignment that contains that reference sequence.
alignmentScores(key, alignment, reference = NULL)alignmentScores(key, alignment, reference = NULL)
key |
A key from |
alignment |
As in |
reference |
Sequence to number sites by; by default the reference the key was built with, if any. |
A sequences x features matrix: 1 if the sequence has the state
the first lead of a couplet asks for, 0 if it has another state, and
NA if it has a gap or an ambiguity code there.
The key from Triplehorn & Johnson (2005), Borror and DeLong's
Introduction to the Study of Insects, 7th ed., chapter 5, as a table of
leads (see keyFromLeads()); arachnidaKey() turns it into a dimoose
key. Transcribed by hand from the book.
arachnidaarachnida
A data frame with 22 rows (11 couplets) and 6 columns:
Couplet number.
a for the first lead (1.), b for the second (1'.).
Text of the lead.
Couplet the lead leads to, or "-".
Order the lead ends in, for terminal leads.
Page of the book where that order is treated.
Triplehorn CA, Johnson NF (2005). Borror and DeLong's
Introduction to the Study of Insects, 7th ed. Thomson Brooks/Cole.
Transcription: data-raw/arachnida/ in the package sources.
Walks each row of scores through key: at every couplet the lead whose
test (Feature, Test, Threshold) passes is taken. When no lead or
more than one passes (for instance on a missing score), the result is NA.
classify(key, scores)classify(key, scores)
key |
A dimoose key with |
scores |
A numeric matrix, one row per object, with a column for every
feature id the key tests (see |
A data frame with id (row names of scores), result and
path (the leads taken, e.g. "1a 3b").
An R6 object holding a dichotomous key as a table of the leads on every
path from the root to a terminal taxon. Usually created by
importFishbase() or parseFishbase(). See
https://www.fishbase.se/keys/allkeys.php for FishBase keys.
descKey title or description (read-only).
dfData frame with one row per lead (or per term, if terms were
separated) per terminal taxon, with columns Statement, Choice,
Character, Taxon, and pSt/pCh for the parent lead.
metaKey/value data frame of metadata (citation, image URLs, ...).
taxaData frame of terminal taxa and their resolved names.
leadsData frame with one row per lead: Statement, Choice,
Character, Next (next couplet, or "-" if terminal) and Taxon,
plus optional Prev, Image, ImageLink, TaxonUrl, Question,
Feature, Test and Threshold. Derived from df when the object
was created without one.
featuresData frame of features a machine can compute, one per
row (see featureTable()), or NULL for keys meant only for people.
dimoose$new()Create a new dimoose object.
dimoose$new(df, desc = NA, meta = NA, taxa = NA, leads = NULL, features = NULL)
dfData frame of leads (see the df field).
descKey title or description.
metaKey/value metadata data frame.
taxaData frame of terminal taxa.
leadsOptional data frame of leads (see the leads field).
featuresOptional data frame of machine-readable features (see
featureTable()).
dimoose$print()Print a short overview of the key.
dimoose$print(...)
...Unused.
dimoose$summary()Counts describing the key.
dimoose$summary()
A one-row data frame: title, couplets, leads, taxa,
depth (longest path in steps) and problems (see validate()).
dimoose$validate()Check the key: leads to missing couplets, terminal leads without a taxon, couplets with fewer than two leads, couplets that cannot be reached from the first one, and (for keys with features) leads whose machine test is missing or inconsistent.
dimoose$validate()
A character vector of problems, invisibly if there are none.
dimoose$toDataTree()Convert the key to a data.tree::Node: couplets are
internal nodes and taxa leaves; each child node carries the lead
label and the character text of the lead that leads to it. A
couplet reached from several leads is attached under the first.
dimoose$toDataTree()
dimoose$toNewick()Write the key's topology in Newick format, with couplets as internal node labels and taxa as leaves (labels quoted when needed). A couplet reached from several leads is placed under the first.
dimoose$toNewick()
A single string ending in ;.
dimoose$clone()The objects of this class are cloneable with this method.
dimoose$clone(deep = FALSE)
deepWhether to make a deep clone.
A sniglet is a visual feature that a model found and that has no name of
its own, so dimoose coins one for it ("dulmzil"). This function runs
k-means on every patch embedding of every image and keeps the unit length
centroids as the definitions of k sniglets. An image "has" a sniglet
when one of its patches is close to that centroid (see snigletScores()).
Once you have looked at what a sniglet picks out, give it a real name with
renameSniglets().
discoverSniglets(patches, k = 40, seed = 1, nstart = 10, exemplars = 4) discoverTerms(...)discoverSniglets(patches, k = 40, seed = 1, nstart = 10, exemplars = 4) discoverTerms(...)
patches |
A numeric array |
k |
Number of sniglets. |
seed |
Seed for k-means and for |
nstart |
Random starts for |
exemplars |
Number of example regions to record per sniglet, each from a different image. |
... |
Passed to |
discoverTerms(), termScores() and keyFromTerms() are the
earlier names of discoverSniglets(), snigletScores() and
keyFromSniglets(), and still work.
An object of class dimooseSniglets: sniglets (data frame with
id, sniglet (the coined word), name (what people see; the coined
word until renamed) and definition), centroids (k x d, rows named
by coined word), exemplars (data frame sniglet, image, patch,
score: the best-matching region of each of the best-matching images),
best (for every image, the region that matches each sniglet best) and
tiles (the tiling of the regions, see embedImages()).
set.seed(1) patches <- array(rnorm(5 * 9 * 8), c(5, 9, 8)) norms <- sqrt(apply(patches^2, c(1, 2), sum)) patches <- sweep(patches, c(1, 2), norms, "/") dimnames(patches) <- list(letters[1:5], NULL, NULL) discoverSniglets(patches, k = 3)$snigletsset.seed(1) patches <- array(rnorm(5 * 9 * 8), c(5, 9, 8)) norms <- sqrt(apply(patches^2, c(1, 2), sum)) patches <- sweep(patches, c(1, 2), norms, "/") dimnames(patches) <- list(letters[1:5], NULL, NULL) discoverSniglets(patches, k = 3)$sniglets
Returns one embedding per image and, for discoverSniglets(), embeddings
of local regions of each image.
embedImages( model, paths, region = NULL, patches = TRUE, tiles = 4, minDetail = 8, minFill = 0.5 )embedImages( model, paths, region = NULL, patches = TRUE, tiles = 4, minDetail = 8, minFill = 0.5 )
model |
|
paths |
Image files, or an |
region |
Optional crop |
patches |
If |
tiles |
Size of the grid of tiles: |
minDetail |
Tiles with less detail than this (standard deviation of the grey levels, 0 to 255) are treated as empty background and match nothing. |
minFill |
In a photo with a plain background (one colour around most of its border), tiles in which the subject covers less than this share are treated as empty too, so that features are about the subject and not about its backdrop. It has no effect on photos without a plain background. |
By default the regions are tiles: overlapping windows cut out of the
image and embedded one by one, as if each were a whole image. A tile's
embedding describes only what is inside it, so tiles find parts and
surfaces that different images have in common (a stem end, a dimpled
peel). Tiles that are mostly plain background are left out. tiles = 0 uses the model's own patch tokens instead, which is
faster (one pass per image) and is what fordera does, but in the last
layer of a CLIP model each token carries much of the whole image, so the
features found are less local.
A list: image (images x d matrix, rows named by image id: the
file name without extension, or the id of an imageSet()) and
patches (images x regions x d array, or NULL), which remembers the
tiling in its tiles attribute.
Embed texts
embedTexts(model, texts)embedTexts(model, texts)
model |
|
texts |
Character vector. |
A texts x d matrix with the texts as row names.
Accuracy of a key followed by machine
evaluateKey(key, scores, labels, groups = NULL)evaluateKey(key, scores, labels, groups = NULL)
key |
A dimoose key with |
scores |
A numeric matrix, one row per object, with a column for every
feature id the key tests (see |
labels |
True label of each row of |
groups |
Optional named vector mapping labels to coarser groups (e.g. model years to generations) for a second accuracy figure. |
A list: results (one row per object with actual, predicted,
correct, groupCorrect), accuracy, groupAccuracy and confusion.
Ready-made dimoose keys built from the datasets that come with dimoose. All
four are ordinary dimoose objects: they share the same fields (leads,
df, meta, taxa, desc) and methods (print(), summary(),
validate(), toDataTree(), toNewick()) and all work with
exportWizard().
sharkKey() arachnidaKey() vibrioKey()sharkKey() arachnidaKey() vibrioKey()
sharkKey(): FishBase key 1, Key to the families of sharks in the
Western Central Pacific (Compagno 1998), from saved FishBase pages in
inst/extdata/fishbase/; 23 couplets, 24 families.
arachnidaKey(): the Key to the Orders of Arachnida from Triplehorn &
Johnson (2005), the arachnida dataset; 11 couplets, 11 orders
(Schizomida is reached from two couplets).
vibrioKey(): a key generated from the vibrio consensus matrix of
Noguerola & Blanch (2008) with keyFromRpart(). Tests scored + or
(+) count as positive and - or (-) as negative; variable (v,
d) and not determined (ND) results are treated as missing, and rpart
routes a species past such a test with surrogate splits, so a species
that varies for a test appears on only one side of it. Species the tests
cannot separate share a result.
phylotreeKey(): PhyloTree Build 17.
A dimoose object.
Compagno LJV (1998). General remarks. In Carpenter KE, Niem VH (eds.), FAO species identification guide for fishery purposes. The living marine resources of the Western Central Pacific, vol. 2, pp. 1196-1207. FAO, Rome. FishBase key 1: https://www.fishbase.se/keys/description.php?keycode=1.
Triplehorn CA, Johnson NF (2005). Borror and DeLong's Introduction to the Study of Insects, 7th ed., chapter 5. Thomson Brooks/Cole. ISBN 0-03-096835-6.
Noguerola I, Blanch AR (2008). Identification of Vibrio spp. with a set of dichotomous keys. Journal of Applied Microbiology 105, 175-185. doi:10.1111/j.1365-2672.2008.03730.x
sharks <- sharkKey() sharks summary(arachnidaKey()) vibrioKey()$validate() ## Not run: exportWizard(sharkKey(), "sharks.html") ## End(Not run)sharks <- sharkKey() sharks summary(arachnidaKey()) vibrioKey()$validate() ## Not run: exportWizard(sharkKey(), "sharks.html") ## End(Not run)
Writes a dimoose key as a single self-contained HTML page. With JavaScript
on, the page steps through the key one couplet at a time, keeps a trail of
the choices made (each one clickable to go back to it) and supports the
browser's Back button. Without JavaScript, the same page is the full key
with every lead hyperlinked to its next couplet or taxon. Each taxon gets
a result section listing the characters on its path, and a map of the
key shows where the user is (see map).
exportWizard( key, file = NULL, displayLinks = TRUE, order = c("original", "parsimony"), title = NULL, map = TRUE, staticPaths = NULL )exportWizard( key, file = NULL, displayLinks = TRUE, order = c("original", "parsimony"), title = NULL, map = TRUE, staticPaths = NULL )
key |
A dimoose object, e.g. from |
file |
Path of the HTML file to write. If |
displayLinks |
If |
order |
Order of couplets. Only |
title |
Page title. Defaults to the key's description. |
map |
If |
staticPaths |
If |
The key is checked first: leads pointing at missing couplets, terminal leads without a taxon, couplets with fewer than two leads and couplets that cannot be reached from the first one are reported as warnings and marked in the page.
The path to file, invisibly, or the HTML as a character string if
file is NULL.
## Not run: sharks <- importFishbase(1, usePhyloService = "none") exportWizard(sharks, "sharks.html") ## End(Not run)## Not run: sharks <- importFishbase(1, usePhyloService = "none") exportWizard(sharks, "sharks.html") ## End(Not run)
Model-free: give it the embeddings and it applies each feature's rule.
centroid_patch_max features need patches; clip_text_pair features
need image and textEmb (rows named by prompt). For external
features supply the scores yourself.
featureScores(key, image = NULL, patches = NULL, textEmb = NULL)featureScores(key, image = NULL, patches = NULL, textEmb = NULL)
key |
A dimoose key with a |
image |
|
patches |
|
textEmb |
|
An objects x features matrix with feature ids as column names.
scoreImages() for images-to-scores in one call.
Keys built from images (see keyFromTerms() and keyFromClusters()) carry
a features table that says how a machine computes the score each lead
tests. classify() walks a key over a matrix of such scores.
featureTable( id, kind, label = id, prompt = NA, negative_prompt = NA, region = NA, embedding = NULL, exemplars = NULL, definition = NA )featureTable( id, kind, label = id, prompt = NA, negative_prompt = NA, region = NA, embedding = NULL, exemplars = NULL, definition = NA )
id |
Feature ids, e.g. |
kind |
|
label |
Name shown to people; defaults to |
prompt, negative_prompt
|
Texts for |
region |
Crop as |
embedding |
List of numeric vectors (one per feature), or |
exemplars |
List of data frames with columns |
definition |
Optional sentence saying what the feature is, shown in
the wizard's glossary (see |
A data frame with the columns above; embedding and exemplars
are list columns.
featureTable("sniglet:x", "centroid_patch_max", embedding = list(c(1, 0, 0)))featureTable("sniglet:x", "centroid_patch_max", embedding = list(c(1, 0, 0)))
Fits a classification tree (or tree ensemble) with the taxon column as the response and every other column as a feature.
generateTree( data, target_col, method = c("rpart", "randomForest", "gbm"), params = list() )generateTree( data, target_col, method = c("rpart", "randomForest", "gbm"), params = list() )
data |
A data frame containing the feature matrix. |
target_col |
Name of the target/response column. |
method |
|
params |
Optional list of arguments passed to the fitting function, overriding the defaults. |
A fitted rpart, randomForest or gbm object.
features <- data.frame( family = factor(c("A", "B", "C", "A", "B", "C")), fin = factor(c("x", "y", "y", "x", "y", "y")), head = factor(c("p", "p", "q", "p", "p", "q")) ) generateTree(features, "family", params = list(control = rpart::rpart.control(minsplit = 2, minbucket = 1)) )features <- data.frame( family = factor(c("A", "B", "C", "A", "B", "C")), fin = factor(c("x", "y", "y", "x", "y", "y")), head = factor(c("p", "p", "q", "p", "p", "q")) ) generateTree(features, "family", params = list(control = rpart::rpart.control(minsplit = 2, minbucket = 1)) )
Follows every haplogroup's path from the root of the tree and records, for
each requested site, whether the haplogroup's haplotype differs from the
root (RSRS) there. Back-mutations are applied as Haplogrep defines them
(they undo the latest change at that site), so a site gained and later
reverted on a lineage is not carried below the reversion. Insertions are
tracked as their own sites ("573.X", "2491.1"), separate from
substitutions at the same position; a deletion counts as carried.
haplotypeMatrix( haplogroups, sites = NULL, tree = dimoose::phylotree17, mutations = dimoose::phylotree17_mutations )haplotypeMatrix( haplogroups, sites = NULL, tree = dimoose::phylotree17, mutations = dimoose::phylotree17_mutations )
haplogroups |
Haplogroup names, one per row of the result; repeats are allowed (e.g. one per sample). |
sites |
Sites to report: positions as character ( |
tree, mutations
|
The tree and its mutations; default phylotree17 and
phylotree17_mutations. |
An integer matrix of 0/1, one row per entry of haplogroups (row
names are the haplogroups) and one column per site.
recurrentPositions(), macroHaplogroup(), simulateExpression()
haplotypeMatrix(c("H2a2a1", "U5b", "L0a1b"), sites = c("152", "16311", "16278"))haplotypeMatrix(c("H2a2a1", "U5b", "L0a1b"), sites = c("152", "16311", "16278"))
Reads image files and returns image_<id> rows for a key's meta, which
exportWizard() embeds in the page (each image once); leads refer to them
by id in their Image column (several separated by ;).
imageMeta(paths, ids = NULL)imageMeta(paths, ids = NULL)
paths |
Image files. |
ids |
Names for the images; default the file names without extension. |
A key/value data frame.
MIME type of an image file from its first bytes
imageMime(path)imageMime(path)
path |
One file. |
"image/png", "image/jpeg", "image/gif", "image/webp" or NA.
The starting point for automated key generation: one row per photo, with the class (species, model, ...) the photo shows. A key separates the classes, so there must be at least two.
imageSet(paths, label = NULL)imageSet(paths, label = NULL)
paths |
Image files, or a single folder. A folder is searched (with its subfolders) for image files: png, jpg/jpeg, gif, webp, bmp and tif/tiff. |
label |
Class of each image:
|
A data frame with id, path and label. id is the file name
without its extension; when two files share a name, their folder is put
in front (cardinal_IMG_01) so that ids are unique.
imageSet(c("pics/1967.png", "pics/1967_alt.png"), label = function(x) sub("_.*$", "", x)) imageSet(c("pics/cardinal/1.jpg", "pics/robin/1.jpg"), label = c("cardinal", "robin")) # the example photos that ship with dimoose: one folder per fruit pics <- imageSet(system.file("extdata", "pics", package = "dimoose")) table(pics$label)imageSet(c("pics/1967.png", "pics/1967_alt.png"), label = function(x) sub("_.*$", "", x)) imageSet(c("pics/cardinal/1.jpg", "pics/robin/1.jpg"), label = c("cardinal", "robin")) # the example photos that ship with dimoose: one folder per fruit pics <- imageSet(system.file("extdata", "pics", package = "dimoose")) table(pics$label)
Downloads a key from FishBase and converts it into a dimoose object. See https://www.fishbase.se/keys/allkeys.php for the list of keys and their key codes.
importFishbase( keycode, fishbaseUrl = "https://www.fishbase.se/", separateTerms = TRUE, usePhyloService = c("GNA", "GNR", "none", "TNRS"), embedImages = FALSE )importFishbase( keycode, fishbaseUrl = "https://www.fishbase.se/", separateTerms = TRUE, usePhyloService = c("GNA", "GNR", "none", "TNRS"), embedImages = FALSE )
keycode |
Numeric or character FishBase key code. |
fishbaseUrl |
Base URL of the FishBase mirror, with a trailing slash. |
separateTerms |
If |
usePhyloService |
Taxonomic name resolution: |
embedImages |
If |
A dimoose object.
parseFishbase() to build a key from saved HTML pages.
## Not run: sharks <- importFishbase(1) sharks$taxa ## End(Not run)## Not run: sharks <- importFishbase(1) sharks$taxa ## End(Not run)
Random words made of consonant onsets, vowels and codas. They name sniglets: visual features that have no English name (as fordera does).
inventNames(n, seed = 1)inventNames(n, seed = 1)
n |
Number of names. |
seed |
Random seed, so the same call gives the same names. The global random number generator state is left unchanged. |
A character vector of n distinct lower-case words.
inventNames(5)inventNames(5)
One command from aligned sequences to a dichotomous key. A phylogeny
program builds a tree from the alignment, the tree is rooted and made
strictly bifurcating, and every fork becomes a couplet whose two leads are
the alignment sites that tell its two clades apart ("152C 16311T"
against "152T 16311C"). Each sequence is a result.
keyFromAlignment( alignment, tool = c("nj", "bionj", "upgma", "parsimony", "ml", "fasttree", "iqtree"), tree = NULL, outgroup = NULL, reference = NULL, type = c("auto", "DNA", "AA"), model = NULL, maxSites = 3, exe = NULL, args = NULL, desc = "Key generated from a sequence alignment", meta = NULL )keyFromAlignment( alignment, tool = c("nj", "bionj", "upgma", "parsimony", "ml", "fasttree", "iqtree"), tree = NULL, outgroup = NULL, reference = NULL, type = c("auto", "DNA", "AA"), model = NULL, maxSites = 3, exe = NULL, args = NULL, desc = "Key generated from a sequence alignment", meta = NULL )
alignment |
The alignment: a FASTA file, an |
tool |
The program that builds the tree:
|
tree |
A tree you built yourself, instead of |
outgroup |
Name(s) of the sequence(s) to root on. Without it, a tree that is not already rooted is rooted at its midpoint. Sequences can be named in full or by the first word of their FASTA header. |
reference |
Name of a sequence in the alignment to number sites by
(its ungapped positions; columns where it has a gap are numbered
|
type |
|
model |
Substitution model, passed to the tool: the |
maxSites |
Most sites listed in a lead. |
exe |
Path to the FastTree or IQ-TREE program, if it is not on the
|
args |
Extra command-line arguments for FastTree or IQ-TREE. |
desc, meta
|
Title and extra metadata of the key. |
Sites are chosen per fork: a site is diagnostic when the states seen on
one side are never seen on the other. Up to maxSites diagnostic sites
are listed, those with the least missing data first. If a fork has no diagnostic site, the
best-separating one is used and marked (most). If no site separates the
two sides, the sequences below it are split by their sites alone,
whatever the tree says. Sequences that no site tells apart share a result
("A / B"), as do identical sequences. Gaps and ambiguity codes are treated as missing data.
The first site of each couplet is also a machine-readable test, so
classify() can place sequences scored with alignmentScores().
A dimoose key. Its meta records the tool, the rooting, the tree
in Newick format (newick, names quoted where Newick needs it), how many couplets lack a diagnostic site
(weak_couplets) and how many do not follow the tree
(regrouped_couplets).
alignmentScores(), phylotreeKey(), toNewick()
aln <- c(human = "ACGTACGTACGA", chimp = "ACGTACGTATGA", mouse = "ACCTACATGCGA", rat = "ACCTACATGCGT", fish = "TCCTTCGTACCA") if (requireNamespace("ape", quietly = TRUE)) { key <- keyFromAlignment(aln, outgroup = "fish") key$leads[, c("Statement", "Character", "Next", "Taxon")] classify(key, alignmentScores(key, aln)) } # the example files that ship with dimoose fasta <- system.file("extdata", "aligned.fasta", package = "dimoose") mtdna <- system.file("extdata", "mtdna.fasta", package = "dimoose") if (requireNamespace("ape", quietly = TRUE)) { keyFromAlignment(fasta) keyFromAlignment(fasta, tree = system.file("extdata", "aligned.nwk", package = "dimoose")) keyFromAlignment(mtdna, reference = "H2a2a1", outgroup = "L0a1") } ## Not run: keyFromAlignment(mtdna, tool = "iqtree", outgroup = "L0a1") # needs IQ-TREE installed ## End(Not run)aln <- c(human = "ACGTACGTACGA", chimp = "ACGTACGTATGA", mouse = "ACCTACATGCGA", rat = "ACCTACATGCGT", fish = "TCCTTCGTACCA") if (requireNamespace("ape", quietly = TRUE)) { key <- keyFromAlignment(aln, outgroup = "fish") key$leads[, c("Statement", "Character", "Next", "Taxon")] classify(key, alignmentScores(key, aln)) } # the example files that ship with dimoose fasta <- system.file("extdata", "aligned.fasta", package = "dimoose") mtdna <- system.file("extdata", "mtdna.fasta", package = "dimoose") if (requireNamespace("ape", quietly = TRUE)) { keyFromAlignment(fasta) keyFromAlignment(fasta, tree = system.file("extdata", "aligned.nwk", package = "dimoose")) keyFromAlignment(mtdna, reference = "H2a2a1", outgroup = "L0a1") } ## Not run: keyFromAlignment(mtdna, tool = "iqtree", outgroup = "L0a1") # needs IQ-TREE installed ## End(Not run)
Classes are clustered on the mean embedding of their images (Ward's method), giving a binary tree. Each split is then described by the vocabulary pair that best separates its two sides: the pair maximising |(L.yes - L.no) - (R.yes - R.no)| over the side means, not used above that split. The "Has feature" lead goes to the side the feature scores higher on. Machine answers use the same two prompts.
keyFromClusters( image, images, vocabulary, textEmb, template = "{x}", order = NULL, maxPerSide = 10, calibrate = c("none", "midpoint"), desc = "Key generated from image clusters", meta = NULL )keyFromClusters( image, images, vocabulary, textEmb, template = "{x}", order = NULL, maxPerSide = 10, calibrate = c("none", "midpoint"), desc = "Key generated from image clusters", meta = NULL )
image |
|
images |
|
vocabulary |
As in |
textEmb |
Text embeddings of |
template |
Must match the one used to make |
order |
Optional function of a character vector of labels returning a number; at each split the child with the smaller value comes first. |
maxPerSide |
Most images per side used for the side means. |
calibrate |
|
desc, meta
|
Title and metadata. |
A dimoose key with clip_text_pair features.
The common constructor behind sharkKey(), arachnidaKey(),
vibrioKey() and phylotreeKey(): takes one row per lead and returns a
dimoose object.
keyFromLeads(leads, desc = NA, meta = NULL, taxa = NULL, features = NULL)keyFromLeads(leads, desc = NA, meta = NULL, taxa = NULL, features = NULL)
leads |
Data frame with columns |
desc |
Title or description of the key. |
meta |
Key/value data frame of metadata (e.g. |
taxa |
Data frame of results with |
features |
Optional |
A dimoose object.
leads <- data.frame( Statement = c("1", "1", "2", "2"), Choice = c("a", "b", "a", "b"), Character = c("Wings present", "Wings absent", "Two wings", "Four wings"), Next = c("2", "-", "-", "-"), Taxon = c("", "Apterygota", "Diptera", "Other") ) k <- keyFromLeads(leads, "A tiny key") k k$toNewick()leads <- data.frame( Statement = c("1", "1", "2", "2"), Choice = c("a", "b", "a", "b"), Character = c("Wings present", "Wings absent", "Two wings", "Four wings"), Next = c("2", "-", "-", "-"), Taxon = c("", "Apterygota", "Diptera", "Other") ) k <- keyFromLeads(leads, "A tiny key") k k$toNewick()
Each split becomes a couplet and each terminal node a result, labelled
with its stratum level and size. Splits on 0/1 variables read as
"Carries 16311" / "Does not carry 16311". The leads carry machine-readable
tests on the split variables, so classify() can place new samples given
their haplotypeMatrix(), and exportWizard() can draw the tree.
Splits on factor columns become text-only couplets ("tissue is liver or
lung"), which a person can follow but classify() cannot; the function
warns when the key has any.
keyFromMecit(fit, desc = NULL, digits = 2)keyFromMecit(fit, desc = NULL, digits = 2)
fit |
A |
desc |
Title of the key. |
digits |
Decimal places for stratum levels. |
A dimoose key.
Converts an rpart::rpart() classification tree into a dichotomous key:
every split becomes a couplet with two leads, and every leaf a result.
Taxa that the tree cannot separate share a leaf and are listed together
("A / B").
keyFromRpart( fit, desc = "Key generated from a classification tree", meta = NULL )keyFromRpart( fit, desc = "Key generated from a classification tree", meta = NULL )
fit |
An |
desc |
Title of the key. |
meta |
Key/value metadata data frame. |
A dimoose object.
d <- data.frame( taxon = factor(c("A", "B", "C")), wings = factor(c("+", "-", "-")), spots = factor(c("-", "+", "-")) ) fit <- generateTree(d, "taxon", params = list(control = rpart::rpart.control(minsplit = 2, minbucket = 1, cp = 0))) keyFromRpart(fit, "Three taxa")$leadsd <- data.frame( taxon = factor(c("A", "B", "C")), wings = factor(c("+", "-", "-")), spots = factor(c("-", "+", "-")) ) fit <- generateTree(d, "taxon", params = list(control = rpart::rpart.control(minsplit = 2, minbucket = 1, cp = 0))) keyFromRpart(fit, "Three taxa")$leads
Each step asks whether the image has one sniglet. method = "balanced" is fordera's algorithm: a sniglet is present when its score is
above the quantile of that sniglet's scores over all images; a label has
a sniglet if any of its images does; each split uses the unused sniglet
that divides the remaining labels most evenly (ties to the earlier one).
method = "rpart" suits several images per label. It first gives each
sniglet one threshold, the cut of its scores that best separates the
labels, and then grows a classification tree on has/lacks, so a sniglet
means the same thing wherever the key asks about it.
keyFromSniglets( scores, images, sniglets, method = c("balanced", "rpart"), quantile = 0.6, desc = "Key generated from sniglets", meta = NULL ) keyFromTerms(scores, images, terms, ...)keyFromSniglets( scores, images, sniglets, method = c("balanced", "rpart"), quantile = 0.6, desc = "Key generated from sniglets", meta = NULL ) keyFromTerms(scores, images, terms, ...)
scores |
|
images |
|
sniglets |
The |
method |
|
quantile |
Presence threshold quantile for |
desc, meta
|
Title and metadata of the key. |
terms, ...
|
|
A dimoose key whose leads carry Feature, Test, Threshold and
Question, and whose features table holds the centroids. Feature ids
are "sniglet:<coined word>" and never change; label is the name
shown, which renameSniglets() changes.
A lead that only says a specimen lacks something gives the reader nothing
to look for. Where it can, the "Lacks" lead therefore also names what its
images have instead: another sniglet that at least 90% of them have and at
most 10% of the other side do ("Lacks gaithiark; has blienvaurk"). The
machine still tests only the first sniglet. Every lead also records example
regions from the images that take it (Examples), which
patchExemplars() turns into crops: for a "Lacks" lead with no such second
sniglet, they are the regions that come closest to the missing one.
Leave-one-out evaluation of a key builder
looKey(images, build, score, groups = NULL)looKey(images, build, score, groups = NULL)
images |
|
build |
Function of the training row indices returning a key. |
score |
Function of (key, test row index) returning a one-row scores matrix for that image. |
groups |
As in |
As evaluateKey().
Macrohaplogroup of a haplogroup
macroHaplogroup( haplogroup, level = c("letter", "depth"), depth = 2, tree = dimoose::phylotree17 )macroHaplogroup( haplogroup, level = c("letter", "depth"), depth = 2, tree = dimoose::phylotree17 )
haplogroup |
Haplogroup names. |
level |
|
depth |
For |
tree |
Default phylotree17. |
A character vector the length of haplogroup.
macroHaplogroup(c("H2a2a1", "L3e1", "U5b")) macroHaplogroup("H2a", level = "depth", depth = 3)macroHaplogroup(c("H2a2a1", "L3e1", "U5b")) macroHaplogroup("H2a", level = "depth", depth = 3)
Fits a tree that partitions observations on candidate split variables (for
example which mutations each sample carries, from haplotypeMatrix())
while a random effect absorbs differences between clusters (for example
macrohaplogroups, from macroHaplogroup()). Without the random effect, a
tree also splits on variables that merely track the clusters, such as
clade-defining markers; with it, those differences are removed before the
tree looks for splits.
mecit( y, partition, cluster = NULL, method = c("ctree", "mob"), slope = NULL, alpha = 0.05, minbucket = 20L, maxdepth = Inf, ranefstart = TRUE, abstol = 0.001, maxit = 50L )mecit( y, partition, cluster = NULL, method = c("ctree", "mob"), slope = NULL, alpha = 0.05, minbucket = 20L, maxdepth = Inf, ranefstart = TRUE, abstol = 0.001, maxit = 50L )
y |
Numeric response, one value per observation. |
partition |
Matrix or data frame of candidate split variables, one row
per observation, with column names (which may be non-syntactic, like
|
cluster |
Cluster of each observation, or |
method |
|
slope |
Optional names of |
alpha |
Significance level for splitting (Bonferroni-adjusted over the candidate variables). |
minbucket |
Smallest allowed terminal node. |
maxdepth |
Maximum tree depth. |
ranefstart |
If |
abstol, maxit
|
Convergence tolerance and the maximum number of
iterations. For |
method = "ctree" (the default) is the RE-EM algorithm of Sela & Simonoff
(2012) with conditional inference trees, as proposed by Fu & Simonoff
(2015). It alternates between (1) a partykit::ctree() on the response
minus the current random-effect contribution and (2) a linear mixed model
(lme4::lmer()) with one fixed effect per terminal node plus the random
effects, until the random effects stop changing. method = "mob" uses
model-based partitioning through glmertree::lmertree() (Fokkema et al.
2018). In both, ranefstart = TRUE estimates the random effects from an
intercept-only mixed model before the first tree, which keeps that tree from
splitting on cluster-level variables.
With cluster = NULL the result is a plain conditional inference tree, the
baseline a mixed-effects tree is compared with.
An object of class mecit: tree (a partykit tree), lmer (the
final mixed model, or NULL), strata (data frame of node, mean
and n; mean is the stratum level net of random effects), node
(terminal node of each observation), ranef (random-effect
contribution of each observation), method, iterations and
converged.
Sela RJ, Simonoff JS (2012). RE-EM trees: a data mining approach for longitudinal and clustered data. Machine Learning 86, 169-207. doi:10.1007/s10994-011-5258-3
Fu W, Simonoff JS (2015). Unbiased regression trees for longitudinal and clustered data. Computational Statistics & Data Analysis 88, 53-74. doi:10.1016/j.csda.2015.02.004
Fokkema M, Smits N, Zeileis A, Hothorn T, Kelderman H (2018). Detecting treatment-subgroup interactions in clustered data with generalized linear mixed-effects model trees. Behavior Research Methods 50, 2016-2034. doi:10.3758/s13428-017-0971-x
splitVariables(), keyFromMecit(), simulateExpression()
## Not run: sim <- simulateExpression(n = 600, genes = 6) fit <- mecit(sim$expr[, 1], sim$X, sim$samples$macro) fit exportWizard(keyFromMecit(fit), "mecit.html") ## End(Not run)## Not run: sim <- simulateExpression(n = 600, genes = 6) fit <- mecit(sim$expr[, 1], sim$X, sim$samples$macro) fit exportWizard(keyFromMecit(fit), "mecit.html") ## End(Not run)
Model details as metadata rows
modelMeta(model)modelMeta(model)
model |
A key/value data frame with model_* keys.
The offline half of importFishbase(): parses a FishBase key description
page and its questions (couplet) page, both already downloaded.
parseFishbase( description, questions, separateTerms = TRUE, usePhyloService = c("GNA", "GNR", "none", "TNRS"), embedImages = FALSE, pageUrl = "https://www.fishbase.se/keys/questions.php" )parseFishbase( description, questions, separateTerms = TRUE, usePhyloService = c("GNA", "GNR", "none", "TNRS"), embedImages = FALSE, pageUrl = "https://www.fishbase.se/keys/questions.php" )
description |
The description page ( |
questions |
The questions page ( |
separateTerms |
If |
usePhyloService |
Taxonomic name resolution: |
embedImages |
If |
pageUrl |
URL of the questions page, used to resolve relative image links. |
A dimoose object.
## Not run: parseFishbase("description.html", "questions.html", usePhyloService = "none") ## End(Not run)## Not run: parseFishbase("description.html", "questions.html", usePhyloService = "none") ## End(Not run)
Cuts out the example regions of each sniglet and of each lead, stores them
as PNGs in the key's features and meta, and points the leads at them
so exportWizard() shows them. A "Has" lead shows the sniglet in the
images that take that lead; a "Lacks" lead shows what its images have
instead (see keyFromSniglets()). The glossary shows each sniglet's
examples across all the images.
patchExemplars(model, key, images, pad = NULL, size = 96)patchExemplars(model, key, images, pad = NULL, size = 96)
model |
|
key |
A key from |
images |
The |
pad |
Pixels of context to show around the region. By default none for tiles, and half a patch's width for patch tokens. |
size |
The crop's output size, px. |
The key, modified in place and returned invisibly.
The 5,435 haplogroups of PhyloTree Build 17 (van Oven 2015) as
distributed by Haplogrep 3 (release 17.2 of phylotree-rsrs-17), one row
per haplogroup, rooted at mtMRCA. Use phylotreeKey() to turn the tree,
or part of it, into an identification key, and phylotree17_mutations for
the mutations one per row.
phylotree17phylotree17
A data frame with 5,435 rows and 5 columns:
Haplogroup name.
Name of the parent haplogroup (NA for mtMRCA).
Number of branches from mtMRCA.
Number of direct subclades.
Space-separated mutations of the branch leading to this haplogroup, as written by Haplogrep.
Rows are in the order of Haplogrep's tree.xml, which is preorder (each
haplogroup directly before its subclades). Names and mutations are
Haplogrep's, verbatim: names such as H2a+152 16311 or K1b1+(16093)
label branches that PhyloTree leaves unnamed, and two names (M4’’67,
M4’’67+16311!) contain the Unicode character U+2019. Haplogrep's
trailing space on one name is trimmed.
Mutations are in RSRS orientation: each is the state on the branch leading
to the haplogroup. 16362C is a substitution (position and derived base),
263G! a back-mutation (it reverts the latest change at that position;
!! marks a second reversion), 315.1C or 5899.XC an insertion (X:
unspecified length) and 249d a deletion. Unlike some other copies (e.g.
MToolBox's), PhyloTree's unstable mutations, which PhyloTree prints in
parentheses, are included; the parentheses are not recorded.
Haplogrep 3 tree phylotree-rsrs-17, release 17.2, commit
0e79ddf1b78f7a1b81fb5d607bc31a6ddea7b18b, src/tree.xml
(https://github.com/genepi/phylotree-rsrs-17), MIT license. The
conversion and a script that checks these data against GitHub are in
data-raw/phylotree17/ in the package sources.
van Oven M (2015). PhyloTree Build 17: Growing the human mitochondrial DNA tree. Forensic Science International: Genetics Supplement Series 5, e392-e394. doi:10.1016/j.fsigss.2015.09.155
Schönherr S, Weissensteiner H, Kronenberg F, Forer L (2023). Haplogrep 3 - an interactive haplogroup classification and analysis platform. Nucleic Acids Research 51, W263-W268. doi:10.1093/nar/gkad284
phylotree17_mutations, phylotreeKey()
head(phylotree17) phylotree17[phylotree17$parent %in% "H2a2a", ]head(phylotree17) phylotree17[phylotree17$parent %in% "H2a2a", ]
The mutations of every haplogroup in phylotree17, one row per mutation, in the order Haplogrep lists them, with the bases before and after worked out by following the tree from the RSRS.
phylotree17_mutationsphylotree17_mutations
A data frame with 13,384 rows and 6 columns:
Haplogroup whose branch carries the mutation.
The mutation as written by Haplogrep.
Position in the RSRS/rCRS coordinates.
transition, transversion, back-mutation,
insertion or deletion.
Base before the mutation (for a reverted insertion, the
inserted sequence); NA for insertions.
Base after the mutation, or the inserted sequence; NA
for deletions and reverted insertions.
Seven back-mutations revert a position that nothing earlier on their path
changes (six 16233C!, e.g. in D4c1b1, and D5a2 1438A!); for those
the written base is taken as the result.
See phylotree17.
table(phylotree17_mutations$type) phylotree17_mutations[phylotree17_mutations$haplogroup == "J1c", ]table(phylotree17_mutations$type) phylotree17_mutations[phylotree17_mutations$haplogroup == "J1c", ]
Turns phylotree17, or the part of it below root, into a dimoose key.
Each haplogroup with subclades becomes a step at which the user picks the
subclade whose defining mutations the sample carries. With paragroups = TRUE every step also offers "none of these", which identifies the
paragroup, written as in PhyloTree with a trailing * (e.g. H2a*).
phylotreeKey(root = "mtMRCA", paragroups = TRUE, maxDepth = Inf)phylotreeKey(root = "mtMRCA", paragroups = TRUE, maxDepth = Inf)
root |
Haplogroup to start from; the default, |
paragroups |
If |
maxDepth |
Maximum number of steps below |
The whole tree gives a very large key (2,420 steps and 5,435 possible
results with paragroups), so for exportWizard() a subtree or a
maxDepth is usually more practical.
A dimoose object whose leads have a Label column with the
haplogroup names.
h2a <- phylotreeKey("H2a") head(h2a$leads) ## Not run: exportWizard(phylotreeKey("U5"), "u5.html") exportWizard(phylotreeKey(maxDepth = 6), "macrohaplogroups.html") ## End(Not run)h2a <- phylotreeKey("H2a") head(h2a$leads) ## Not run: exportWizard(phylotreeKey("U5"), "u5.html") exportWizard(phylotreeKey(maxDepth = 6), "macrohaplogroups.html") ## End(Not run)
An R6 object holding a FishBase key's description and its couplet table as downloaded, before conversion to a dimoose object.
descKey title (read-only).
dfThe key's couplet table: one row per lead, with columns
Statement, Choice, Character, Next, Prev and Taxon.
rawhtml$print()Print the description, table and metadata.
rawhtml$print(...)
...Unused.
rawhtml$new()Download a FishBase key.
rawhtml$new( keycode, fishbaseUrl = "https://www.fishbase.se/", separateTerms = TRUE )
keycodeFishBase key code.
fishbaseUrlBase URL of the FishBase mirror.
separateTermsIgnored; kept for backward compatibility.
rawhtml$clone()The objects of this class are cloneable with this method.
rawhtml$clone(deep = FALSE)
deepWhether to make a deep clone.
Parses the nested <haplogroup> XML that Haplogrep distributes (for
example phylotree-rcrs-17's tree.xml) into the same data frame shape as
phylotree17, so any Haplogrep tree can be loaded, not just the bundled
snapshot. Each haplogroup's <details><poly> entries become its mutations.
readHaplogrep(file, key = FALSE)readHaplogrep(file, key = FALSE)
file |
Path to the tree XML. |
key |
If |
A data frame with haplogroup, parent, depth, n_subclades
and mutations, or a dimoose object if key = TRUE.
## Not run: tree <- readHaplogrep("tree.xml") ## End(Not run)## Not run: tree <- readHaplogrep("tree.xml") ## End(Not run)
Sites that mutate independently on many branches of the tree, such as 152, 16311 and 16189 in PhyloTree. These are the variants whose effects a tree can find across unrelated lineages.
recurrentPositions( min_branches = 10, types = c("transition", "transversion", "back-mutation"), mutations = dimoose::phylotree17_mutations )recurrentPositions( min_branches = 10, types = c("transition", "transversion", "back-mutation"), mutations = dimoose::phylotree17_mutations )
min_branches |
Minimum number of branches (haplogroups) on which the site mutates. |
types |
Mutation types to count; by default substitutions and
back-mutations. Insertions and deletions are left out, except that a
reverted insertion counts as a back-mutation at its insertion site
(for example |
mutations |
Default phylotree17_mutations. |
A data frame of site and n_branches, most recurrent first.
head(recurrentPositions())head(recurrentPositions())
Sniglets start with coined names ("dulmzil") because nobody has looked at
them yet. After looking at what a sniglet picks out (the example crops in
the wizard's glossary), give it a real name. The coined word stays as the
sniglet's permanent identifier, so scores, machine tests and saved name
tables keep working; only the text people read changes: the leads
("Has round headlights"), the questions and the glossary.
renameSniglets(x, names = NULL, definitions = NULL)renameSniglets(x, names = NULL, definitions = NULL)
x |
A key from |
names |
The new names: a named character vector
( |
definitions |
Optional named character vector of definitions, named
like |
The names table has one row per sniglet you want to rename, with columns
sniglet (the coined word, or the sniglet's current name), name and
optionally definition. Rules:
a blank name puts the coined word back;
no two sniglets may share a name, and a name may not be another sniglet's coined word;
a definition column replaces the definitions of the rows listed
(blank removes one); without the column, definitions are left alone;
a used column, as snigletNames() returns, is ignored.
Names read best as noun phrases ("an egg-crate grille"), since leads are
written "Has name" and "Lacks name".
A renamed copy of x; x itself is not changed.
set.seed(1) patches <- array(rnorm(5 * 9 * 8), c(5, 9, 8)) patches <- sweep(patches, c(1, 2), sqrt(apply(patches^2, c(1, 2), sum)), "/") s <- discoverSniglets(patches, k = 3) first <- s$sniglets$sniglet[1] s <- renameSniglets(s, stats::setNames("round headlights", first), definitions = stats::setNames("Circular lamps in the grille", first)) snigletNames(s)set.seed(1) patches <- array(rnorm(5 * 9 * 8), c(5, 9, 8)) patches <- sweep(patches, c(1, 2), sqrt(apply(patches^2, c(1, 2), sum)), "/") s <- discoverSniglets(patches, k = 3) first <- s$sniglets$sniglet[1] s <- renameSniglets(s, stats::setNames("round headlights", first), definitions = stats::setNames("Circular lamps in the grille", first)) snigletNames(s)
Embeds the images (once per distinct crop region the key's text features
use) and applies featureScores().
scoreImages(key, model, paths)scoreImages(key, model, paths)
key |
A key with a |
model |
|
paths |
Image files, or an |
An images x features matrix for classify().
Simulates per-sample expression for a set of genes, where recurrent
mutations (variants that arise independently on many branches) shift
expression by fixed amounts on top of a baseline that differs between
macrohaplogroups. It is the ground truth for testing mecit(): a good
method finds the mutation effects as splits and does not split on clade
markers that only track the macrohaplogroup baselines.
simulateExpression( n = 1000, genes = 20, effectSites = c("16362", "150", "709", "16093"), propMutation = 0.4, propBaseline = 0.3, sitesPerGene = 1:2, effect = 1, macroSD = 1, slopeSD = 0, noise = 1, decoys = NULL, macroLevel = "letter", seed = 1 )simulateExpression( n = 1000, genes = 20, effectSites = c("16362", "150", "709", "16093"), propMutation = 0.4, propBaseline = 0.3, sitesPerGene = 1:2, effect = 1, macroSD = 1, slopeSD = 0, noise = 1, decoys = NULL, macroLevel = "letter", seed = 1 )
n |
Number of samples. |
genes |
Number of genes. |
effectSites |
Sites that can carry mutation effects. |
propMutation, propBaseline
|
Proportions of mutation and baseline genes; the rest are null. |
sitesPerGene |
Possible numbers of effect sites per mutation gene. |
effect |
Size of each mutation effect (its sign is random). |
macroSD |
Standard deviation of the macrohaplogroup baselines. |
slopeSD |
If positive, each mutation effect also varies between macrohaplogroups with this standard deviation (a random slope). |
noise |
Residual standard deviation. |
decoys |
Extra candidate split sites with no effect. By default the most recurrent other sites plus the markers of the four most common macrohaplogroups in the sample. |
macroLevel |
Passed to |
seed |
Random seed. |
Samples are drawn uniformly from the leaf haplogroups of phylotree17, so their macrohaplogroups are as unbalanced as the tree itself (H is far more common than L5). For sample i and gene g:
expr[i, g] = b[g, macro(i)] + sum_s beta[g, s] * X[i, s] + slope + noise
Genes come in three kinds: "mutation" genes have a baseline and one or
more mutation effects, "baseline" genes have only the macrohaplogroup
baseline, and "null" genes are pure noise.
The default effect sites (16362, 150, 709, 16093) are highly recurrent but carried by a minority of lineages across many macrohaplogroups. The most-cited recurrent sites (152, 16311, 146, 16189) are poor effect sites in RSRS orientation: they are also on deep branches (16311 is an L3 marker), so most lineages carry them and carrying them largely tracks clade membership. They are included as decoys instead.
A list with expr (samples x genes), samples (data frame of
sample, haplogroup, macro), X (samples x sites, 0/1, from
haplotypeMatrix()), truth (beta, genes x sites; b, genes x
macrohaplogroups; geneType; and slope when slopeSD > 0),
effectSites, markerSites and decoySites.
sim <- simulateExpression(n = 300, genes = 10) table(sim$truth$geneType)sim <- simulateExpression(n = 300, genes = 10) table(sim$truth$geneType)
Lists the sniglets of a key (or of a discoverSniglets() result) with the
names they currently go by. This is the table renameSniglets() takes:
write it to a CSV file, fill in the name and definition columns, and
read it back.
snigletNames(x)snigletNames(x)
x |
A key from |
A data frame with one row per sniglet:
sniglet: the coined word. It identifies the sniglet and never changes.
name: the name people see. It is the coined word until you rename it.
definition: an optional sentence saying what the sniglet is.
used (keys only): whether the key asks about this sniglet. Only these
need names.
Score images against sniglets
snigletScores(patches, centroids) termScores(patches, centroids)snigletScores(patches, centroids) termScores(patches, centroids)
patches |
As in |
centroids |
A |
An images x sniglets matrix: for each sniglet, the highest cosine
similarity between the centroid and any patch of the image. Columns are
named by the coined words, whatever the sniglets have been renamed to.
Variables a fitted tree splits on
splitVariables(fit)splitVariables(fit)
fit |
A |
The names (as given in partition) of the variables used in any
split, in the order they first appear; character(0) if the tree has no
splits.
Writes the key's spanning tree as an Auspice v2 dataset, which the
Nextstrain viewer and auspice.us can display. Node names are made unique
and space-free (required by the schema); the original labels and each
lead's text are kept in node_attrs. div is the depth from the root.
toAuspiceJSON(key, title = NULL, file = NULL)toAuspiceJSON(key, title = NULL, file = NULL)
key |
A dimoose key. |
title |
Dataset title; defaults to the key's description. |
file |
Optional path to write to; if |
The JSON string (invisibly if written to file).
js <- toAuspiceJSON(phylotreeKey("H2a"))js <- toAuspiceJSON(phylotreeKey("H2a"))
Unlike toNewick() and toDataTree(), which use a spanning tree, this
keeps the key's true structure: a couplet reached from several leads has
several incoming edges. Each edge carries the lead's label and
Character text; vertices are couplets and taxa.
toIgraph(key)toIgraph(key)
key |
A dimoose key. |
An igraph::igraph directed graph.
## Not run: g <- toIgraph(arachnidaKey()) igraph::vcount(g) ## End(Not run)## Not run: g <- toIgraph(arachnidaKey()) igraph::vcount(g) ## End(Not run)
The dimoose method $toNewick() writes quoted Newick, which is correct but
which several parsers (ape, scikit-bio, toytree) mangle. This wrapper adds
two options for interoperating with the wider phylogenetics ecosystem.
toNewick( key, labels = c("quoted", "safe"), annotate = c("none", "nhx", "beast") )toNewick( key, labels = c("quoted", "safe"), annotate = c("none", "nhx", "beast") )
key |
A dimoose key. |
labels |
|
annotate |
[ ]: R:%20 |
For labels = "quoted" or any annotate, a single Newick string.
For labels = "safe" with annotate = "none", a list of newick (the
string) and labels (a data frame of id and label).
k <- arachnidaKey() cat(toNewick(k, annotate = "nhx"))k <- arachnidaKey() cat(toNewick(k, annotate = "nhx"))
Builds a treedata object whose tree is the key's spanning tree and whose
node data carries each lead's Character, Choice and Taxon. The data
of a child node describes the edge into it, so in ggtree you draw lead text
on branches with geom_label(aes(x = branch, label = Character)) and join
your own data by the node column (never by label, since taxa repeat).
toTreedata(key)toTreedata(key)
key |
A dimoose key. |
A tidytree::treedata object.
## Not run: td <- toTreedata(arachnidaKey()) library(ggtree) ggtree(td) + geom_tiplab() + geom_label(aes(x = branch, label = Character)) ## End(Not run)## Not run: td <- toTreedata(arachnidaKey()) library(ggtree) ggtree(td) + geom_tiplab() + geom_label(aes(x = branch, label = Character)) ## End(Not run)
Biochemical and growth test results for 74 Vibrio taxa from Noguerola &
Blanch (2008), one row per taxon. vibrioKey() generates a key from it.
vibriovibrio
A data frame with 74 rows and 46 columns: species, then 45 tests
coded as in the paper: + positive, - negative, (+) / (-) mostly
positive / negative, v or d variable, ND not determined (and one
blank cell in the source, NA). Tests under the paper's "Acid from" and
"Resistance to" headings are named with that prefix.
Noguerola I, Blanch AR (2008). Identification of Vibrio spp.
with a set of dichotomous keys. Journal of Applied Microbiology 105,
175-185. doi:10.1111/j.1365-2672.2008.03730.x. Extracted from the
paper's table; see data-raw/vibrio/ in the package sources.
Uses Python's open_clip through reticulate. You do not need to install
anything in Python yourself: the first call sets up a private Python with
the packages dimoose needs (torch, open_clip_torch, pillow, numpy)
and reuses it afterwards. That first call downloads them, which takes a
few minutes. This needs reticulate 1.41 or later.
visionModel( weights = NULL, name = "ViT-B-32", pretrained = "openai", python = NULL )visionModel( weights = NULL, name = "ViT-B-32", pretrained = "openai", python = NULL )
weights |
Local checkpoint file: OpenAI's |
name |
The model: an open_clip architecture name, |
pretrained |
open_clip's tag for the weights to download for an
architecture |
python |
Optional path to the Python executable to use (passed to
|
To use a Python of your own instead, give its path in python, or select
it with reticulate::use_python(), reticulate::use_virtualenv() or the
RETICULATE_PYTHON environment variable before the first call, and install
the packages there with
reticulate::py_install(c("torch", "open_clip_torch", "pillow", "numpy")).
An object of class dimooseVisionModel with py (the Python model)
and spec (library, architecture, weights SHA-256, image size, ...).
Any open_clip model whose image side is a vision transformer works. The key builders only see its embeddings, so nothing else changes.
visionModel(name = "bioclip") loads
BioCLIP and
visionModel(name = "bioclip-2") BioCLIP 2, models trained on images of
organisms, from the Hugging Face Hub. They are downloaded on first use.
name = "hf-hub:<organisation>/<model>" loads any other open_clip model
on the Hub, and name = "local-dir:<folder>" a copy you have downloaded
(the folder holds the model's open_clip_config.json and weights file).
name and pretrained together select one of open_clip's built-in
models, e.g. name = "ViT-B-16", pretrained = "laion2b_s34b_b88k".
A key can only be followed with the model it was built with: use the same
model for embedImages() and later for scoreImages().
BioCLIP's text side was trained on names of organisms, not on descriptions
of what they look like. It suits sniglets (discoverSniglets()), which use
images only, better than vocabulary questions (keyFromClusters()).
## Not run: model <- visionModel() # CLIP ViT-B/32 model <- visionModel(name = "bioclip") # BioCLIP, for photos of organisms ## End(Not run)## Not run: model <- visionModel() # CLIP ViT-B/32 model <- visionModel(name = "bioclip") # BioCLIP, for photos of organisms ## End(Not run)
Prompts for a vocabulary of visual features
vocabularyPrompts(vocabulary, template = "{x}")vocabularyPrompts(vocabulary, template = "{x}")
vocabulary |
Data frame with |
template |
Text with |
A character vector: the feature prompt then the opposite prompt
for each row, in order. Embed these with embedTexts() and pass the
result to keyFromClusters().
v <- data.frame(feature = c("round lights", "a flat hood"), opposite = c("square lights", "a curved hood")) vocabularyPrompts(v, "a truck with {x}")v <- data.frame(feature = c("round lights", "a flat hood"), opposite = c("square lights", "a curved hood")) vocabularyPrompts(v, "a truck with {x}")