├── .Rbuildignore
├── .gitignore
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── NEWS.md
├── R
├── bias-helpers.R
├── calibrate.R
├── compositional-mean.R
├── estimate.R
├── math.R
├── mean_efficiency.R
├── metacal-package.R
├── metacal.R
├── ratios.R
├── utilities.R
└── utils-pipe.R
├── README.md
├── _pkgdown.yml
├── data-raw
└── brooks2015.R
├── docs
├── 404.html
├── LICENSE-text.html
├── LICENSE.html
├── articles
│ ├── index.html
│ ├── tutorial.html
│ └── tutorial_files
│ │ ├── figure-html
│ │ ├── unnamed-chunk-11-1.png
│ │ ├── unnamed-chunk-17-1.png
│ │ ├── unnamed-chunk-20-1.png
│ │ ├── unnamed-chunk-23-1.png
│ │ ├── unnamed-chunk-24-1.png
│ │ └── unnamed-chunk-8-1.png
│ │ └── header-attrs-2.9
│ │ └── header-attrs.js
├── authors.html
├── bootstrap-toc.css
├── bootstrap-toc.js
├── docsearch.css
├── docsearch.js
├── index.html
├── link.svg
├── news
│ └── index.html
├── pkgdown.css
├── pkgdown.js
├── pkgdown.yml
└── reference
│ ├── Rplot001.png
│ ├── anorm.html
│ ├── as_matrix.html
│ ├── bootrep_center.html
│ ├── build_matrix.html
│ ├── calibrate.html
│ ├── center.html
│ ├── center_elts.html
│ ├── close_elts.html
│ ├── clr.html
│ ├── compute_ratios.html
│ ├── cooccurrence.html
│ ├── corner.html
│ ├── estimate_bias.html
│ ├── gm.html
│ ├── gm_abs.html
│ ├── gm_mean.html
│ ├── gm_range.html
│ ├── gm_sd.html
│ ├── import_phyloseq.html
│ ├── index.html
│ ├── log_center_proj.html
│ ├── log_center_rss.html
│ ├── logit.html
│ ├── mutate_by.html
│ ├── odds.html
│ ├── pairwise_ratios.html
│ ├── perturb.html
│ ├── proj_mat.html
│ └── xydist.html
├── inst
└── extdata
│ ├── brooks2015-actual.csv
│ ├── brooks2015-observed.csv
│ └── brooks2015-sample-data.csv
├── man
├── anorm.Rd
├── as_matrix.Rd
├── bootrep_center.Rd
├── build_matrix.Rd
├── calibrate.Rd
├── center.Rd
├── center_elts.Rd
├── close_elts.Rd
├── clr.Rd
├── compute_ratios.Rd
├── cooccurrence.Rd
├── corner.Rd
├── estimate_bias.Rd
├── gm.Rd
├── gm_abs.Rd
├── gm_mean.Rd
├── gm_range.Rd
├── gm_sd.Rd
├── import_phyloseq.Rd
├── log_center_proj.Rd
├── log_center_rss.Rd
├── logit.Rd
├── mean_efficiency.Rd
├── metacal-package.Rd
├── mutate_by.Rd
├── odds.Rd
├── pairwise_ratios.Rd
├── perturb.Rd
├── proj_mat.Rd
└── xydist.Rd
├── tests
├── testthat.R
└── testthat
│ ├── test-calibrate.R
│ ├── test-center.R
│ ├── test-ratios.R
│ └── test-utilities.R
└── vignettes
└── tutorial.Rmd
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^metacal\.Rproj$
2 | ^\.Rproj\.user$
3 | ^LICENSE\.md$
4 | ^README\.Rmd$
5 | ^cran-comments\.md$
6 | ^\.github$
7 | ^data-raw$
8 | ^docs$
9 | ^vignettes/data$
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | inst/doc
3 | /vignettes/data/
4 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: metacal
2 | Title: Bias estimation and calibration for metagenomics experiments
3 | Version: 0.2.0.9010
4 | Authors@R:
5 | person(given = "Michael",
6 | family = "McLaren",
7 | role = c("aut", "cre"),
8 | email = "m.mclaren42@gmail.com",
9 | comment = c(ORCID = "0000-0003-1575-473X"))
10 | Description: The metacal package provides tools for bias estimation and
11 | calibration in marker-gene and metagenomics sequencing experiments, using
12 | the methods developed in https://elifesciences.org/articles/46923.
13 | URL: https://mikemc.github.io/metacal, https://github.com/mikemc/metacal
14 | BugReports: https://github.com/mikemc/metacal/issues
15 | License: MIT + file LICENSE
16 | Imports:
17 | dplyr,
18 | igraph,
19 | lifecycle,
20 | magrittr,
21 | MASS,
22 | phyloseq,
23 | purrr,
24 | rlang,
25 | tibble,
26 | tidyr,
27 | useful
28 | Suggests:
29 | testthat,
30 | roxygen2,
31 | knitr,
32 | rmarkdown,
33 | tidyverse,
34 | cowplot,
35 | ggbeeswarm,
36 | here,
37 | readr,
38 | sessioninfo
39 | Encoding: UTF-8
40 | LazyData: true
41 | Roxygen: list(markdown = TRUE)
42 | RoxygenNote: 7.1.2
43 | VignetteBuilder: knitr
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | YEAR: 2019
2 | COPYRIGHT HOLDER: Michael R. McLaren
3 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2019 Michael R. McLaren
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | S3method(calibrate,matrix)
4 | S3method(calibrate,otu_table)
5 | S3method(calibrate,phyloseq)
6 | S3method(coef,mc_bias_fit)
7 | S3method(estimate_bias,matrix)
8 | S3method(estimate_bias,otu_table)
9 | S3method(estimate_bias,phyloseq)
10 | S3method(fitted,mc_bias_fit)
11 | S3method(mean_efficiency,matrix)
12 | S3method(mean_efficiency,mc_bias_fit)
13 | S3method(mean_efficiency,otu_table)
14 | S3method(mean_efficiency,phyloseq)
15 | S3method(pairwise_ratios,default)
16 | S3method(pairwise_ratios,matrix)
17 | S3method(pairwise_ratios,otu_table)
18 | S3method(pairwise_ratios,phyloseq)
19 | S3method(perturb,matrix)
20 | S3method(perturb,mc_bias_fit)
21 | S3method(perturb,otu_table)
22 | S3method(perturb,phyloseq)
23 | S3method(print,mc_bias_fit)
24 | S3method(print,mc_bias_fit_summary)
25 | S3method(residuals,mc_bias_fit)
26 | S3method(summary,mc_bias_fit)
27 | export(anorm)
28 | export(as_matrix)
29 | export(bootrep_center)
30 | export(build_matrix)
31 | export(calibrate)
32 | export(center)
33 | export(center_elts)
34 | export(close_elts)
35 | export(clr)
36 | export(compute_ratios)
37 | export(cooccurrence_components)
38 | export(cooccurrence_matrix)
39 | export(cooccurrence_network)
40 | export(corner)
41 | export(estimate_bias)
42 | export(gm)
43 | export(gm_abs)
44 | export(gm_mean)
45 | export(gm_range)
46 | export(gm_sd)
47 | export(logit)
48 | export(mean_efficiency)
49 | export(mutate_by)
50 | export(odds)
51 | export(pairwise_ratios)
52 | export(perturb)
53 | export(xydist)
54 | importClassesFrom(phyloseq,otu_table)
55 | importClassesFrom(phyloseq,phyloseq)
56 | importFrom(magrittr,"%>%")
57 | importFrom(phyloseq,"otu_table<-")
58 | importFrom(phyloseq,"sample_data<-")
59 | importFrom(phyloseq,nsamples)
60 | importFrom(phyloseq,ntaxa)
61 | importFrom(phyloseq,otu_table)
62 | importFrom(phyloseq,prune_taxa)
63 | importFrom(phyloseq,sample_data)
64 | importFrom(phyloseq,sample_names)
65 | importFrom(phyloseq,sample_sums)
66 | importFrom(phyloseq,t)
67 | importFrom(phyloseq,taxa_are_rows)
68 | importFrom(phyloseq,taxa_names)
69 | importFrom(useful,corner)
70 |
--------------------------------------------------------------------------------
/NEWS.md:
--------------------------------------------------------------------------------
1 | # metacal (development version)
2 |
3 | * `build_matrix()` now works correctly on grouped tibbles
4 |
5 | * `pairwise_ratios()` now correctly handles phyloseq objects with just 1 sample
6 | or taxon, and is properly exported
7 |
8 | * `estimate_bias()` now allows `observed` to have extra samples and taxa not in `actual`, by automatically subsetting to those in `actual`
9 |
10 | * `calibrate()` now allows `bias` to be an 'mc_bias_fit' object
11 |
12 | * Add `mean_efficiency()` to compute mean efficiency of control or new samples
13 |
14 | * `calibrate()` now (by default) computes and adds the mean efficiency to the sample data
15 |
16 | # metacal 0.2.0
17 |
18 | ## New features
19 |
20 | ### New estimation and calibration functions
21 |
22 | `estimate_bias()` and `calibrate()` provide easy-to-use high-level interfaces to the original metacal bias-estimation and calibration method.
23 | Their use is illustrated in the new tutorial.
24 |
25 | ### New utility functions
26 |
27 | * `pairwise_ratios()` allows computing ratios between pairs of taxa and/or samples.
28 |
29 | * `perturb()` applies a compositional perturbation to all observations in an abundance matrix (or phyloseq object).
30 |
31 | ### Support for phyloseq objects
32 |
33 | The new functions `estimate_bias()`, `perturb()`, `calibrate()`, and `pairwise_ratios()` all work with objects from the [phyloseq](https://joey711.github.io/phyloseq/) package as well as plain matrices.
34 | Phyloseq is now a required dependency, though may be made optional in the future.
35 |
36 | ### New tutorial
37 |
38 | The [new tutorial](https://mikemc.github.io/metacal/articles/tutorial.html) demonstrates the new estimation and calibration functions on a new dataset from [Leopold and Busby (2020)](https://doi.org/10.1016/j.cub.2020.06.011).
39 |
40 | ## Minor fixes
41 |
42 | * Fixed failure of `coocurrence_matrix()` when names were missing (#5).
43 |
44 | # metacal 0.1.0
45 |
46 | Direct implementation of the methods described in [McLaren MR, Willis AD, Callahan BJ (2019)](https://elifesciences.org/articles/46923) and used for [the analysis of that paper](https://github.com/mikemc/mgs-bias-manuscript).
47 |
--------------------------------------------------------------------------------
/R/bias-helpers.R:
--------------------------------------------------------------------------------
1 | # Functions that can help understand bias estimates
2 |
3 | # Taxon co-occurrence network -------------------------------------------------
4 |
5 | #' Taxon co-occurrence network
6 | #'
7 | #' Functions for probing the taxon co-occurrence network, used for checking if
8 | #' the bias estimated by the `center()` function is fully-determined.
9 | #'
10 | #' The edges are weighted by the number of samples the pair of taxa co-occur in
11 | #' and so provide some information about the precision of the pairwise bias
12 | #' estimate.
13 | #'
14 | #' @param mat A compositional error matrix
15 | #' @param all Whether to include taxa that aren't in any multi-taxon samples
16 | #' @param enframe Whether to "enframe" the returned vector
17 | #'
18 | #' @name cooccurrence
19 | NULL
20 |
21 | #' @describeIn cooccurrence Adjacency matrix of the co-occurrence network
22 | #' @export
23 | cooccurrence_matrix <- function(mat, all = TRUE) {
24 | # To compute the number of times each pair of taxa cooccur, we leverage the
25 | # `compute_ratios()` function. Doing so requires that the samples (rows of
26 | # `mat`) and the taxa (cols of `mat`) have names.
27 | if (is.null(rownames(mat)))
28 | rownames(mat) <- paste0("S", seq(nrow(mat)))
29 | if (is.null(colnames(mat)))
30 | colnames(mat) <- paste0("T", seq(ncol(mat)))
31 | ratios <- mat %>%
32 | tibble::as_tibble(rownames = "Sample") %>%
33 | tidyr::gather("Taxon", "Value", -Sample) %>%
34 | compute_ratios()
35 | if (!all) {
36 | ratios <- dplyr::filter(ratios, !is.na(Value))
37 | }
38 | adj_mat <- ratios %>%
39 | dplyr::filter(Taxon.x != Taxon.y) %>%
40 | dplyr::group_by(Taxon.x, Taxon.y) %>%
41 | dplyr::summarize(n = sum(!is.na(Value))) %>%
42 | dplyr::ungroup() %>%
43 | build_matrix(Taxon.x, Taxon.y, n, 0)
44 | adj_mat
45 | }
46 |
47 | #' @describeIn cooccurrence Co-occurrence network as an `igraph` object
48 | #' @export
49 | cooccurrence_network <- function(mat, all = TRUE) {
50 | adj_mat <- cooccurrence_matrix(mat, all = all)
51 | igraph::graph.adjacency(adj_mat, mode = "undirected", weighted = TRUE)
52 | }
53 |
54 | #' @describeIn cooccurrence Connected components of the co-occurrence network
55 | #' @export
56 | cooccurrence_components <- function(mat, all = TRUE, enframe = FALSE) {
57 | g <- cooccurrence_network(mat, all = all)
58 | components <- igraph::components(g)$membership
59 |
60 | if (enframe)
61 | components <- tibble::enframe(components, "Taxon", "Component")
62 |
63 | components
64 | }
65 |
66 | # TODO: Add example showing usage. Include plotting the graph with the edge
67 | # weights shown
68 | # TODO: Allow a matrix of the actual composition to be passed instead of the
69 | # error matrix
70 |
--------------------------------------------------------------------------------
/R/calibrate.R:
--------------------------------------------------------------------------------
1 | # perturb ---------------------------------------------------------------------
2 |
3 | #' Compositionally perturb a relative-abundance matrix
4 | #'
5 | #' The perturbation of two compositional vectors `v` and `y` is given (up to
6 | #' compositional equivalence) by the elementwise product `v * y`.
7 | #'
8 | #' Let `w = v * y`, where `v` is a row or column of `x`. The normalization
9 | #' options specified by the `norm` argument are
10 | #'
11 | #' * "close" Return the compositional closure of w into the simplex,
12 | #' `w / sum(w)`
13 | #' * "keep" Keep the same total abundance as the original vector by returning
14 | #' `w * sum(v) / sum(w)`
15 | #' * "none" Return `w` without any normalization
16 | #'
17 | #' If `y` is named, then the names must agree with the taxa names in `x` and
18 | #' will be used to reorder `y` to match the taxa order in `x`.
19 | #'
20 | #' @param x An abundance matrix or phyloseq object containing one
21 | #' @param y A numeric vector with which to perturb the observations in x
22 | #' @param margin Matrix margin that corresponds to observations (samples);
23 | #' `1` for rows, `2` for columns
24 | #' @param norm String specifying how to normalize the perturbed observations;
25 | #' see Details.
26 | #'
27 | #' @seealso [calibrate()]
28 | #'
29 | #' @rdname perturb
30 | #' @export
31 | perturb <- function(x, y, ...) {
32 | UseMethod("perturb")
33 | }
34 |
35 | #' @rdname perturb
36 | #' @method perturb matrix
37 | #' @export
38 | perturb.matrix <- function(x, y, margin, norm = "close") {
39 | stopifnot(margin %in% 1:2)
40 | stopifnot(norm %in% c("close", "keep", "none"))
41 | taxa_margin <- setdiff(1:2, margin)
42 | stopifnot(identical(dim(x)[[taxa_margin]], length(y)))
43 |
44 | # Align taxa
45 | if (!is.null(names(y))) {
46 | if (!setequal(dimnames(x)[[taxa_margin]], names(y)))
47 | stop("Taxa names in `x` and `y` do not match")
48 | y <- y[dimnames(x)[[taxa_margin]]]
49 | }
50 |
51 | if (margin == 2) {
52 | z <- diag(y) %*% x
53 | rownames(z) <- rownames(x)
54 | if (norm %in% c("close", "keep"))
55 | z <- sweep(z, 2, colSums(z), `/`)
56 | if (norm == "keep")
57 | z <- sweep(z, 2, colSums(x), `*`)
58 | } else {
59 | z <- x %*% diag(y)
60 | colnames(z) <- colnames(x)
61 | if (norm %in% c("close", "keep"))
62 | z <- sweep(z, 1, rowSums(z), `/`)
63 | if (norm == "keep")
64 | z <- sweep(z, 1, rowSums(x), `*`)
65 | }
66 |
67 | z
68 | }
69 |
70 | #' @rdname perturb
71 | #' @method perturb otu_table
72 | #' @export
73 | perturb.otu_table <- function(x, y, norm = "close") {
74 | margin <- 1 + taxa_are_rows(x)
75 | z <- perturb.matrix(as(x, "matrix"), y, margin = margin, norm = norm)
76 | otu_table(z, taxa_are_rows = taxa_are_rows(x))
77 | }
78 |
79 | #' @rdname perturb
80 | #' @method perturb phyloseq
81 | #' @export
82 | perturb.phyloseq <- function(x, y, norm = "close") {
83 | otu_table(x) <- perturb(otu_table(x), y, norm = norm)
84 | x
85 | }
86 |
87 | #' @rdname perturb
88 | #' @method perturb mc_bias_fit
89 | #' @export
90 | perturb.mc_bias_fit <- function(x, y) {
91 | stopifnot(identical(length(x$estimate), length(y)))
92 | x$estimate <- x$estimate * y
93 | if (!is.null(x$bootreps))
94 | x$bootreps <- sweep(x$bootreps, 2, y, `*`)
95 | x
96 | }
97 |
98 | # calibrate -------------------------------------------------------------------
99 |
100 | #' Calibrate a relative-abundance matrix by a bias vector
101 | #'
102 | #' Calibration via the simple deterministic procedure described in McLaren,
103 | #' Willis, and Callahan (2019), simply involved dividing the observed vector of
104 | #' relative abundances by the estimated bias vector and (optionally)
105 | #' normalizing the result to sum to 1 or some other chosen value.
106 | #'
107 | #' Normalization options specified by `norm`:
108 | #'
109 | #' * "close": Divide the calibrated abundance vector by its sum, so that it
110 | #' sums to 1
111 | #' * "keep": Keep the same total abundance as the original observation
112 | #' * "none": Return the calibrated abundances without any normalization
113 | #'
114 | #' If `bias` is named, then the names must agree with the taxa names in
115 | #' `observed` and will be used to reorder `bias` to match the taxa order in
116 | #' `observed`.
117 | #'
118 | #' @param observed An abundance matrix or phyloseq object containing one
119 | #' @param bias A numeric vector of relative efficiencies or an object of class
120 | #' 'mc_bias_fit' (from which efficiencies will be extracted)
121 | #' @param margin Matrix margin that corresponds to observations (samples);
122 | #' `1` for rows, `2` for columns
123 | #' @param norm String specifying how to normalize the calibrated observations;
124 | #' see Details.
125 | #' @param mean_name Character vector or NULL. Name of the column in the sample
126 | #' data in which to store the mean efficiency, or NULL to skip.
127 | #'
128 | #' @seealso [perturb()] [estimate_bias()]
129 | #'
130 | #' @rdname calibrate
131 | #' @export
132 | calibrate <- function(observed, bias, ...) {
133 | UseMethod("calibrate")
134 | }
135 |
136 | #' @rdname calibrate
137 | #' @method calibrate matrix
138 | #' @export
139 | calibrate.matrix <- function(observed, bias, margin, norm = "close") {
140 | if (inherits(bias, 'mc_bias_fit'))
141 | bias <- coef(bias)
142 | perturb.matrix(observed, 1 / bias, margin = margin, norm = norm)
143 | }
144 |
145 | #' @rdname calibrate
146 | #' @method calibrate otu_table
147 | #' @export
148 | calibrate.otu_table <- function(observed, bias, norm = "close") {
149 | if (inherits(bias, 'mc_bias_fit'))
150 | bias <- coef(bias)
151 | # The otu-table method will try to subset to the shared taxa in observed and
152 | # bias
153 | if (!identical(ntaxa(observed), length(bias))) {
154 | if (is.null(names(bias)))
155 | stop("`bias` must be named if `!identical(ntaxa(observed), length(bias))`")
156 | taxa <- intersect(taxa_names(observed), names(bias))
157 | if (!length(taxa) > 0)
158 | stop("`intersect(taxa_names(observed), names(bias))` is empty")
159 | observed <- phyloseq::prune_taxa(taxa, observed)
160 | bias <- bias[taxa]
161 | } # else: perturb() will make sure the taxa names match the names in bias
162 | perturb.otu_table(observed, 1 / bias, norm = norm)
163 | }
164 |
165 | #' @rdname calibrate
166 | #' @method calibrate phyloseq
167 | #' @export
168 | calibrate.phyloseq <- function(observed,
169 | bias,
170 | norm = "close",
171 | mean_name = ".mean_efficiency") {
172 | otu_table(observed) <- calibrate(otu_table(observed), bias, norm = norm)
173 | if (!is.null(mean_name) & !is.null(phyloseq::access(observed, 'sam_data'))) {
174 | if (!is.character(mean_name))
175 | stop('`mean_name` must be a character vector')
176 | me <- mean_efficiency(
177 | observed,
178 | bias,
179 | # `observed` is now calibrated so type = 'actual'
180 | type = 'actual'
181 | )
182 | sample_data(observed)[, mean_name] <- me
183 | }
184 | observed
185 | }
186 |
--------------------------------------------------------------------------------
/R/math.R:
--------------------------------------------------------------------------------
1 | # TODO
2 | # - check trim usage
3 | # - add documentation
4 | # - add tests
5 |
6 | # Element-wise functions ------------------------------------------------------
7 |
8 | #' Odds of the probability vector x
9 | #'
10 | #' @export
11 | odds <- function (x) {
12 | x / (1-x)
13 | }
14 |
15 | #' Logit (log-odds) of the probability vector x
16 | #'
17 | #' @export
18 | logit <- function (x) {
19 | log(x) - log(1-x)
20 | }
21 |
22 | # Summaries of relative abundance vectors--------------------------------------
23 |
24 | #' Geometric mean of x
25 | #'
26 | #' @export
27 | gm_mean <- function(x, na.rm = FALSE) {
28 | exp(mean(log(x), na.rm = na.rm))
29 | }
30 |
31 | #' Geometric standard deviation of x
32 | #'
33 | #' Note, uses denominator n-1
34 | #'
35 | #' @export
36 | gm_sd <- function(x, na.rm = FALSE) {
37 | exp(sd(log(x), na.rm = na.rm))
38 | }
39 |
40 | #' Geometric range of x
41 | #'
42 | #' @export
43 | gm_range <- function(x) {
44 | max(x) / min(x)
45 | }
46 |
47 | #' Geometric absolute value of x
48 | #'
49 | #' @export
50 | gm_abs <- function(x) {
51 | exp(abs(log(x)))
52 | }
53 |
54 | #' Geometric (multiplicative) version of the function f
55 | #'
56 | #' @export
57 | gm <- function(f) {
58 | function (x, ...) exp(f(log(x), ...))
59 | }
60 |
61 | # Transformations for relative abundance vectors ------------------------------
62 |
63 | #' Close the elements of x to proportions
64 | #'
65 | #' @export
66 | close_elts <- function (x, na.rm = FALSE) {
67 | x / sum(x, na.rm = na.rm)
68 | }
69 |
70 | #' Geometrically center the elements of x
71 | #'
72 | #' @export
73 | center_elts <- function (x, na.rm = FALSE) {
74 | exp(log(x) - mean(log(x), na.rm = na.rm))
75 | }
76 |
77 | #' Compute the centered log-ratio transform of x
78 | #'
79 | #' @param x Vector of abundances.
80 | #' @param base Base for logarithm
81 | #'
82 | #' @export
83 | clr <- function(x, base = exp(1), na.rm = FALSE) {
84 | log(x, base = base) - mean(log(x, base = base), na.rm = na.rm)
85 | }
86 |
87 | # Distance / dissimilarity between samples ------------------------------------
88 |
89 | #' Distance or dissimilarity between relative abundance vectors x and y
90 | #'
91 | #' @param method Distance/dissimilarity measure.
92 | #' @param trim Should x and y be reduced to their common positive elements
93 | #' before computing the Aitchison distance (otherwise, the distance will be
94 | #' Inf).
95 | #'
96 | #' method == "aitchison" -> Aitchison distance
97 | #' method == "bray" -> Bray-Curtis dissimilarity between x and y. Note,
98 | #' converts x and y to proportions before computing.
99 | #'
100 | #' @export
101 | # Bray method is equal to `vegan::vegdist(rbind(close_elts(x), close_elts(y)))[1]`
102 | xydist <- function(x, y, method = "aitchison", trim = FALSE) {
103 | if (length(x) != length(y)) {
104 | stop("x and y have different lengths")
105 | }
106 | if (method == "aitchison") {
107 | if (trim) {
108 | idx <- (x > 0) & (y > 0)
109 | x <- x[idx]
110 | y <- y[idx]
111 | }
112 | sqrt( sum( (clr(x) - clr(y))^2 ) )
113 | } else if (method == "bray") {
114 | x <- close_elts(x)
115 | y <- close_elts(y)
116 | Cxy <- purrr::map2_dbl(x, y, min) %>% sum
117 | 1 - Cxy
118 | }
119 | }
120 |
121 | #' Aitchison norm of x
122 | #'
123 | #' @param na.rm Whether to remove NAs and NaNs before calculating.
124 | #'
125 | #' @export
126 | anorm <- function (x, na.rm = FALSE) {
127 | x %>%
128 | clr(., na.rm = na.rm) %>%
129 | {.^2} %>%
130 | sum(., na.rm = na.rm) %>%
131 | sqrt(.)
132 | }
133 |
--------------------------------------------------------------------------------
/R/mean_efficiency.R:
--------------------------------------------------------------------------------
1 | #' Compute sample mean efficiencies
2 | #'
3 | #' Given a matrix of 'observed' or 'actual' (e.g. calibrated) abundance
4 | #' profiles and a vector of relative efficiencies, compute the estimated mean
5 | #' efficiency for each sample.
6 | #'
7 | #' The mean efficiency of a sample equals `weighted.mean(bias, y)`, where
8 | #' `bias` is the vector of taxa efficiencies and `y` is the vector of taxa
9 | #' proportions.
10 | #'
11 | #' The `type %in% c('actual', 'observed')` specifies whether the data is
12 | #' 'actual' (i.e. nominally known or calibrated abundances) or 'observed' (i.e.
13 | #' uncalibrated) data. 'Observed' data is calibrated to determine `y` prior to
14 | #' computing the mean efficiency.
15 | #'
16 | #' If `x` is an `mc_bias_fit` object, then the efficiencies will be extracted
17 | #' with `coef(x)`. An abundance matrix can optionally be given with `newdata`;
18 | #' otherwise, the mean efficiency will be computed for the control samples in
19 | #' `x`.
20 | #'
21 | #' `r lifecycle::badge("experimental")`
22 | #'
23 | #' @param x A matrix, a phyloseq object with an otu_table, or an object of
24 | #' class 'mc_bias_fit'
25 | #' @param bias A (possibly named) numeric vector of relative efficiencies
26 | #' @param newdata NULL or an abundance matrix
27 | #' @param margin The margin containing the samples (observations)
28 | #' @param type 'actual' or 'observed', indicating the type of abundance
29 | #' profiles in the matrix `x` or `newdata`
30 | #'
31 | #' @seealso [estimate_bias()]
32 | #'
33 | #' @rdname mean_efficiency
34 | #' @export
35 | # mean_efficiency <- function(bias, actual, observed, margin) {
36 | # UseMethod("mean_efficiency")
37 | # }
38 | mean_efficiency <- function(x, ...) {
39 | UseMethod("mean_efficiency")
40 | }
41 |
42 | #' @rdname mean_efficiency
43 | #' @method mean_efficiency matrix
44 | #' @export
45 | mean_efficiency.matrix <- function(x,
46 | bias,
47 | margin,
48 | type) {
49 | # First, get to point where `x` is a matrix with the 'actual' (unbiased)
50 | # profiles with samples as rows, and the taxa (columns) are properly aligned
51 | # with `bias`.
52 | if (!margin %in% 1:2)
53 | stop("`margin` must be 1 or 2.")
54 | if (margin == 2) {
55 | x <- t(x)
56 | margin <- 1
57 | }
58 | taxa_margin <- 2
59 | if (type == 'observed') {
60 | # Note: Consider allowing taxa to be dropped from 'observed' with a
61 | # message, in the case where 'bias' is named.
62 | stopifnot(identical(dim(x)[[taxa_margin]], length(bias)))
63 | x <- calibrate(x, bias, margin = margin, norm = 'none')
64 | } else if (type != 'actual') {
65 | stop("`type` must be 'actual' or 'observed'.")
66 | }
67 | # TODO: Add ability to extract efficiencies from mc_bias_fit objects
68 | # Align taxa order between x and bias
69 | if (!is.null(names(bias))) {
70 | if (!setequal(dimnames(x)[[taxa_margin]], names(bias)))
71 | stop("Taxa names in `bias` and `actual` do not match")
72 | bias <- bias[dimnames(x)[[taxa_margin]]]
73 | }
74 |
75 | # Can also do the same thing slightly slower with weighted.mean()
76 | # apply(bias$actual, 1, function(x) weighted.mean(bias, x))
77 |
78 | x %>%
79 | # normalize to proportions
80 | sweep(., 1, rowSums(.), `/`) %>%
81 | # multiply taxa by their efficiency
82 | perturb(bias, margin = 1, norm = 'none') %>%
83 | # sum up within samples
84 | rowSums
85 | }
86 |
87 | #' @rdname mean_efficiency
88 | #' @method mean_efficiency otu_table
89 | #' @export
90 | mean_efficiency.otu_table <- function(x, bias, type) {
91 | mean_efficiency(
92 | as(x, "matrix"),
93 | bias,
94 | margin = 1 + taxa_are_rows(x),
95 | type = type
96 | )
97 | }
98 |
99 | #' @rdname mean_efficiency
100 | #' @method mean_efficiency phyloseq
101 | #' @export
102 | mean_efficiency.phyloseq <- function(x, bias, type) {
103 | mean_efficiency(otu_table(x), bias, type = type)
104 | }
105 |
106 | #' @rdname mean_efficiency
107 | #' @method mean_efficiency mc_bias_fit
108 | #' @export
109 | mean_efficiency.mc_bias_fit <- function(x,
110 | newdata = NULL,
111 | margin = NULL,
112 | type = NULL) {
113 | bias = coef(x)
114 |
115 | if (is.null(newdata)) {
116 | stopifnot(is.null(margin))
117 | x <- x$actual
118 | type <- 'actual'
119 | margin <- 1
120 | } else {
121 | if (! type %in% c('actual', 'observed')) {
122 | stop("`type` must be 'actual' or 'observed'.")
123 | }
124 | if (! margin %in% 1:2) {
125 | stop("`margin` must be 1 or 2.")
126 | }
127 | }
128 |
129 | mean_efficiency(
130 | x = x,
131 | bias = bias,
132 | type = type,
133 | margin = margin
134 | )
135 | }
136 |
137 |
--------------------------------------------------------------------------------
/R/metacal-package.R:
--------------------------------------------------------------------------------
1 | #' @keywords internal
2 | "_PACKAGE"
3 |
4 | ## usethis namespace: start
5 | ## usethis namespace: end
6 | NULL
7 |
--------------------------------------------------------------------------------
/R/metacal.R:
--------------------------------------------------------------------------------
1 | #' Import phyloseq classes and functions
2 | #'
3 | #' @name import_phyloseq
4 | #' @importClassesFrom phyloseq otu_table phyloseq
5 | #' @importFrom phyloseq otu_table otu_table<- t taxa_are_rows taxa_names
6 | #' sample_names ntaxa nsamples sample_sums prune_taxa
7 | #' sample_data sample_data<-
8 | NULL
9 |
--------------------------------------------------------------------------------
/R/utilities.R:
--------------------------------------------------------------------------------
1 | #' @name corner
2 | #' @importFrom useful corner
3 | #' @export
4 | useful::corner
5 |
6 | # Helpers for working with "tidy" microbiome data -----------------------------
7 |
8 | #' Mutate within groups
9 | #'
10 | #' @export
11 | mutate_by <- function(.data, group_vars, ...) {
12 | gvs <- rlang::enquos(group_vars)
13 | .data %>%
14 | dplyr::group_by_at(vars(!!!gvs)) %>%
15 | dplyr::mutate(...) %>%
16 | dplyr::ungroup()
17 | }
18 |
19 | #' Create a matrix from columns of a tidy data frame
20 | #'
21 | #' Note: Setting `fill` will replace NAs and NaNs, along with elements
22 | #' corresponding to missing rows, with the value of `fill`.
23 | #'
24 | #' @param .data A data frame with columns `rows`, `cols`, and `elts`.
25 | #' @param rows Column that will become the rownames of the matrix.
26 | #' @param cols Column that will become the colnames of the matrix.
27 | #' @param elts Column that will become the matrix elements.
28 | #' @param fill Value to use for missing elements.
29 | #' @export
30 | build_matrix <- function(.data, rows, cols, elts, fill = NULL) {
31 | rows <- rlang::enquo(rows)
32 | cols <- rlang::enquo(cols)
33 | elts <- rlang::enquo(elts)
34 | tb <- .data %>%
35 | dplyr::ungroup() %>%
36 | dplyr::select(!!rows, !!cols, !!elts)
37 | if (!is.null(fill)) {
38 | tb <- tb %>% tidyr::complete(!!rows, !!cols,
39 | fill = rlang::list2(!!elts := fill))
40 | }
41 | tb <- tb %>% tidyr::pivot_wider(names_from = !!cols, values_from = !!elts)
42 | mat <- tb %>% dplyr::select(-!!rows) %>% as("matrix")
43 | rownames(mat) <- tb %>% dplyr::pull(!!rows)
44 | mat
45 | }
46 |
47 | #' Coerce a (wide) data frame to a matrix
48 | #'
49 | #' @export
50 | as_matrix <- function(.data, rownames = NULL) {
51 | rownames <- rlang::enquo(rownames)
52 | if (rlang::quo_is_null(rownames)) {
53 | mat <- .data %>% as("matrix")
54 | } else {
55 | mat <- .data %>% dplyr::select(-!!rownames) %>% as("matrix")
56 | rownames(mat) <- .data %>% dplyr::pull(!!rownames)
57 | }
58 | mat
59 | }
60 |
--------------------------------------------------------------------------------
/R/utils-pipe.R:
--------------------------------------------------------------------------------
1 | # Import magrittr pipe for internal use
2 |
3 | #' @importFrom magrittr %>%
4 | NULL
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # metacal
2 |
3 | [](https://zenodo.org/badge/latestdoi/192036279)
4 |
5 | The metacal package provides tools for bias estimation and calibration in
6 | marker-gene and metagenomics sequencing experiments. It implements the methods
7 | described in [McLaren MR, Willis AD, Callahan BJ
8 | (2019)](https://elifesciences.org/articles/46923) and is used for the
9 | analysis associated with that manuscript, available at the [manuscript's
10 | repository](https://github.com/mikemc/mgs-bias-manuscript).
11 |
12 | ## Installation
13 |
14 | Install the development version of metacal from from GitHub,
15 |
16 | ``` r
17 | # install.packages("devtools")
18 | devtools::install_github("mikemc/metacal")
19 | ```
20 |
21 | ## Usage
22 |
23 | See the [package tutorial](https://mikemc.github.io/metacal/articles/tutorial.html)
24 | for a demonstration of how to estimate bias from control samples with known
25 | composition (i.e., mock community samples), and how to calibrate the relative
26 | abundances in unknown samples of the taxa that were in the controls.
27 |
28 | The primary utility of this package is quantitatively estimating the bias of
29 | protocols in quality control experiments, where samples with known composition
30 | are measured or samples with unknown composition are measured by multiple
31 | protocols.
32 |
33 | It is currently not possible to calibrate the composition of a natural
34 | community without making strong and untested assumptions about bias being the
35 | same for constructed and natural samples and about the efficiencies of taxa not
36 | in the controls (e.g., approximating them by that of the closest relative or
37 | the average efficiency). For this and other limitations described in the
38 | Discussion of our manuscript, calibration as a practical method to obtain
39 | quantitatively accurate composition measurements is not currently feasible
40 | using this or any package. However, calibration using a hypothesized bias
41 | (perhaps partially informed by experimental measurement) can still be useful to
42 | analyze the sensitivity of downstream results to bias, a use case we will
43 | illustrate in a future vignette.
44 |
--------------------------------------------------------------------------------
/_pkgdown.yml:
--------------------------------------------------------------------------------
1 | reference:
2 | - title: Bias estimation and calibration
3 | - contents:
4 | - estimate_bias
5 | - calibrate
6 | - starts_with("cooccurrence")
7 | - title: Compositional-data computations
8 | - contents:
9 | - perturb
10 | - pairwise_ratios
11 | - compute_ratios
12 | - center
13 | - bootrep_center
14 | - center_elts
15 | - close_elts
16 | - clr
17 | - logit
18 | - odds
19 | - anorm
20 | - xydist
21 | - starts_with("gm")
22 | - title: Data-frame manipulation and coercion
23 | - contents:
24 | - as_matrix
25 | - build_matrix
26 | - mutate_by
27 |
--------------------------------------------------------------------------------
/docs/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Page not found (404) • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
127 |
128 | Content not found. Please use links in the navbar.
129 |
130 |
131 |
132 |
137 |
138 |
139 |
140 |
141 |
142 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/docs/LICENSE-text.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | License • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
127 |
128 |
YEAR: 2019
129 | COPYRIGHT HOLDER: Michael R. McLaren
130 |
131 |
132 |
133 |
134 |
139 |
140 |
141 |
142 |
143 |
144 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/docs/LICENSE.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MIT License • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
127 |
128 |
129 |
130 |
Copyright (c) 2019 Michael R. McLaren
131 |
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
132 |
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
133 |
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
134 |
135 |
136 |
137 |
138 |
143 |
144 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/articles/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Articles • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
127 |
128 |
129 |
All vignettes
130 |
131 |
132 |
133 | Tutorial
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/docs/articles/tutorial_files/figure-html/unnamed-chunk-11-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikemc/metacal/f56792d02bd722ab16c1ed215b07c1187829a226/docs/articles/tutorial_files/figure-html/unnamed-chunk-11-1.png
--------------------------------------------------------------------------------
/docs/articles/tutorial_files/figure-html/unnamed-chunk-17-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikemc/metacal/f56792d02bd722ab16c1ed215b07c1187829a226/docs/articles/tutorial_files/figure-html/unnamed-chunk-17-1.png
--------------------------------------------------------------------------------
/docs/articles/tutorial_files/figure-html/unnamed-chunk-20-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikemc/metacal/f56792d02bd722ab16c1ed215b07c1187829a226/docs/articles/tutorial_files/figure-html/unnamed-chunk-20-1.png
--------------------------------------------------------------------------------
/docs/articles/tutorial_files/figure-html/unnamed-chunk-23-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikemc/metacal/f56792d02bd722ab16c1ed215b07c1187829a226/docs/articles/tutorial_files/figure-html/unnamed-chunk-23-1.png
--------------------------------------------------------------------------------
/docs/articles/tutorial_files/figure-html/unnamed-chunk-24-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikemc/metacal/f56792d02bd722ab16c1ed215b07c1187829a226/docs/articles/tutorial_files/figure-html/unnamed-chunk-24-1.png
--------------------------------------------------------------------------------
/docs/articles/tutorial_files/figure-html/unnamed-chunk-8-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikemc/metacal/f56792d02bd722ab16c1ed215b07c1187829a226/docs/articles/tutorial_files/figure-html/unnamed-chunk-8-1.png
--------------------------------------------------------------------------------
/docs/articles/tutorial_files/header-attrs-2.9/header-attrs.js:
--------------------------------------------------------------------------------
1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to
2 | // be compatible with the behavior of Pandoc < 2.8).
3 | document.addEventListener('DOMContentLoaded', function(e) {
4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child");
5 | var i, h, a;
6 | for (i = 0; i < hs.length; i++) {
7 | h = hs[i];
8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6
9 | a = h.attributes;
10 | while (a.length > 0) h.removeAttribute(a[0].name);
11 | }
12 | });
13 |
--------------------------------------------------------------------------------
/docs/authors.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Authors • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
127 |
128 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/docs/bootstrap-toc.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
3 | * Copyright 2015 Aidan Feldman
4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
5 |
6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */
7 |
8 | /* All levels of nav */
9 | nav[data-toggle='toc'] .nav > li > a {
10 | display: block;
11 | padding: 4px 20px;
12 | font-size: 13px;
13 | font-weight: 500;
14 | color: #767676;
15 | }
16 | nav[data-toggle='toc'] .nav > li > a:hover,
17 | nav[data-toggle='toc'] .nav > li > a:focus {
18 | padding-left: 19px;
19 | color: #563d7c;
20 | text-decoration: none;
21 | background-color: transparent;
22 | border-left: 1px solid #563d7c;
23 | }
24 | nav[data-toggle='toc'] .nav > .active > a,
25 | nav[data-toggle='toc'] .nav > .active:hover > a,
26 | nav[data-toggle='toc'] .nav > .active:focus > a {
27 | padding-left: 18px;
28 | font-weight: bold;
29 | color: #563d7c;
30 | background-color: transparent;
31 | border-left: 2px solid #563d7c;
32 | }
33 |
34 | /* Nav: second level (shown on .active) */
35 | nav[data-toggle='toc'] .nav .nav {
36 | display: none; /* Hide by default, but at >768px, show it */
37 | padding-bottom: 10px;
38 | }
39 | nav[data-toggle='toc'] .nav .nav > li > a {
40 | padding-top: 1px;
41 | padding-bottom: 1px;
42 | padding-left: 30px;
43 | font-size: 12px;
44 | font-weight: normal;
45 | }
46 | nav[data-toggle='toc'] .nav .nav > li > a:hover,
47 | nav[data-toggle='toc'] .nav .nav > li > a:focus {
48 | padding-left: 29px;
49 | }
50 | nav[data-toggle='toc'] .nav .nav > .active > a,
51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a,
52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a {
53 | padding-left: 28px;
54 | font-weight: 500;
55 | }
56 |
57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */
58 | nav[data-toggle='toc'] .nav > .active > ul {
59 | display: block;
60 | }
61 |
--------------------------------------------------------------------------------
/docs/bootstrap-toc.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
3 | * Copyright 2015 Aidan Feldman
4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
5 | (function() {
6 | 'use strict';
7 |
8 | window.Toc = {
9 | helpers: {
10 | // return all matching elements in the set, or their descendants
11 | findOrFilter: function($el, selector) {
12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
13 | // http://stackoverflow.com/a/12731439/358804
14 | var $descendants = $el.find(selector);
15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])');
16 | },
17 |
18 | generateUniqueIdBase: function(el) {
19 | var text = $(el).text();
20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-');
21 | return anchor || el.tagName.toLowerCase();
22 | },
23 |
24 | generateUniqueId: function(el) {
25 | var anchorBase = this.generateUniqueIdBase(el);
26 | for (var i = 0; ; i++) {
27 | var anchor = anchorBase;
28 | if (i > 0) {
29 | // add suffix
30 | anchor += '-' + i;
31 | }
32 | // check if ID already exists
33 | if (!document.getElementById(anchor)) {
34 | return anchor;
35 | }
36 | }
37 | },
38 |
39 | generateAnchor: function(el) {
40 | if (el.id) {
41 | return el.id;
42 | } else {
43 | var anchor = this.generateUniqueId(el);
44 | el.id = anchor;
45 | return anchor;
46 | }
47 | },
48 |
49 | createNavList: function() {
50 | return $('');
51 | },
52 |
53 | createChildNavList: function($parent) {
54 | var $childList = this.createNavList();
55 | $parent.append($childList);
56 | return $childList;
57 | },
58 |
59 | generateNavEl: function(anchor, text) {
60 | var $a = $(' ');
61 | $a.attr('href', '#' + anchor);
62 | $a.text(text);
63 | var $li = $(' ');
64 | $li.append($a);
65 | return $li;
66 | },
67 |
68 | generateNavItem: function(headingEl) {
69 | var anchor = this.generateAnchor(headingEl);
70 | var $heading = $(headingEl);
71 | var text = $heading.data('toc-text') || $heading.text();
72 | return this.generateNavEl(anchor, text);
73 | },
74 |
75 | // Find the first heading level (``, then ``, etc.) that has more than one element. Defaults to 1 (for ``).
76 | getTopLevel: function($scope) {
77 | for (var i = 1; i <= 6; i++) {
78 | var $headings = this.findOrFilter($scope, 'h' + i);
79 | if ($headings.length > 1) {
80 | return i;
81 | }
82 | }
83 |
84 | return 1;
85 | },
86 |
87 | // returns the elements for the top level, and the next below it
88 | getHeadings: function($scope, topLevel) {
89 | var topSelector = 'h' + topLevel;
90 |
91 | var secondaryLevel = topLevel + 1;
92 | var secondarySelector = 'h' + secondaryLevel;
93 |
94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector);
95 | },
96 |
97 | getNavLevel: function(el) {
98 | return parseInt(el.tagName.charAt(1), 10);
99 | },
100 |
101 | populateNav: function($topContext, topLevel, $headings) {
102 | var $context = $topContext;
103 | var $prevNav;
104 |
105 | var helpers = this;
106 | $headings.each(function(i, el) {
107 | var $newNav = helpers.generateNavItem(el);
108 | var navLevel = helpers.getNavLevel(el);
109 |
110 | // determine the proper $context
111 | if (navLevel === topLevel) {
112 | // use top level
113 | $context = $topContext;
114 | } else if ($prevNav && $context === $topContext) {
115 | // create a new level of the tree and switch to it
116 | $context = helpers.createChildNavList($prevNav);
117 | } // else use the current $context
118 |
119 | $context.append($newNav);
120 |
121 | $prevNav = $newNav;
122 | });
123 | },
124 |
125 | parseOps: function(arg) {
126 | var opts;
127 | if (arg.jquery) {
128 | opts = {
129 | $nav: arg
130 | };
131 | } else {
132 | opts = arg;
133 | }
134 | opts.$scope = opts.$scope || $(document.body);
135 | return opts;
136 | }
137 | },
138 |
139 | // accepts a jQuery object, or an options object
140 | init: function(opts) {
141 | opts = this.helpers.parseOps(opts);
142 |
143 | // ensure that the data attribute is in place for styling
144 | opts.$nav.attr('data-toggle', 'toc');
145 |
146 | var $topContext = this.helpers.createChildNavList(opts.$nav);
147 | var topLevel = this.helpers.getTopLevel(opts.$scope);
148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel);
149 | this.helpers.populateNav($topContext, topLevel, $headings);
150 | }
151 | };
152 |
153 | $(function() {
154 | $('nav[data-toggle="toc"]').each(function(i, el) {
155 | var $nav = $(el);
156 | Toc.init($nav);
157 | });
158 | });
159 | })();
160 |
--------------------------------------------------------------------------------
/docs/docsearch.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | // register a handler to move the focus to the search bar
4 | // upon pressing shift + "/" (i.e. "?")
5 | $(document).on('keydown', function(e) {
6 | if (e.shiftKey && e.keyCode == 191) {
7 | e.preventDefault();
8 | $("#search-input").focus();
9 | }
10 | });
11 |
12 | $(document).ready(function() {
13 | // do keyword highlighting
14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */
15 | var mark = function() {
16 |
17 | var referrer = document.URL ;
18 | var paramKey = "q" ;
19 |
20 | if (referrer.indexOf("?") !== -1) {
21 | var qs = referrer.substr(referrer.indexOf('?') + 1);
22 | var qs_noanchor = qs.split('#')[0];
23 | var qsa = qs_noanchor.split('&');
24 | var keyword = "";
25 |
26 | for (var i = 0; i < qsa.length; i++) {
27 | var currentParam = qsa[i].split('=');
28 |
29 | if (currentParam.length !== 2) {
30 | continue;
31 | }
32 |
33 | if (currentParam[0] == paramKey) {
34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20"));
35 | }
36 | }
37 |
38 | if (keyword !== "") {
39 | $(".contents").unmark({
40 | done: function() {
41 | $(".contents").mark(keyword);
42 | }
43 | });
44 | }
45 | }
46 | };
47 |
48 | mark();
49 | });
50 | });
51 |
52 | /* Search term highlighting ------------------------------*/
53 |
54 | function matchedWords(hit) {
55 | var words = [];
56 |
57 | var hierarchy = hit._highlightResult.hierarchy;
58 | // loop to fetch from lvl0, lvl1, etc.
59 | for (var idx in hierarchy) {
60 | words = words.concat(hierarchy[idx].matchedWords);
61 | }
62 |
63 | var content = hit._highlightResult.content;
64 | if (content) {
65 | words = words.concat(content.matchedWords);
66 | }
67 |
68 | // return unique words
69 | var words_uniq = [...new Set(words)];
70 | return words_uniq;
71 | }
72 |
73 | function updateHitURL(hit) {
74 |
75 | var words = matchedWords(hit);
76 | var url = "";
77 |
78 | if (hit.anchor) {
79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor;
80 | } else {
81 | url = hit.url + '?q=' + escape(words.join(" "));
82 | }
83 |
84 | return url;
85 | }
86 |
--------------------------------------------------------------------------------
/docs/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/pkgdown.js:
--------------------------------------------------------------------------------
1 | /* http://gregfranko.com/blog/jquery-best-practices/ */
2 | (function($) {
3 | $(function() {
4 |
5 | $('.navbar-fixed-top').headroom();
6 |
7 | $('body').css('padding-top', $('.navbar').height() + 10);
8 | $(window).resize(function(){
9 | $('body').css('padding-top', $('.navbar').height() + 10);
10 | });
11 |
12 | $('[data-toggle="tooltip"]').tooltip();
13 |
14 | var cur_path = paths(location.pathname);
15 | var links = $("#navbar ul li a");
16 | var max_length = -1;
17 | var pos = -1;
18 | for (var i = 0; i < links.length; i++) {
19 | if (links[i].getAttribute("href") === "#")
20 | continue;
21 | // Ignore external links
22 | if (links[i].host !== location.host)
23 | continue;
24 |
25 | var nav_path = paths(links[i].pathname);
26 |
27 | var length = prefix_length(nav_path, cur_path);
28 | if (length > max_length) {
29 | max_length = length;
30 | pos = i;
31 | }
32 | }
33 |
34 | // Add class to parent , and enclosing if in dropdown
35 | if (pos >= 0) {
36 | var menu_anchor = $(links[pos]);
37 | menu_anchor.parent().addClass("active");
38 | menu_anchor.closest("li.dropdown").addClass("active");
39 | }
40 | });
41 |
42 | function paths(pathname) {
43 | var pieces = pathname.split("/");
44 | pieces.shift(); // always starts with /
45 |
46 | var end = pieces[pieces.length - 1];
47 | if (end === "index.html" || end === "")
48 | pieces.pop();
49 | return(pieces);
50 | }
51 |
52 | // Returns -1 if not found
53 | function prefix_length(needle, haystack) {
54 | if (needle.length > haystack.length)
55 | return(-1);
56 |
57 | // Special case for length-0 haystack, since for loop won't run
58 | if (haystack.length === 0) {
59 | return(needle.length === 0 ? 0 : -1);
60 | }
61 |
62 | for (var i = 0; i < haystack.length; i++) {
63 | if (needle[i] != haystack[i])
64 | return(i);
65 | }
66 |
67 | return(haystack.length);
68 | }
69 |
70 | /* Clipboard --------------------------*/
71 |
72 | function changeTooltipMessage(element, msg) {
73 | var tooltipOriginalTitle=element.getAttribute('data-original-title');
74 | element.setAttribute('data-original-title', msg);
75 | $(element).tooltip('show');
76 | element.setAttribute('data-original-title', tooltipOriginalTitle);
77 | }
78 |
79 | if(ClipboardJS.isSupported()) {
80 | $(document).ready(function() {
81 | var copyButton = " ";
82 |
83 | $(".examples, div.sourceCode").addClass("hasCopyButton");
84 |
85 | // Insert copy buttons:
86 | $(copyButton).prependTo(".hasCopyButton");
87 |
88 | // Initialize tooltips:
89 | $('.btn-copy-ex').tooltip({container: 'body'});
90 |
91 | // Initialize clipboard:
92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', {
93 | text: function(trigger) {
94 | return trigger.parentNode.textContent;
95 | }
96 | });
97 |
98 | clipboardBtnCopies.on('success', function(e) {
99 | changeTooltipMessage(e.trigger, 'Copied!');
100 | e.clearSelection();
101 | });
102 |
103 | clipboardBtnCopies.on('error', function() {
104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy');
105 | });
106 | });
107 | }
108 | })(window.jQuery || window.$)
109 |
--------------------------------------------------------------------------------
/docs/pkgdown.yml:
--------------------------------------------------------------------------------
1 | pandoc: 2.14.0.2
2 | pkgdown: 1.6.1
3 | pkgdown_sha: ~
4 | articles:
5 | tutorial: tutorial.html
6 | last_built: 2021-07-31T14:34Z
7 |
8 |
--------------------------------------------------------------------------------
/docs/reference/Rplot001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikemc/metacal/f56792d02bd722ab16c1ed215b07c1187829a226/docs/reference/Rplot001.png
--------------------------------------------------------------------------------
/docs/reference/anorm.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Aitchison norm of x — anorm • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Aitchison norm of x
133 |
134 |
135 |
anorm ( x , na.rm = FALSE )
136 |
137 |
Arguments
138 |
139 |
140 |
141 | na.rm
142 | Whether to remove NAs and NaNs before calculating.
143 |
144 |
145 |
146 |
147 |
148 |
153 |
154 |
155 |
156 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/docs/reference/as_matrix.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Coerce a (wide) data frame to a matrix — as_matrix • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Coerce a (wide) data frame to a matrix
133 |
134 |
135 |
as_matrix ( .data , rownames = NULL )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/reference/center_elts.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Geometrically center the elements of x — center_elts • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Geometrically center the elements of x
133 |
134 |
135 |
center_elts ( x , na.rm = FALSE )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/reference/close_elts.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Close the elements of x to proportions — close_elts • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Close the elements of x to proportions
133 |
134 |
135 |
close_elts ( x , na.rm = FALSE )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/reference/corner.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Objects exported from other packages — corner • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
135 |
136 |
137 |
These objects are imported from other packages. Follow the links
138 | below to see their documentation.
139 |
140 | useful corner
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
154 |
155 |
156 |
157 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
--------------------------------------------------------------------------------
/docs/reference/gm.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Geometric (multiplicative) version of the function f — gm • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Geometric (multiplicative) version of the function f
133 |
134 |
135 |
gm ( f )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/reference/gm_abs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Geometric absolute value of x — gm_abs • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Geometric absolute value of x
133 |
134 |
135 |
gm_abs ( x )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/reference/gm_mean.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Geometric mean of x — gm_mean • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Geometric mean of x
133 |
134 |
135 |
gm_mean ( x , na.rm = FALSE )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/reference/gm_range.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Geometric range of x — gm_range • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Geometric range of x
133 |
134 |
135 |
gm_range ( x )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/reference/gm_sd.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Geometric standard deviation of x — gm_sd • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Note, uses denominator n-1
133 |
134 |
135 |
gm_sd ( x , na.rm = FALSE )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/reference/import_phyloseq.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Import phyloseq classes and functions — import_phyloseq • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Import phyloseq classes and functions
133 |
134 |
135 |
136 |
137 |
138 |
139 |
144 |
145 |
146 |
147 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
--------------------------------------------------------------------------------
/docs/reference/logit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Logit (log-odds) of the probability vector x — logit • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Logit (log-odds) of the probability vector x
133 |
134 |
135 |
logit ( x )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/reference/mutate_by.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Mutate within groups — mutate_by • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Mutate within groups
133 |
134 |
135 |
mutate_by ( .data , group_vars , ... )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/reference/odds.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Odds of the probability vector x — odds • metacal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
130 |
131 |
132 |
Odds of the probability vector x
133 |
134 |
135 |
odds ( x )
136 |
137 |
138 |
139 |
140 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/inst/extdata/brooks2015-actual.csv:
--------------------------------------------------------------------------------
1 | Sample,Atopobium_vaginae,Gardnerella_vaginalis,Lactobacillus_crispatus,Lactobacillus_iners,Prevotella_bivia,Sneathia_amnii,Streptococcus_agalactiae
2 | s1-1,0,0,0.3333333333333333,0,0.3333333333333333,0,0.3333333333333333
3 | s1-10,0.3333333333333333,0,0.3333333333333333,0,0,0.3333333333333333,0
4 | s1-11,0,0.3333333333333333,0.3333333333333333,0.3333333333333333,0,0,0
5 | s1-12,0.5,0,0,0,0.5,0,0
6 | s1-13,0,0,0.3333333333333333,0,0.3333333333333333,0.3333333333333333,0
7 | s1-14,0,0,0.5,0,0,0,0.5
8 | s1-15,0.3333333333333333,0,0,0.3333333333333333,0,0,0.3333333333333333
9 | s1-16,0,0,0,0.5,0,0.5,0
10 | s1-17,0,0,0,0,0,0,1
11 | s1-18,0,0.5,0.5,0,0,0,0
12 | s1-19,0,0,0,0.3333333333333333,0.3333333333333333,0,0.3333333333333333
13 | s1-2,0.3333333333333333,0.3333333333333333,0.3333333333333333,0,0,0,0
14 | s1-20,0,0,0,0,0.5,0,0.5
15 | s1-21,0.3333333333333333,0,0,0,0.3333333333333333,0,0.3333333333333333
16 | s1-22,0.3333333333333333,0,0,0.3333333333333333,0,0.3333333333333333,0
17 | s1-23,0.14285714285714285,0.14285714285714285,0.14285714285714285,0.14285714285714285,0.14285714285714285,0.14285714285714285,0.14285714285714285
18 | s1-24,0,0.3333333333333333,0,0,0,0.3333333333333333,0.3333333333333333
19 | s1-25,0,0.3333333333333333,0,0.3333333333333333,0,0,0.3333333333333333
20 | s1-26,0,0.3333333333333333,0,0,0.3333333333333333,0,0.3333333333333333
21 | s1-27,0,0.3333333333333333,0.3333333333333333,0,0.3333333333333333,0,0
22 | s1-28,0,0,1,0,0,0,0
23 | s1-29,0,0.5,0,0,0,0.5,0
24 | s1-3,0.3333333333333333,0.3333333333333333,0,0,0.3333333333333333,0,0
25 | s1-30,0,0.3333333333333333,0.3333333333333333,0,0,0.3333333333333333,0
26 | s1-31,0,0,0,0.5,0.5,0,0
27 | s1-32,0.5,0,0.5,0,0,0,0
28 | s1-33,0,0,0.5,0.5,0,0,0
29 | s1-34,1,0,0,0,0,0,0
30 | s1-35,0,0.25,0,0.25,0.25,0.25,0
31 | s1-36,0,0,0,0.3333333333333333,0,0.3333333333333333,0.3333333333333333
32 | s1-37,0.3333333333333333,0.3333333333333333,0,0,0,0,0.3333333333333333
33 | s1-38,0,0,0,0,0.5,0.5,0
34 | s1-39,0,0.5,0,0.5,0,0,0
35 | s1-4,0.3333333333333333,0,0.3333333333333333,0,0,0,0.3333333333333333
36 | s1-40,0,0,0.5,0,0,0.5,0
37 | s1-5,0,0.5,0,0,0.5,0,0
38 | s1-6,0.3333333333333333,0,0,0.3333333333333333,0.3333333333333333,0,0
39 | s1-7,0.5,0,0,0,0,0,0.5
40 | s1-8,0,0.5,0,0,0,0,0.5
41 | s1-9,0.3333333333333333,0,0,0,0,0.3333333333333333,0.3333333333333333
42 | s2-1,0,0,0,0,0,0,1
43 | s2-10,0,0,0,0,0,1,0
44 | s2-11,0,0.3333333333333333,0.3333333333333333,0,0,0,0.3333333333333333
45 | s2-12,0.3333333333333333,0.3333333333333333,0,0,0,0,0.3333333333333333
46 | s2-13,0.3333333333333333,0,0.3333333333333333,0,0.3333333333333333,0,0
47 | s2-14,0.14285714285714285,0.14285714285714285,0.14285714285714285,0.14285714285714285,0.14285714285714285,0.14285714285714285,0.14285714285714285
48 | s2-15,0,0,0,0,0.3333333333333333,0.3333333333333333,0.3333333333333333
49 | s2-16,0,0,0.3333333333333333,0.3333333333333333,0,0,0.3333333333333333
50 | s2-17,0.3333333333333333,0.3333333333333333,0,0.3333333333333333,0,0,0
51 | s2-18,1,0,0,0,0,0,0
52 | s2-19,0,0,0.5,0.5,0,0,0
53 | s2-2,0,0,0.3333333333333333,0,0,0.3333333333333333,0.3333333333333333
54 | s2-20,0.3333333333333333,0.3333333333333333,0.3333333333333333,0,0,0,0
55 | s2-21,0,0,0.5,0,0,0,0.5
56 | s2-22,0,0,0,0,1,0,0
57 | s2-23,0.5,0,0,0,0.5,0,0
58 | s2-24,0,0,0,1,0,0,0
59 | s2-25,0,0,0,0.3333333333333333,0,0.3333333333333333,0.3333333333333333
60 | s2-26,0,0,0.3333333333333333,0.3333333333333333,0.3333333333333333,0,0
61 | s2-27,0.3333333333333333,0,0,0.3333333333333333,0,0,0.3333333333333333
62 | s2-28,0,0,0.5,0,0.5,0,0
63 | s2-29,0,0,0,0.5,0,0,0.5
64 | s2-3,0,0.3333333333333333,0,0,0,0.3333333333333333,0.3333333333333333
65 | s2-30,0,0,0.5,0,0,0.5,0
66 | s2-31,0.3333333333333333,0,0.3333333333333333,0,0,0.3333333333333333,0
67 | s2-32,0,0,0,0.3333333333333333,0.3333333333333333,0.3333333333333333,0
68 | s2-33,0,0,0,0,0,0.5,0.5
69 | s2-34,0.3333333333333333,0,0,0,0.3333333333333333,0.3333333333333333,0
70 | s2-35,0.3333333333333333,0,0.3333333333333333,0.3333333333333333,0,0,0
71 | s2-36,0,0.3333333333333333,0,0,0.3333333333333333,0.3333333333333333,0
72 | s2-37,0,1,0,0,0,0,0
73 | s2-38,0,0.3333333333333333,0,0.3333333333333333,0,0.3333333333333333,0
74 | s2-39,0.5,0.5,0,0,0,0,0
75 | s2-4,0.5,0,0,0,0,0.5,0
76 | s2-40,0,0,0.3333333333333333,0.3333333333333333,0,0.3333333333333333,0
77 | s2-5,0.5,0,0,0.5,0,0,0
78 | s2-6,0.3333333333333333,0.3333333333333333,0,0,0,0.3333333333333333,0
79 | s2-7,0,0,0,0.3333333333333333,0.3333333333333333,0,0.3333333333333333
80 | s2-8,0,0.3333333333333333,0,0.3333333333333333,0.3333333333333333,0,0
81 | s2-9,0,0.3333333333333333,0.3333333333333333,0,0.3333333333333333,0,0
82 |
--------------------------------------------------------------------------------
/inst/extdata/brooks2015-observed.csv:
--------------------------------------------------------------------------------
1 | Sample,Atopobium_vaginae,Gardnerella_vaginalis,Lactobacillus_crispatus,Lactobacillus_iners,Prevotella_bivia,Sneathia_amnii,Streptococcus_agalactiae,Other
2 | s1-1,1,1,13670,0,7544,1,1506,7
3 | s1-10,1028,0,10310,2,1,14947,2,3
4 | s1-11,0,181,3956,7598,6,2,0,2
5 | s1-12,1424,0,0,1,21708,7,0,8
6 | s1-13,0,0,3199,0,1854,6501,0,3
7 | s1-14,0,0,9348,2,0,3,1475,10
8 | s1-15,572,0,1,7493,1,3,466,4
9 | s1-16,0,0,1,3849,0,3590,4,2
10 | s1-17,2,1,19,4,1,14,51332,206
11 | s1-18,0,865,9892,0,0,0,0,7
12 | s1-19,0,0,0,9138,4339,2,468,3
13 | s1-2,2930,1650,22645,0,1,1,4,8
14 | s1-20,0,0,4,5,16249,5,1937,6
15 | s1-21,1232,0,1,3,9639,2,1249,5
16 | s1-22,361,0,0,7117,0,6229,1,0
17 | s1-23,351,203,2463,4886,1460,4798,281,1
18 | s1-24,1,621,0,1,2,16454,906,1
19 | s1-25,0,787,4,21869,0,355,1100,2
20 | s1-26,0,1007,3,1,10761,0,1217,3
21 | s1-27,0,522,9194,1,5792,3,2,6
22 | s1-28,0,0,21759,0,1,7,1,5
23 | s1-29,2,1020,1,1,0,23306,0,11
24 | s1-3,2073,1514,3,1,15772,0,1,16
25 | s1-30,1,283,4740,4,0,12702,0,2
26 | s1-31,1,0,6,8471,3555,0,2,0
27 | s1-32,1172,0,9825,0,0,1,1,1
28 | s1-33,3,0,4192,9087,0,0,1,2
29 | s1-34,13370,0,0,3,2,4,0,18
30 | s1-35,1,267,0,8329,3190,5445,5,1
31 | s1-36,1,0,0,5821,1,6622,308,0
32 | s1-37,5493,2422,0,2,0,1,4971,20
33 | s1-38,3,1,0,3,4677,9272,0,0
34 | s1-39,1,275,3,8890,0,1,0,0
35 | s1-4,2217,0,16037,0,5,30,1557,8
36 | s1-40,1,0,2292,0,0,5974,0,1
37 | s1-5,0,754,3,0,14670,3,0,5
38 | s1-6,500,1,2,9866,4318,0,0,2
39 | s1-7,7782,1,0,0,0,0,6678,14
40 | s1-8,2,3307,0,0,3,2,3252,13
41 | s1-9,1403,0,0,0,0,15119,1085,6
42 | s2-1,0,0,176,9,2,15,24437,6
43 | s2-10,1,0,1,2,0,22682,1,1
44 | s2-11,0,570,10690,3,0,3,1143,4
45 | s2-12,7170,2642,7,7,0,47,9387,45
46 | s2-13,1245,3,11969,18,7303,1,1,1
47 | s2-14,511,308,2256,4175,1648,4707,259,2
48 | s2-15,0,0,0,4,5126,13714,649,1
49 | s2-16,0,0,4288,8703,0,0,533,4
50 | s2-17,837,523,0,13121,0,0,0,4
51 | s2-18,12395,0,2,2,0,124,1,18
52 | s2-19,0,0,3427,7517,0,1,0,1
53 | s2-2,0,0,6497,1,0,11854,679,2
54 | s2-20,1730,956,11699,5,1,4,6,2
55 | s2-21,0,3,10777,3,4,0,1160,1
56 | s2-22,0,0,3,3,15696,1,0,0
57 | s2-23,2261,0,1,0,12096,0,6,2
58 | s2-24,0,0,0,14783,0,2,0,0
59 | s2-25,2,2,3,12498,0,13504,733,0
60 | s2-26,0,0,4775,11234,3249,1,0,5
61 | s2-27,424,0,0,7120,0,1,447,6
62 | s2-28,0,1,10682,0,7253,1,1,2
63 | s2-29,2,0,3,15628,1,4,771,3
64 | s2-3,1,714,2,1,0,19831,924,4
65 | s2-30,0,0,6294,3,0,17503,0,6
66 | s2-31,615,2,4552,7,3,9467,1,1
67 | s2-32,1,0,0,10509,3685,10047,0,3
68 | s2-33,0,0,4,10,1,24914,1189,5
69 | s2-34,569,0,0,1,4261,12493,0,1
70 | s2-35,441,0,3461,7611,1,7,0,0
71 | s2-36,0,232,0,7,2532,10118,0,0
72 | s2-37,0,4770,5,7,0,0,1,9
73 | s2-38,0,192,0,6962,1,6399,0,0
74 | s2-39,14324,8200,4,4,35,5,1,23
75 | s2-4,1449,0,14,9,6,20636,0,0
76 | s2-40,0,0,2286,5677,0,6239,0,3
77 | s2-5,883,0,0,14212,7,11,0,2
78 | s2-6,1533,1021,12,1,1,17227,1,4
79 | s2-7,0,0,1,12725,4926,3,663,4
80 | s2-8,0,746,3,20551,7766,2,0,4
81 | s2-9,0,491,9872,0,6410,0,0,10
82 |
--------------------------------------------------------------------------------
/inst/extdata/brooks2015-sample-data.csv:
--------------------------------------------------------------------------------
1 | Sample,Plate,Barcode,Mixture_type,Num_species,Species_list
2 | s1-1,1,1,Cells,3,Lactobacillus_crispatus;Prevotella_bivia;Streptococcus_agalactiae
3 | s1-2,1,2,Cells,3,Gardnerella_vaginalis;Atopobium_vaginae;Lactobacillus_crispatus
4 | s1-3,1,3,Cells,3,Gardnerella_vaginalis;Atopobium_vaginae;Prevotella_bivia
5 | s1-4,1,4,Cells,3,Atopobium_vaginae;Lactobacillus_crispatus;Streptococcus_agalactiae
6 | s1-5,1,5,Cells,2,Gardnerella_vaginalis;Prevotella_bivia
7 | s1-6,1,6,Cells,3,Atopobium_vaginae;Lactobacillus_iners;Prevotella_bivia
8 | s1-7,1,7,Cells,2,Atopobium_vaginae;Streptococcus_agalactiae
9 | s1-8,1,8,Cells,2,Gardnerella_vaginalis;Streptococcus_agalactiae
10 | s1-9,1,9,Cells,3,Atopobium_vaginae;Sneathia_amnii;Streptococcus_agalactiae
11 | s1-10,1,10,Cells,3,Atopobium_vaginae;Lactobacillus_crispatus;Sneathia_amnii
12 | s1-11,1,11,Cells,3,Gardnerella_vaginalis;Lactobacillus_crispatus;Lactobacillus_iners
13 | s1-12,1,12,Cells,2,Atopobium_vaginae;Prevotella_bivia
14 | s1-13,1,13,Cells,3,Lactobacillus_crispatus;Prevotella_bivia;Sneathia_amnii
15 | s1-14,1,14,Cells,2,Lactobacillus_crispatus;Streptococcus_agalactiae
16 | s1-15,1,15,Cells,3,Atopobium_vaginae;Lactobacillus_iners;Streptococcus_agalactiae
17 | s1-16,1,16,Cells,2,Lactobacillus_iners;Sneathia_amnii
18 | s1-17,1,17,Cells,1,Streptococcus_agalactiae
19 | s1-18,1,18,Cells,2,Gardnerella_vaginalis;Lactobacillus_crispatus
20 | s1-19,1,19,Cells,3,Lactobacillus_iners;Prevotella_bivia;Streptococcus_agalactiae
21 | s1-20,1,20,Cells,2,Prevotella_bivia;Streptococcus_agalactiae
22 | s1-21,1,21,Cells,3,Atopobium_vaginae;Prevotella_bivia;Streptococcus_agalactiae
23 | s1-22,1,22,Cells,3,Atopobium_vaginae;Lactobacillus_iners;Sneathia_amnii
24 | s1-23,1,23,Cells,7,Gardnerella_vaginalis;Atopobium_vaginae;Lactobacillus_crispatus;Lactobacillus_iners;Prevotella_bivia;Sneathia_amnii;Streptococcus_agalactiae
25 | s1-24,1,24,Cells,3,Gardnerella_vaginalis;Sneathia_amnii;Streptococcus_agalactiae
26 | s1-25,1,25,Cells,3,Gardnerella_vaginalis;Lactobacillus_iners;Streptococcus_agalactiae
27 | s1-26,1,26,Cells,3,Gardnerella_vaginalis;Prevotella_bivia;Streptococcus_agalactiae
28 | s1-27,1,27,Cells,3,Gardnerella_vaginalis;Lactobacillus_crispatus;Prevotella_bivia
29 | s1-28,1,28,Cells,1,Lactobacillus_crispatus
30 | s1-29,1,29,Cells,2,Gardnerella_vaginalis;Sneathia_amnii
31 | s1-30,1,30,Cells,3,Gardnerella_vaginalis;Lactobacillus_crispatus;Sneathia_amnii
32 | s1-31,1,31,Cells,2,Lactobacillus_iners;Prevotella_bivia
33 | s1-32,1,32,Cells,2,Atopobium_vaginae;Lactobacillus_crispatus
34 | s1-33,1,33,Cells,2,Lactobacillus_crispatus;Lactobacillus_iners
35 | s1-34,1,34,Cells,1,Atopobium_vaginae
36 | s1-35,1,35,Cells,4,Gardnerella_vaginalis;Lactobacillus_iners;Prevotella_bivia;Sneathia_amnii
37 | s1-36,1,36,Cells,3,Lactobacillus_iners;Sneathia_amnii;Streptococcus_agalactiae
38 | s1-37,1,37,Cells,3,Gardnerella_vaginalis;Atopobium_vaginae;Streptococcus_agalactiae
39 | s1-38,1,38,Cells,2,Prevotella_bivia;Sneathia_amnii
40 | s1-39,1,39,Cells,2,Gardnerella_vaginalis;Lactobacillus_iners
41 | s1-40,1,40,Cells,2,Lactobacillus_crispatus;Sneathia_amnii
42 | s2-1,2,1,Cells,1,Streptococcus_agalactiae
43 | s2-2,2,2,Cells,3,Lactobacillus_crispatus;Sneathia_amnii;Streptococcus_agalactiae
44 | s2-3,2,3,Cells,3,Gardnerella_vaginalis;Sneathia_amnii;Streptococcus_agalactiae
45 | s2-4,2,4,Cells,2,Atopobium_vaginae;Sneathia_amnii
46 | s2-5,2,5,Cells,2,Atopobium_vaginae;Lactobacillus_iners
47 | s2-6,2,6,Cells,3,Gardnerella_vaginalis;Atopobium_vaginae;Sneathia_amnii
48 | s2-7,2,7,Cells,3,Lactobacillus_iners;Prevotella_bivia;Streptococcus_agalactiae
49 | s2-8,2,8,Cells,3,Gardnerella_vaginalis;Lactobacillus_iners;Prevotella_bivia
50 | s2-9,2,9,Cells,3,Gardnerella_vaginalis;Lactobacillus_crispatus;Prevotella_bivia
51 | s2-10,2,10,Cells,1,Sneathia_amnii
52 | s2-11,2,11,Cells,3,Gardnerella_vaginalis;Lactobacillus_crispatus;Streptococcus_agalactiae
53 | s2-12,2,12,Cells,3,Gardnerella_vaginalis;Atopobium_vaginae;Streptococcus_agalactiae
54 | s2-13,2,13,Cells,3,Atopobium_vaginae;Lactobacillus_crispatus;Prevotella_bivia
55 | s2-14,2,14,Cells,7,Gardnerella_vaginalis;Atopobium_vaginae;Lactobacillus_crispatus;Lactobacillus_iners;Prevotella_bivia;Sneathia_amnii;Streptococcus_agalactiae
56 | s2-15,2,15,Cells,3,Prevotella_bivia;Sneathia_amnii;Streptococcus_agalactiae
57 | s2-16,2,16,Cells,3,Lactobacillus_crispatus;Lactobacillus_iners;Streptococcus_agalactiae
58 | s2-17,2,17,Cells,3,Gardnerella_vaginalis;Atopobium_vaginae;Lactobacillus_iners
59 | s2-18,2,18,Cells,1,Atopobium_vaginae
60 | s2-19,2,19,Cells,2,Lactobacillus_crispatus;Lactobacillus_iners
61 | s2-20,2,20,Cells,3,Gardnerella_vaginalis;Atopobium_vaginae;Lactobacillus_crispatus
62 | s2-21,2,21,Cells,2,Lactobacillus_crispatus;Streptococcus_agalactiae
63 | s2-22,2,22,Cells,1,Prevotella_bivia
64 | s2-23,2,23,Cells,2,Atopobium_vaginae;Prevotella_bivia
65 | s2-24,2,24,Cells,1,Lactobacillus_iners
66 | s2-25,2,25,Cells,3,Lactobacillus_iners;Sneathia_amnii;Streptococcus_agalactiae
67 | s2-26,2,26,Cells,3,Lactobacillus_crispatus;Lactobacillus_iners;Prevotella_bivia
68 | s2-27,2,27,Cells,3,Atopobium_vaginae;Lactobacillus_iners;Streptococcus_agalactiae
69 | s2-28,2,28,Cells,2,Lactobacillus_crispatus;Prevotella_bivia
70 | s2-29,2,29,Cells,2,Lactobacillus_iners;Streptococcus_agalactiae
71 | s2-30,2,30,Cells,2,Lactobacillus_crispatus;Sneathia_amnii
72 | s2-31,2,31,Cells,3,Atopobium_vaginae;Lactobacillus_crispatus;Sneathia_amnii
73 | s2-32,2,32,Cells,3,Lactobacillus_iners;Prevotella_bivia;Sneathia_amnii
74 | s2-33,2,33,Cells,2,Sneathia_amnii;Streptococcus_agalactiae
75 | s2-34,2,34,Cells,3,Atopobium_vaginae;Prevotella_bivia;Sneathia_amnii
76 | s2-35,2,35,Cells,3,Atopobium_vaginae;Lactobacillus_crispatus;Lactobacillus_iners
77 | s2-36,2,36,Cells,3,Gardnerella_vaginalis;Prevotella_bivia;Sneathia_amnii
78 | s2-37,2,37,Cells,1,Gardnerella_vaginalis
79 | s2-38,2,38,Cells,3,Gardnerella_vaginalis;Lactobacillus_iners;Sneathia_amnii
80 | s2-39,2,39,Cells,2,Gardnerella_vaginalis;Atopobium_vaginae
81 | s2-40,2,40,Cells,3,Lactobacillus_crispatus;Lactobacillus_iners;Sneathia_amnii
82 |
--------------------------------------------------------------------------------
/man/anorm.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{anorm}
4 | \alias{anorm}
5 | \title{Aitchison norm of x}
6 | \usage{
7 | anorm(x, na.rm = FALSE)
8 | }
9 | \arguments{
10 | \item{na.rm}{Whether to remove NAs and NaNs before calculating.}
11 | }
12 | \description{
13 | Aitchison norm of x
14 | }
15 |
--------------------------------------------------------------------------------
/man/as_matrix.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utilities.R
3 | \name{as_matrix}
4 | \alias{as_matrix}
5 | \title{Coerce a (wide) data frame to a matrix}
6 | \usage{
7 | as_matrix(.data, rownames = NULL)
8 | }
9 | \description{
10 | Coerce a (wide) data frame to a matrix
11 | }
12 |
--------------------------------------------------------------------------------
/man/bootrep_center.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/compositional-mean.R
3 | \name{bootrep_center}
4 | \alias{bootrep_center}
5 | \title{Generate bootstrap replicates of the sample center}
6 | \usage{
7 | bootrep_center(
8 | .data,
9 | R = 4000,
10 | N = nrow(.data),
11 | method = "proj",
12 | dist = "dirichlet",
13 | in_scale = "linear",
14 | out_scale = "linear",
15 | denom = NULL,
16 | enframe = FALSE
17 | )
18 | }
19 | \arguments{
20 | \item{.data}{All-numeric data frame or matrix with taxa as columns.}
21 |
22 | \item{R}{Number of bootstrap replicates.}
23 |
24 | \item{N}{Number of trials for multinomial resampling.}
25 |
26 | \item{method}{Method for computing the center: "proj", "gm", or "rss".}
27 |
28 | \item{dist}{Distribution for drawing the bootstrap weights: "dirichlet" or
29 | "multinomial".}
30 |
31 | \item{in_scale}{"linear" (default) or "log".}
32 |
33 | \item{out_scale}{"linear" (default) or "log".}
34 |
35 | \item{denom}{Taxa to use in the denominator; if NULL, use all taxa.}
36 |
37 | \item{enframe}{Whether to "enframe" the bootstrap estimates in a tibble.}
38 | }
39 | \description{
40 | Generate bootstrap replicates of the sample center
41 | }
42 |
--------------------------------------------------------------------------------
/man/build_matrix.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utilities.R
3 | \name{build_matrix}
4 | \alias{build_matrix}
5 | \title{Create a matrix from columns of a tidy data frame}
6 | \usage{
7 | build_matrix(.data, rows, cols, elts, fill = NULL)
8 | }
9 | \arguments{
10 | \item{.data}{A data frame with columns \code{rows}, \code{cols}, and \code{elts}.}
11 |
12 | \item{rows}{Column that will become the rownames of the matrix.}
13 |
14 | \item{cols}{Column that will become the colnames of the matrix.}
15 |
16 | \item{elts}{Column that will become the matrix elements.}
17 |
18 | \item{fill}{Value to use for missing elements.}
19 | }
20 | \description{
21 | Note: Setting \code{fill} will replace NAs and NaNs, along with elements
22 | corresponding to missing rows, with the value of \code{fill}.
23 | }
24 |
--------------------------------------------------------------------------------
/man/calibrate.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/calibrate.R
3 | \name{calibrate}
4 | \alias{calibrate}
5 | \alias{calibrate.matrix}
6 | \alias{calibrate.otu_table}
7 | \alias{calibrate.phyloseq}
8 | \title{Calibrate a relative-abundance matrix by a bias vector}
9 | \usage{
10 | calibrate(observed, bias, ...)
11 |
12 | \method{calibrate}{matrix}(observed, bias, margin, norm = "close")
13 |
14 | \method{calibrate}{otu_table}(observed, bias, norm = "close")
15 |
16 | \method{calibrate}{phyloseq}(observed, bias, norm = "close", mean_name = ".mean_efficiency")
17 | }
18 | \arguments{
19 | \item{observed}{An abundance matrix or phyloseq object containing one}
20 |
21 | \item{bias}{A numeric vector of relative efficiencies or an object of class
22 | 'mc_bias_fit' (from which efficiencies will be extracted)}
23 |
24 | \item{margin}{Matrix margin that corresponds to observations (samples);
25 | \code{1} for rows, \code{2} for columns}
26 |
27 | \item{norm}{String specifying how to normalize the calibrated observations;
28 | see Details.}
29 |
30 | \item{mean_name}{Character vector or NULL. Name of the column in the sample
31 | data in which to store the mean efficiency, or NULL to skip.}
32 | }
33 | \description{
34 | Calibration via the simple deterministic procedure described in McLaren,
35 | Willis, and Callahan (2019), simply involved dividing the observed vector of
36 | relative abundances by the estimated bias vector and (optionally)
37 | normalizing the result to sum to 1 or some other chosen value.
38 | }
39 | \details{
40 | Normalization options specified by \code{norm}:
41 | \itemize{
42 | \item "close": Divide the calibrated abundance vector by its sum, so that it
43 | sums to 1
44 | \item "keep": Keep the same total abundance as the original observation
45 | \item "none": Return the calibrated abundances without any normalization
46 | }
47 |
48 | If \code{bias} is named, then the names must agree with the taxa names in
49 | \code{observed} and will be used to reorder \code{bias} to match the taxa order in
50 | \code{observed}.
51 | }
52 | \seealso{
53 | \code{\link[=perturb]{perturb()}} \code{\link[=estimate_bias]{estimate_bias()}}
54 | }
55 |
--------------------------------------------------------------------------------
/man/center.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/compositional-mean.R
3 | \name{center}
4 | \alias{center}
5 | \title{Compute the center (compositional mean) of a set of compositions}
6 | \usage{
7 | center(
8 | .data,
9 | weights = rep(1, nrow(.data)),
10 | method = "proj",
11 | in_scale = "linear",
12 | out_scale = "linear",
13 | denom = NULL,
14 | enframe = FALSE,
15 | components = FALSE
16 | )
17 | }
18 | \arguments{
19 | \item{.data}{All-numeric data frame or matrix with taxa as columns.}
20 |
21 | \item{weights}{Sample (row) weights.}
22 |
23 | \item{method}{Method for computing the center: "proj", "gm", or "rss".}
24 |
25 | \item{in_scale}{"linear" or "log".}
26 |
27 | \item{out_scale}{"linear" or "log".}
28 |
29 | \item{denom}{Taxa to use in the denominator; if NULL, use all taxa.}
30 |
31 | \item{enframe}{Whether to return the bias estimate as a two-column tibble.}
32 | }
33 | \description{
34 | Unobserved values should be marked as NaN.
35 | }
36 |
--------------------------------------------------------------------------------
/man/center_elts.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{center_elts}
4 | \alias{center_elts}
5 | \title{Geometrically center the elements of x}
6 | \usage{
7 | center_elts(x, na.rm = FALSE)
8 | }
9 | \description{
10 | Geometrically center the elements of x
11 | }
12 |
--------------------------------------------------------------------------------
/man/close_elts.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{close_elts}
4 | \alias{close_elts}
5 | \title{Close the elements of x to proportions}
6 | \usage{
7 | close_elts(x, na.rm = FALSE)
8 | }
9 | \description{
10 | Close the elements of x to proportions
11 | }
12 |
--------------------------------------------------------------------------------
/man/clr.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{clr}
4 | \alias{clr}
5 | \title{Compute the centered log-ratio transform of x}
6 | \usage{
7 | clr(x, base = exp(1), na.rm = FALSE)
8 | }
9 | \arguments{
10 | \item{x}{Vector of abundances.}
11 |
12 | \item{base}{Base for logarithm}
13 | }
14 | \description{
15 | Compute the centered log-ratio transform of x
16 | }
17 |
--------------------------------------------------------------------------------
/man/compute_ratios.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ratios.R
3 | \name{compute_ratios}
4 | \alias{compute_ratios}
5 | \title{Compute taxon ratios from a tidy data frame}
6 | \usage{
7 | compute_ratios(
8 | .data,
9 | group_vars = c("Sample"),
10 | comp_vars = setdiff(names(dplyr::select_if(.data, is.numeric)), group_vars),
11 | drop = TRUE
12 | )
13 | }
14 | \arguments{
15 | \item{drop}{Whether to drop the individual taxon quantities}
16 | }
17 | \description{
18 | Assumes the taxon variable name is \code{Taxon}
19 | }
20 |
--------------------------------------------------------------------------------
/man/cooccurrence.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/bias-helpers.R
3 | \name{cooccurrence}
4 | \alias{cooccurrence}
5 | \alias{cooccurrence_matrix}
6 | \alias{cooccurrence_network}
7 | \alias{cooccurrence_components}
8 | \title{Taxon co-occurrence network}
9 | \usage{
10 | cooccurrence_matrix(mat, all = TRUE)
11 |
12 | cooccurrence_network(mat, all = TRUE)
13 |
14 | cooccurrence_components(mat, all = TRUE, enframe = FALSE)
15 | }
16 | \arguments{
17 | \item{mat}{A compositional error matrix}
18 |
19 | \item{all}{Whether to include taxa that aren't in any multi-taxon samples}
20 |
21 | \item{enframe}{Whether to "enframe" the returned vector}
22 | }
23 | \description{
24 | Functions for probing the taxon co-occurrence network, used for checking if
25 | the bias estimated by the \code{center()} function is fully-determined.
26 | }
27 | \details{
28 | The edges are weighted by the number of samples the pair of taxa co-occur in
29 | and so provide some information about the precision of the pairwise bias
30 | estimate.
31 | }
32 | \section{Functions}{
33 | \itemize{
34 | \item \code{cooccurrence_matrix}: Adjacency matrix of the co-occurrence network
35 |
36 | \item \code{cooccurrence_network}: Co-occurrence network as an \code{igraph} object
37 |
38 | \item \code{cooccurrence_components}: Connected components of the co-occurrence network
39 | }}
40 |
41 |
--------------------------------------------------------------------------------
/man/corner.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utilities.R
3 | \docType{import}
4 | \name{corner}
5 | \alias{corner}
6 | \title{Objects exported from other packages}
7 | \keyword{internal}
8 | \description{
9 | These objects are imported from other packages. Follow the links
10 | below to see their documentation.
11 |
12 | \describe{
13 | \item{useful}{\code{\link[useful]{corner}}}
14 | }}
15 |
16 |
--------------------------------------------------------------------------------
/man/estimate_bias.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/estimate.R
3 | \name{estimate_bias}
4 | \alias{estimate_bias}
5 | \alias{estimate_bias.matrix}
6 | \alias{estimate_bias.otu_table}
7 | \alias{estimate_bias.phyloseq}
8 | \title{Estimate bias from control measurements}
9 | \usage{
10 | estimate_bias(observed, actual, ...)
11 |
12 | \method{estimate_bias}{matrix}(observed, actual, margin, boot = FALSE, times = 1000)
13 |
14 | \method{estimate_bias}{otu_table}(observed, actual, ...)
15 |
16 | \method{estimate_bias}{phyloseq}(observed, actual, ...)
17 | }
18 | \arguments{
19 | \item{observed}{Abundance matrix of observed compositions.}
20 |
21 | \item{actual}{Abundance matrix of actual or reference compositions for the
22 | same samples and taxa in \code{observed}.}
23 |
24 | \item{...}{Arguments passed to the matrix method.}
25 |
26 | \item{margin}{Matrix margin that corresponds to observations (samples);
27 | \code{1} for rows, \code{2} for columns.}
28 |
29 | \item{boot}{Whether to perform bootstrapping.}
30 |
31 | \item{times}{Number of bootstrap replicates.}
32 | }
33 | \value{
34 | A \code{mc_bias_fit} object with \code{\link[=coef]{coef()}}, \code{\link[=fitted]{fitted()}}, \code{\link[=residuals]{residuals()}}, and
35 | \code{\link[=summary]{summary()}} methods.
36 | }
37 | \description{
38 | Estimate bias using the compositional least-squares approach described in
39 | McLaren, Willis, and Callahan (2019).
40 | }
41 | \details{
42 | Bias is estimated by applying \code{\link[=center]{center()}} to the compositional error matrix
43 | defined by \code{observed/actual}, which requires that \code{observed} and \code{actual}
44 | are non-zero for the same sample-taxa pairs. For convenience, this
45 | function will automatically set values in \code{observed} to 0 whose
46 | corresponding entries are 0 in \code{actual}, but it is up to you to replace 0
47 | values in \code{observed} with a non-zero value (such as a pseudocount).
48 |
49 | Requirements for \code{observed} and \code{actual}: The row and column names (for
50 | matrices) or taxa and sample names (for phyloseq objects) must match, but
51 | can be in different orders. Any taxa and samples in \code{observed} but not in
52 | \code{actual} will be dropped prior to estimation.
53 | }
54 | \examples{
55 | # Load data from the cellular mock communities of Brooks et al 2015
56 | dr <- system.file("extdata", package = "metacal")
57 | list.files(dr)
58 | actual <- file.path(dr, "brooks2015-actual.csv") |>
59 | read.csv(row.names = "Sample") |>
60 | as("matrix")
61 | observed <- file.path(dr, "brooks2015-observed.csv") |>
62 | read.csv(row.names = "Sample") |>
63 | subset(select = - Other) |>
64 | as("matrix")
65 | sam <- file.path(dr, "brooks2015-sample-data.csv") |> read.csv()
66 |
67 | # Estimate bias with bootstrapping for error estimation
68 | mc_fit <- estimate_bias(observed, actual, margin = 1, boot = TRUE)
69 | summary(mc_fit)
70 | }
71 | \seealso{
72 | \code{\link[=center]{center()}} \code{\link[=calibrate]{calibrate()}}
73 | }
74 |
--------------------------------------------------------------------------------
/man/gm.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{gm}
4 | \alias{gm}
5 | \title{Geometric (multiplicative) version of the function f}
6 | \usage{
7 | gm(f)
8 | }
9 | \description{
10 | Geometric (multiplicative) version of the function f
11 | }
12 |
--------------------------------------------------------------------------------
/man/gm_abs.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{gm_abs}
4 | \alias{gm_abs}
5 | \title{Geometric absolute value of x}
6 | \usage{
7 | gm_abs(x)
8 | }
9 | \description{
10 | Geometric absolute value of x
11 | }
12 |
--------------------------------------------------------------------------------
/man/gm_mean.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{gm_mean}
4 | \alias{gm_mean}
5 | \title{Geometric mean of x}
6 | \usage{
7 | gm_mean(x, na.rm = FALSE)
8 | }
9 | \description{
10 | Geometric mean of x
11 | }
12 |
--------------------------------------------------------------------------------
/man/gm_range.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{gm_range}
4 | \alias{gm_range}
5 | \title{Geometric range of x}
6 | \usage{
7 | gm_range(x)
8 | }
9 | \description{
10 | Geometric range of x
11 | }
12 |
--------------------------------------------------------------------------------
/man/gm_sd.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{gm_sd}
4 | \alias{gm_sd}
5 | \title{Geometric standard deviation of x}
6 | \usage{
7 | gm_sd(x, na.rm = FALSE)
8 | }
9 | \description{
10 | Note, uses denominator n-1
11 | }
12 |
--------------------------------------------------------------------------------
/man/import_phyloseq.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/metacal.R
3 | \name{import_phyloseq}
4 | \alias{import_phyloseq}
5 | \title{Import phyloseq classes and functions}
6 | \description{
7 | Import phyloseq classes and functions
8 | }
9 |
--------------------------------------------------------------------------------
/man/log_center_proj.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/compositional-mean.R
3 | \name{log_center_proj}
4 | \alias{log_center_proj}
5 | \title{Compute the log center by the projection method}
6 | \usage{
7 | log_center_proj(mat, weights = rep(1, nrow(mat)))
8 | }
9 | \description{
10 | Compute the log center by the projection method, which allows for missing
11 | observations.
12 | }
13 | \references{
14 | van den Boogaart KG, Tolosana-Delgado R, Bren M. 2006. Concepts
15 | for handling of zeros and missing values in compositional data. Proc IAMG
16 | 6:1-4. http://www.stat.boogaart.de/Publications/iamg06_s07_01.pdf
17 |
18 | Bren M, Tolosana-Delgado R, van den Boogaart KG. 2008. News from
19 | "compositions", the R package.
20 | https://core.ac.uk/download/pdf/132548286.pdf
21 | }
22 |
--------------------------------------------------------------------------------
/man/log_center_rss.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/compositional-mean.R
3 | \name{log_center_rss}
4 | \alias{log_center_rss}
5 | \title{Compute the log center by numerical optimization}
6 | \usage{
7 | log_center_rss(mat, weights = rep(1, nrow(mat)), bound = 10)
8 | }
9 | \arguments{
10 | \item{bound}{Single number giving the lower and upper bound on the alr
11 | efficiencies ("rss" only).}
12 | }
13 | \description{
14 | Compute the log center by numerical optimization
15 | }
16 |
--------------------------------------------------------------------------------
/man/logit.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{logit}
4 | \alias{logit}
5 | \title{Logit (log-odds) of the probability vector x}
6 | \usage{
7 | logit(x)
8 | }
9 | \description{
10 | Logit (log-odds) of the probability vector x
11 | }
12 |
--------------------------------------------------------------------------------
/man/mean_efficiency.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/mean_efficiency.R
3 | \name{mean_efficiency}
4 | \alias{mean_efficiency}
5 | \alias{mean_efficiency.matrix}
6 | \alias{mean_efficiency.otu_table}
7 | \alias{mean_efficiency.phyloseq}
8 | \alias{mean_efficiency.mc_bias_fit}
9 | \title{Compute sample mean efficiencies}
10 | \usage{
11 | mean_efficiency(x, ...)
12 |
13 | \method{mean_efficiency}{matrix}(x, bias, margin, type)
14 |
15 | \method{mean_efficiency}{otu_table}(x, bias, type)
16 |
17 | \method{mean_efficiency}{phyloseq}(x, bias, type)
18 |
19 | \method{mean_efficiency}{mc_bias_fit}(x, newdata = NULL, margin = NULL, type = NULL)
20 | }
21 | \arguments{
22 | \item{x}{A matrix, a phyloseq object with an otu_table, or an object of
23 | class 'mc_bias_fit'}
24 |
25 | \item{bias}{A (possibly named) numeric vector of relative efficiencies}
26 |
27 | \item{margin}{The margin containing the samples (observations)}
28 |
29 | \item{type}{'actual' or 'observed', indicating the type of abundance
30 | profiles in the matrix \code{x} or \code{newdata}}
31 |
32 | \item{newdata}{NULL or an abundance matrix}
33 | }
34 | \description{
35 | Given a matrix of 'observed' or 'actual' (e.g. calibrated) abundance
36 | profiles and a vector of relative efficiencies, compute the estimated mean
37 | efficiency for each sample.
38 | }
39 | \details{
40 | The mean efficiency of a sample equals \code{weighted.mean(bias, y)}, where
41 | \code{bias} is the vector of taxa efficiencies and \code{y} is the vector of taxa
42 | proportions.
43 |
44 | The \code{type \%in\% c('actual', 'observed')} specifies whether the data is
45 | 'actual' (i.e. nominally known or calibrated abundances) or 'observed' (i.e.
46 | uncalibrated) data. 'Observed' data is calibrated to determine \code{y} prior to
47 | computing the mean efficiency.
48 |
49 | If \code{x} is an \code{mc_bias_fit} object, then the efficiencies will be extracted
50 | with \code{coef(x)}. An abundance matrix can optionally be given with \code{newdata};
51 | otherwise, the mean efficiency will be computed for the control samples in
52 | \code{x}.
53 |
54 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}}
55 | }
56 | \seealso{
57 | \code{\link[=estimate_bias]{estimate_bias()}}
58 | }
59 |
--------------------------------------------------------------------------------
/man/metacal-package.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/metacal-package.R
3 | \docType{package}
4 | \name{metacal-package}
5 | \alias{metacal}
6 | \alias{metacal-package}
7 | \title{metacal: Bias estimation and calibration for metagenomics experiments}
8 | \description{
9 | The metacal package provides tools for bias estimation and calibration in marker-gene and metagenomics sequencing experiments, using the methods developed in https://elifesciences.org/articles/46923.
10 | }
11 | \seealso{
12 | Useful links:
13 | \itemize{
14 | \item \url{https://mikemc.github.io/metacal}
15 | \item \url{https://github.com/mikemc/metacal}
16 | \item Report bugs at \url{https://github.com/mikemc/metacal/issues}
17 | }
18 |
19 | }
20 | \author{
21 | \strong{Maintainer}: Michael McLaren \email{m.mclaren42@gmail.com} (\href{https://orcid.org/0000-0003-1575-473X}{ORCID})
22 |
23 | }
24 | \keyword{internal}
25 |
--------------------------------------------------------------------------------
/man/mutate_by.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utilities.R
3 | \name{mutate_by}
4 | \alias{mutate_by}
5 | \title{Mutate within groups}
6 | \usage{
7 | mutate_by(.data, group_vars, ...)
8 | }
9 | \description{
10 | Mutate within groups
11 | }
12 |
--------------------------------------------------------------------------------
/man/odds.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{odds}
4 | \alias{odds}
5 | \title{Odds of the probability vector x}
6 | \usage{
7 | odds(x)
8 | }
9 | \description{
10 | Odds of the probability vector x
11 | }
12 |
--------------------------------------------------------------------------------
/man/pairwise_ratios.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ratios.R
3 | \name{pairwise_ratios}
4 | \alias{pairwise_ratios}
5 | \alias{pairwise_ratios.default}
6 | \alias{pairwise_ratios.matrix}
7 | \alias{pairwise_ratios.otu_table}
8 | \alias{pairwise_ratios.phyloseq}
9 | \title{Pairwise ratios of vector elements and matrix rows or columns}
10 | \usage{
11 | pairwise_ratios(x, ..., f = `/`, filter = TRUE, set_names = TRUE, sep = ":")
12 |
13 | \method{pairwise_ratios}{default}(x, f = `/`, filter = TRUE, set_names = TRUE, sep = ":")
14 |
15 | \method{pairwise_ratios}{matrix}(x, margin, f = `/`, filter = TRUE, set_names = TRUE, sep = ":")
16 |
17 | \method{pairwise_ratios}{otu_table}(x, margin = "taxa", f = `/`, filter = TRUE, sep = ":")
18 |
19 | \method{pairwise_ratios}{phyloseq}(x, margin = "taxa", f = `/`, filter = TRUE, sep = ":")
20 | }
21 | \arguments{
22 | \item{x}{A vector or matrix}
23 |
24 | \item{f}{Vectorized binary function applied to numerator and denominator}
25 |
26 | \item{filter}{Whether to filter out redundant pairs}
27 |
28 | \item{set_names}{Whether to set names for the pairs}
29 |
30 | \item{sep}{Seperator for pair names}
31 |
32 | \item{margin}{Margin (1 = rows, 2 = cols) of matrix x to compute ratios of}
33 | }
34 | \description{
35 | For a matrix, computes the ratios of the supplied margin (1 = rows, 2 =
36 | cols). Otherwise, computes the ratios of the elements.
37 | }
38 | \examples{
39 | mat <- seq(10) |>
40 | matrix(nrow = 2)
41 | rownames(mat) <- paste0('r', seq(2))
42 | colnames(mat) <- paste0('c', seq(5))
43 |
44 | pairwise_ratios(mat, 2)
45 | pairwise_ratios(mat[1,])
46 | }
47 |
--------------------------------------------------------------------------------
/man/perturb.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/calibrate.R
3 | \name{perturb}
4 | \alias{perturb}
5 | \alias{perturb.matrix}
6 | \alias{perturb.otu_table}
7 | \alias{perturb.phyloseq}
8 | \alias{perturb.mc_bias_fit}
9 | \title{Compositionally perturb a relative-abundance matrix}
10 | \usage{
11 | perturb(x, y, ...)
12 |
13 | \method{perturb}{matrix}(x, y, margin, norm = "close")
14 |
15 | \method{perturb}{otu_table}(x, y, norm = "close")
16 |
17 | \method{perturb}{phyloseq}(x, y, norm = "close")
18 |
19 | \method{perturb}{mc_bias_fit}(x, y)
20 | }
21 | \arguments{
22 | \item{x}{An abundance matrix or phyloseq object containing one}
23 |
24 | \item{y}{A numeric vector with which to perturb the observations in x}
25 |
26 | \item{margin}{Matrix margin that corresponds to observations (samples);
27 | \code{1} for rows, \code{2} for columns}
28 |
29 | \item{norm}{String specifying how to normalize the perturbed observations;
30 | see Details.}
31 | }
32 | \description{
33 | The perturbation of two compositional vectors \code{v} and \code{y} is given (up to
34 | compositional equivalence) by the elementwise product \code{v * y}.
35 | }
36 | \details{
37 | Let \code{w = v * y}, where \code{v} is a row or column of \code{x}. The normalization
38 | options specified by the \code{norm} argument are
39 | \itemize{
40 | \item "close" Return the compositional closure of w into the simplex,
41 | \code{w / sum(w)}
42 | \item "keep" Keep the same total abundance as the original vector by returning
43 | \code{w * sum(v) / sum(w)}
44 | \item "none" Return \code{w} without any normalization
45 | }
46 |
47 | If \code{y} is named, then the names must agree with the taxa names in \code{x} and
48 | will be used to reorder \code{y} to match the taxa order in \code{x}.
49 | }
50 | \seealso{
51 | \code{\link[=calibrate]{calibrate()}}
52 | }
53 |
--------------------------------------------------------------------------------
/man/proj_mat.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/compositional-mean.R
3 | \name{proj_mat}
4 | \alias{proj_mat}
5 | \title{Projection matrix P_M}
6 | \usage{
7 | proj_mat(K, M = c())
8 | }
9 | \arguments{
10 | \item{K}{number of elements (taxa)}
11 |
12 | \item{M}{set of missing elements (default is none missing)}
13 | }
14 | \description{
15 | Used internally for the "proj" method of computing the compositional mean.
16 | See vandenBoogaart2006 and Bren2008.
17 | }
18 |
--------------------------------------------------------------------------------
/man/xydist.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{xydist}
4 | \alias{xydist}
5 | \title{Distance or dissimilarity between relative abundance vectors x and y}
6 | \usage{
7 | xydist(x, y, method = "aitchison", trim = FALSE)
8 | }
9 | \arguments{
10 | \item{method}{Distance/dissimilarity measure.}
11 |
12 | \item{trim}{Should x and y be reduced to their common positive elements
13 | before computing the Aitchison distance (otherwise, the distance will be
14 | Inf).
15 |
16 | method == "aitchison" -> Aitchison distance
17 | method == "bray" -> Bray-Curtis dissimilarity between x and y. Note,
18 | converts x and y to proportions before computing.}
19 | }
20 | \description{
21 | Distance or dissimilarity between relative abundance vectors x and y
22 | }
23 |
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(metacal)
3 |
4 | test_check("metacal")
5 |
--------------------------------------------------------------------------------
/tests/testthat/test-calibrate.R:
--------------------------------------------------------------------------------
1 | # run just this file:
2 | # devtools::test_active_file(here::here("tests", "testthat", "test-calibrate.R"))
3 | #
4 | # Covers estimate_bias(), perturb(), calibrate()
5 |
6 | # Setup -----------------------------------------------------------------------
7 |
8 | test_xy <- function(n_taxa, n_samples) {
9 | set.seed(42)
10 | # random abundance matrix with zeros
11 | x <- sample(0:5, n_taxa*n_samples, replace = TRUE) %>%
12 | matrix(nrow = n_taxa)
13 | rownames(x) <- paste0("t", seq(n_taxa))
14 | colnames(x) <- paste0("s", seq(n_samples))
15 | # perturbation vector
16 | y <- seq(n_taxa)
17 |
18 | list(x = x, y = y)
19 | }
20 |
21 | l <- test_xy(5, 10)
22 | x <- l$x; y <- l$y
23 | otu <- otu_table(x, taxa_are_rows = TRUE)
24 |
25 | # Tests -----------------------------------------------------------------------
26 |
27 | test_that("`estimate_bias()` correctly recovers a deterministic perturbation", {
28 | actual <- otu
29 | bias <- rlang::set_names(center_elts(y), phyloseq::taxa_names(otu))
30 | observed <- perturb(otu, bias, norm = "keep")
31 | # Mix up the sample and taxa order
32 | observed <- observed[rownames(observed) %>% rev, colnames(observed) %>% rev]
33 |
34 | expect_equal(bias, estimate_bias(observed, actual) %>% coef)
35 | expect_equal(bias, estimate_bias(observed, actual %>% t) %>% coef)
36 |
37 | # non-zero values is observed that are zero in actual should be automatically
38 | # zeroed with a message
39 | observed1 <- otu_table(observed + 23 * (observed == 0), taxa_are_rows = TRUE)
40 | expect_message(fit <- estimate_bias(observed1, actual, boot = TRUE, times = 2))
41 | expect_equal(bias, coef(fit))
42 |
43 | # Matrices stored in `fit` should have samples as rows, and so work without
44 | # error in perturb() with `margin = 1`.
45 | perturb(fit$actual, fit$estimate, margin = 1, norm = "close")
46 |
47 | # Check perturb on mc_bias_fit's
48 | x <- perturb(fit, 1/fit$estimate)
49 | expect_equal(x$estimate / x$estimate, apply(x$bootreps, 2, mean))
50 | expect_error(perturb(fit, 1:3))
51 |
52 | # NOTE: doesn't quite fit this test title
53 | # Test that calibrate works on mc_bias_fit objects
54 | # fit <- estimate_bias(observed, actual)
55 | expect_equal(
56 | calibrate(observed, fit),
57 | calibrate(observed, coef(fit))
58 | )
59 |
60 | # Test mean efficiency computation
61 | me1 <- apply(fit$actual, 1, function(x) weighted.mean(coef(fit), x))
62 | me2 <- mean_efficiency(fit$actual, coef(fit), margin = 1, type = 'actual')
63 | me3 <- mean_efficiency(fit)
64 | expect_equal(me1, me3)
65 | expect_equal(me2, me3)
66 | me4 <- actual %>%
67 | phyloseq::transform_sample_counts(close_elts) %>%
68 | perturb(coef(fit), norm = 'none') %>%
69 | phyloseq::sample_sums() %>%
70 | .[names(me1)]
71 | expect_equal(me1, me4)
72 |
73 | # can also compute within `calibrate()`
74 | sam <- data.frame(
75 | dummy_var = seq(phyloseq::nsamples(observed)),
76 | row.names = sample_names(observed)
77 | ) %>%
78 | phyloseq::sample_data()
79 | cal <- phyloseq::phyloseq(observed, sam) %>%
80 | calibrate(coef(fit), mean_name = 'silly_name')
81 | me5 <- sample_data(cal)$silly_name
82 | names(me5) <- sample_names(cal)
83 | me5 <- me5[names(me1)]
84 | expect_equal(me1, me4)
85 | })
86 |
87 | test_that("`estimate_bias()` silently drops taxa and samples not in 'actual'", {
88 | actual <- otu %>%
89 | phyloseq::prune_taxa(taxa_names(.)[-3], .) %>%
90 | phyloseq::prune_samples(sample_names(.)[-4], .)
91 | bias <- rlang::set_names(center_elts(y), phyloseq::taxa_names(otu))
92 | observed <- perturb(otu, bias, norm = "keep")
93 | # Mix up the sample and taxa order
94 | observed <- observed[rownames(observed) %>% rev, colnames(observed) %>% rev]
95 |
96 | expect_equal(
97 | bias[-3] %>% center_elts,
98 | estimate_bias(observed, actual) %>% coef
99 | )
100 | })
101 |
102 | test_that("`calibrate()` and `perturb()` are inverse operations", {
103 | expect_equal(
104 | otu,
105 | otu %>% perturb(y, norm = "none") %>% calibrate(y, norm = "none")
106 | )
107 | mat <- otu %>% as("matrix")
108 | expect_equal(
109 | mat,
110 | mat %>% perturb(y, 2, norm = "none") %>% calibrate(y, 2, norm = "none")
111 | )
112 | # Should also work if y is named and has a different order
113 | y1 <- rlang::set_names(y, taxa_names(otu)) %>% rev
114 | expect_equal(
115 | otu,
116 | otu %>% perturb(y1, norm = "none") %>% calibrate(y, norm = "none")
117 | )
118 | })
119 |
120 | test_that("`calibrate()` (and `perturb()`) normalizations work", {
121 | expect_equal(
122 | rlang::set_names(rep(1, phyloseq::nsamples(otu)), phyloseq::sample_names(otu)),
123 | calibrate(otu, y, norm = "close") %>% phyloseq::sample_sums()
124 | )
125 | expect_equal(
126 | otu %>% sample_sums,
127 | calibrate(otu, y, norm = "keep") %>% phyloseq::sample_sums()
128 | )
129 | })
130 |
131 | test_that("taxa disagreements are properly handled", {
132 | y1 <- rlang::set_names(y, phyloseq::taxa_names(otu)) %>% rev
133 | y2 <- rlang::set_names(y, letters[seq_along(y)])
134 | # calibrate should work as long as some taxa names are shared with `bias`
135 | cal <- calibrate(otu, y1[1:4])
136 | expect_identical(taxa_names(cal), intersect(taxa_names(otu), names(y1)[1:4]))
137 | expect_error(calibrate(otu, y[1:4]))
138 | expect_error(calibrate(otu, y2))
139 | expect_error(calibrate(otu, y2[1:4]))
140 | })
141 |
--------------------------------------------------------------------------------
/tests/testthat/test-center.R:
--------------------------------------------------------------------------------
1 | context("Methods for computing compositional means")
2 |
3 | # Setup -----------------------------------------------------------------------
4 |
5 | library(tibble)
6 | library(tidyr)
7 | library(dplyr)
8 |
9 | set.seed(1)
10 | # Bias for 5 fake taxa:
11 | K <- 5
12 | taxa <- paste0("T", seq(K))
13 | bias <- tibble(Taxon = taxa, Bias = exp(rnorm(K, 0, 2))) %>%
14 | mutate(
15 | Bias = center_elts(Bias),
16 | )
17 | # Fake experimental dataset 1
18 | N <- 10
19 | samples <- paste0("S", seq(N))
20 | exp1 <- crossing(Sample = samples, Taxon = taxa) %>%
21 | left_join(bias, by = "Taxon")
22 | exp1 <- exp1 %>%
23 | mutate(
24 | Actual = rexp(n(), 1),
25 | Noise = exp(rnorm(n(), mean = log(1), sd = 0.5)),
26 | Observed = Actual * Bias * Noise
27 | ) %>%
28 | group_by(Sample) %>%
29 | # mutate_at(vars(Actual, Noise, Observed), center_elts) %>%
30 | ungroup
31 | # Fake experimental dataset 2
32 | exp2 <- exp1 %>%
33 | mutate(
34 | Actual = Actual * purrr::rbernoulli(n(), p = 0.66),
35 | Observed = Actual * Bias * Noise
36 | )
37 | # Fake experimental dataset 3
38 | exp3 <- exp1 %>%
39 | mutate(
40 | Actual = case_when(
41 | Sample <= "S5" & Taxon <= "T3" ~ Actual,
42 | Sample <= "S5" & Taxon > "T3" ~ 0,
43 | Sample > "S5" & Taxon <= "T3" ~ 0,
44 | Sample > "S5" & Taxon > "T3" ~ Actual,
45 | ),
46 | Observed = Actual * Bias * Noise
47 | )
48 | # Get compositional errors in matrix form
49 | d1 <- exp1 %>%
50 | transmute(Sample, Taxon, Error = Observed / Actual) %>%
51 | build_matrix(Sample, Taxon, Error)
52 | d2 <- exp2 %>%
53 | transmute(Sample, Taxon, Error = Observed / Actual) %>%
54 | build_matrix(Sample, Taxon, Error)
55 | d3 <- exp3 %>%
56 | transmute(Sample, Taxon, Error = Observed / Actual) %>%
57 | build_matrix(Sample, Taxon, Error)
58 | # Example set of weights
59 | w <- rmultinom(1, N, rep(1, N))[,1]
60 |
61 | # Deterministic datasets
62 | d4 <- exp1 %>%
63 | build_matrix(Sample, Taxon, Bias)
64 | d5 <- exp2 %>%
65 | transmute(Sample, Taxon, Error = Actual * Bias / Actual) %>%
66 | build_matrix(Sample, Taxon, Error)
67 |
68 | # TODO: Dataset w/ covariance in the errors
69 |
70 | # Detach everything to make sure metacal is importing correctly
71 | detach(package:tibble)
72 | detach(package:tidyr)
73 | detach(package:dplyr)
74 |
75 | # Mean ------------------------------------------------------------------------
76 |
77 | test_that("all methods agree when all samples have all taxa", {
78 | expect_equal(center(d1, method = "proj"), center(d1, method = "gm"))
79 | expect_equal(center(d1, method = "proj"), center(d1, method = "rss"),
80 | tolerance = 1e-5)
81 | })
82 |
83 | test_that("the 'proj' and 'rss' methods agree when samples have different taxa, but sufficient overlap", {
84 | expect_equal(center(d2, method = "proj"), center(d2, method = "rss"),
85 | tolerance = 1e-5)
86 | })
87 |
88 | test_that("the 'gm' method returns all NaNs when some taxa-sample observations are missing", {
89 | expect_equal(center(d2, method = "gm"),
90 | rlang::rep_named(colnames(d2), NaN))
91 | })
92 |
93 | test_that("the estimate does not depend on first normalizing the `weights`", {
94 | expect_equal(
95 | center(d2, weights = w, method = "rss"),
96 | center(d2, weights = w / sum(w), method = "rss"),
97 | tolerance = 1e-5)
98 | expect_equal(
99 | center(d2, weights = w, method = "proj"),
100 | center(d2, weights = w / sum(w), method = "proj"))
101 | expect_equal(
102 | center(d2, weights = w, method = "gm"),
103 | center(d2, weights = w / sum(w), method = "gm"))
104 | })
105 |
106 | test_that("sampling rows or using `weights` gives an equal estimate", {
107 | rows <- sample(N, N, replace = TRUE)
108 | w.rows <- table(factor(rows, seq(N))) %>% c
109 | expect_equal(
110 | center(d1[rows,], method = "gm"),
111 | center(d1, weights = w.rows, method = "gm"))
112 | expect_equal(
113 | center(d2[rows,], method = "proj"),
114 | center(d2, weights = w.rows, method = "proj"))
115 | expect_equal(
116 | center(d2[rows,], method = "rss"),
117 | center(d2, weights = w.rows, method = "rss"))
118 | })
119 |
120 | test_that("the center is correctly computed when sample and taxa names are missing", {
121 | d2.no_names <- d2
122 | rownames(d2.no_names) <- colnames(d2.no_names) <- NULL
123 | c1 <- center(d2)
124 | names(c1) <- NULL
125 | c2 <- center(d2.no_names)
126 | expect_equal(c1, c2)
127 | })
128 |
129 | # Additional tests to add
130 | # - Check various in scale and out scale combinations
131 | # - Check behavior in the exp3 case (bias not fully defined)
132 | # - Check that the projection method gives the right answer in the
133 | # deterministic missing observations case
134 |
135 | test_that("`bootrep_center()` output format", {
136 | bootreps <- bootrep_center(d2, R = 5, enframe = FALSE)
137 | bootreps.tb <- bootrep_center(d2, R = 5, enframe = TRUE)
138 | expect_identical(colnames(bootreps), colnames(bootreps))
139 | expect_identical(nrow(bootreps), 5L)
140 | expect_true(is.matrix(bootreps))
141 | expect_s3_class(bootreps.tb, "tbl_df")
142 | })
143 |
--------------------------------------------------------------------------------
/tests/testthat/test-ratios.R:
--------------------------------------------------------------------------------
1 | # run just this file:
2 | # devtools::test_active_file(here::here("tests", "testthat", "test-ratios.R"))
3 |
4 | data("enterotype", package = "phyloseq")
5 |
6 | # Test for issue #18 fix
7 | test_that("Maintains name with just 1 item on opposing margin; throws error if 1 item on given margin", {
8 | p0 <- enterotype %>%
9 | phyloseq::prune_taxa(taxa_names(.)[3], .) %>%
10 | phyloseq::prune_samples(sample_names(.)[1:5], .)
11 | p1 <- p0 %>% pairwise_ratios("samples")
12 | expect_equal(taxa_names(p1), taxa_names(p0))
13 | expect_error(p0 %>% pairwise_ratios("taxa"))
14 |
15 | p0 <- enterotype %>%
16 | phyloseq::prune_taxa(taxa_names(.)[3:5], .) %>%
17 | phyloseq::prune_samples(sample_names(.)[5], .)
18 | p1 <- p0 %>% pairwise_ratios("taxa")
19 | expect_equal(sample_names(p1), sample_names(p0))
20 | expect_error(p0 %>% pairwise_ratios("samples"))
21 | })
22 |
--------------------------------------------------------------------------------
/tests/testthat/test-utilities.R:
--------------------------------------------------------------------------------
1 | # run just this file:
2 | # devtools::test_active_file(here::here("tests", "testthat", "test-utilities.R"))
3 |
4 | # Setup: Load Brooks files
5 | x <- system.file("extdata", "brooks2015-actual.csv", package = "metacal") %>%
6 | readr::read_csv() %>%
7 | dplyr::arrange(Sample) # Not strictly needed since already in this order
8 | sam <- system.file("extdata", "brooks2015-sample-data.csv", package = "metacal") %>%
9 | readr::read_csv()
10 |
11 | test_that("`as_matrix()` and `build_matrix()` work as inverses", {
12 | y <- x %>%
13 | as_matrix(Sample)
14 | z <- x %>%
15 | tidyr::pivot_longer(-Sample) %>%
16 | build_matrix(Sample, name, value)
17 | expect_equal(y, z)
18 | })
19 |
20 | test_that("`build_matrix()` works on grouped variables", {
21 | y <- x %>%
22 | dplyr::left_join(sam, by = "Sample") %>%
23 | tidyr::pivot_longer(-colnames(sam), names_to = ".otu")
24 | z <- y %>%
25 | dplyr::group_by(Plate, .otu) %>%
26 | dplyr::summarize(across(value, sum), .groups = "drop_last") %>%
27 | build_matrix(Plate, .otu, value)
28 | expect_equal(
29 | rownames(z),
30 | sam$Plate %>% unique %>% as.character %>% sort
31 | )
32 | expect_equal(
33 | colnames(z),
34 | y$.otu %>% unique %>% sort
35 | )
36 | })
37 |
--------------------------------------------------------------------------------