recipe() accepts a phyloseq or
TreeSummarizedExperiment object. These containers connect
an abundance matrix to sample metadata and, when available, taxonomy.
Import files with the tools supplied by phyloseq or
mia, then inspect the resulting object before configuring
an analysis.
Importing data does not establish that their units, experimental design or taxonomic annotations are appropriate for a particular differential-abundance method.
Start with an existing phyloseq object
The package includes metaHIV_phy, with its recorded
sample metadata and taxonomy. No statistical model is needed to inspect
the data or define preprocessing steps.
library(dar)
data("metaHIV_phy", package = "dar")
rec <- recipe(metaHIV_phy)
rec
#> ── DAR Recipe ──────────────────────────────────────────────────────────────────
#> Inputs:
#>
#> ℹ phyloseq object with 451 taxa and 156 samples
#> ✖ undefined analysis target. Use add_model() to define the analysis!
#> ✖ undefined taxonomic level. Use add_model() to define the analysis!recipe() also accepts a phyloseq object
whose stored abundance matrix has samples in rows: the accessors below
return one consistent orientation. When constructing your own
phyloseq object, set taxa_are_rows to match
the actual matrix, rather than changing this flag without transposing
the data.
Inspect samples, taxonomy and abundances
Use the dar accessors explicitly when other attached packages export functions with the same names.
samples <- dar::sample_data(rec)
taxonomy <- dar::tax_table(rec)
abundances <- dar::otu_table(rec)
head(samples[c("sample_id", "RiskGroup2")])
#> # A tibble: 6 × 2
#> sample_id RiskGroup2
#> <chr> <chr>
#> 1 Sample_186 msm
#> 2 Sample_185 msm
#> 3 Sample_184 hts
#> 4 Sample_182 pwid
#> 5 Sample_181 msm
#> 6 Sample_170 msm
head(taxonomy)
#> # A tibble: 6 × 8
#> taxa_id Kingdom Phylum Class Order Family Genus Species
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 Otu_1 Archaea Euryarchaeota Methanobacteria Methanob… Metha… Meth… Methan…
#> 2 Otu_2 Archaea Euryarchaeota Methanobacteria Methanob… Metha… Meth… Methan…
#> 3 Otu_3 Bacteria Actinobacteria Actinobacteria Actinomy… Actin… Acti… Actino…
#> 4 Otu_4 Bacteria Actinobacteria Actinobacteria Actinomy… Actin… Acti… Actino…
#> 5 Otu_5 Bacteria Actinobacteria Actinobacteria Actinomy… Actin… Acti… Actino…
#> 6 Otu_6 Bacteria Actinobacteria Actinobacteria Actinomy… Actin… Acti… Actino…
abundances[seq_len(6), seq_len(5)]
#> # A tibble: 6 × 5
#> taxa_id Sample_186 Sample_185 Sample_184 Sample_182
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 Otu_1 2538 0 9026 12049
#> 2 Otu_2 0 0 0 609
#> 3 Otu_3 0 0 0 0
#> 4 Otu_4 0 0 0 0
#> 5 Otu_5 0 0 0 0
#> 6 Otu_6 0 0 0 0The accessors expose the complete stored components, independently of
the target or taxonomic rank later selected with
add_model():
-
sample_data()returnssample_idfollowed by all sample metadata columns, inphyloseq::sample_names()order. -
tax_table()returnstaxa_idfollowed by all taxonomic ranks, inphyloseq::taxa_names()order. -
otu_table()returns one row per taxon, withtaxa_idfirst and one column per sample. Taxon and sample order match the other two accessors.
stopifnot(
identical(colnames(abundances)[-1], samples$sample_id),
identical(abundances$taxa_id, taxonomy$taxa_id)
)Keep sample and taxon identifiers unique and consistent across input
files. Taxonomic labels are annotations, not replacements for feature
identifiers: several features can share a species name. Inspect missing
annotations and use standard rank names such as Kingdom,
Genus and Species.
If metadata or taxonomy is absent, the corresponding accessor returns
an ID-only tibble. That is sufficient for inspection, but it does not
supply the real covariates or taxonomic rank needed by a model. Add
genuine study metadata before calling add_model(); do not
manufacture groups just to make an example run.
Extract the shared taxonomic analysis view
Selecting tax_level = "Genus" with
add_model() does not replace the stored features returned
by otu_table(). tidy_abundance() instead
exposes the shared analysis view: counts are summed through the selected
rank, using the same taxon identities as differential-abundance results.
Features with the same label but different lineages remain distinct
analysis units.
genus_rec <- recipe(metaHIV_phy) |>
add_model(~ RiskGroup2, targets = "RiskGroup2", tax_level = "Genus")
genus_abundances <- tidy_abundance(genus_rec, metadata = "RiskGroup2")
head(genus_abundances)
#> # A tibble: 6 × 12
#> taxa_id taxa sample_id abundance taxonomy_Kingdom taxonomy_Phylum
#> <chr> <chr> <chr> <dbl> <chr> <chr>
#> 1 Otu_1 Methanobrevibact… Sample_1… 2538 Archaea Euryarchaeota
#> 2 Otu_1 Methanobrevibact… Sample_1… 0 Archaea Euryarchaeota
#> 3 Otu_1 Methanobrevibact… Sample_1… 9026 Archaea Euryarchaeota
#> 4 Otu_1 Methanobrevibact… Sample_1… 12049 Archaea Euryarchaeota
#> 5 Otu_1 Methanobrevibact… Sample_1… 22126 Archaea Euryarchaeota
#> 6 Otu_1 Methanobrevibact… Sample_1… 15374 Archaea Euryarchaeota
#> # ℹ 6 more variables: taxonomy_Class <chr>, taxonomy_Order <chr>,
#> # taxonomy_Family <chr>, taxonomy_Genus <chr>, taxonomy_Species <chr>,
#> # metadata_RiskGroup2 <chr>
data.frame(
stored_features = nrow(dar::otu_table(genus_rec)),
analysis_taxa = dplyr::n_distinct(genus_abundances$taxa_id)
)
#> stored_features analysis_taxa
#> 1 451 143The long table has one row per taxon and sample, with
taxa_id, taxa, sample_id and
abundance. Taxonomy has a taxonomy_ prefix and
selected sample metadata a metadata_ prefix, so annotations
cannot overwrite these columns. Supply original metadata names to
metadata; NULL includes all metadata and
character(0) excludes them. Lineage is retained through the
selected rank; lower ranks removed by aggregation remain missing.
For within-sample fractions, select
transform = "compositional". The denominator includes
all shared analysis taxa, before selecting taxon IDs;
fractions of a displayed subset need not sum to one.
selected_ids <- head(unique(genus_abundances$taxa_id), 2)
fractions <- tidy_abundance(
genus_rec, taxa_ids = selected_ids,
transform = "compositional", metadata = "RiskGroup2"
)
head(fractions)
#> # A tibble: 6 × 12
#> taxa_id taxa sample_id abundance taxonomy_Kingdom taxonomy_Phylum
#> <chr> <chr> <chr> <dbl> <chr> <chr>
#> 1 Otu_1 Methanobrevibact… Sample_1… 0.000597 Archaea Euryarchaeota
#> 2 Otu_1 Methanobrevibact… Sample_1… 0 Archaea Euryarchaeota
#> 3 Otu_1 Methanobrevibact… Sample_1… 0.000928 Archaea Euryarchaeota
#> 4 Otu_1 Methanobrevibact… Sample_1… 0.00182 Archaea Euryarchaeota
#> 5 Otu_1 Methanobrevibact… Sample_1… 0.00609 Archaea Euryarchaeota
#> 6 Otu_1 Methanobrevibact… Sample_1… 0.00160 Archaea Euryarchaeota
#> # ℹ 6 more variables: taxonomy_Class <chr>, taxonomy_Order <chr>,
#> # taxonomy_Family <chr>, taxonomy_Genus <chr>, taxonomy_Species <chr>,
#> # metadata_RiskGroup2 <chr>The default transform = "identity" preserves the stored
abundance scale while summing aggregated features. Extraction from an
unprepared recipe does not execute pending steps. A prepared recipe
includes common preprocessing and the shared model cohort, but this view
does not reproduce method-specific filtering, rarefaction or
transformations. It is not a table of adjusted predictions. For paired
graphics, include the actual visit and participant columns in
metadata and use them to group descriptive
trajectories.
Import a BIOM table
This example uses a file distributed with phyloseq,
without downloading data. The importer reads the sample metadata already
present in that file.
biom_file <- system.file(
"extdata", "rich_dense_otu_table.biom", package = "phyloseq"
)
phy <- phyloseq::import_biom(
biom_file,
parseFunction = phyloseq::parse_taxonomy_greengenes
)
biom_rec <- recipe(phy)
head(dar::sample_data(biom_rec))
#> # A tibble: 6 × 5
#> sample_id BarcodeSequence LinkerPrimerSequence BODY_SITE Description
#> <chr> <chr> <chr> <chr> <chr>
#> 1 Sample1 CGCTTATCGAGA CATGCTGCCTCCCGTAGGAGT gut human gut
#> 2 Sample2 CATACCAGTAGC CATGCTGCCTCCCGTAGGAGT gut human gut
#> 3 Sample3 CTCTCTACCTGT CATGCTGCCTCCCGTAGGAGT gut human gut
#> 4 Sample4 CTCTCGGCCTGT CATGCTGCCTCCCGTAGGAGT skin human skin
#> 5 Sample5 CTCTCTACCAAT CATGCTGCCTCCCGTAGGAGT skin human skin
#> 6 Sample6 CTAACTACCAAT CATGCTGCCTCCCGTAGGAGT skin human skin
head(dar::tax_table(biom_rec))
#> # A tibble: 5 × 8
#> taxa_id Kingdom Phylum Class Order Family Genus Species
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 GG_OTU_1 Bacteria Proteobacteria Gammaproteobacter… Ente… Enter… Esch… NA
#> 2 GG_OTU_2 Bacteria Cyanobacteria Nostocophycideae Nost… Nosto… Doli… NA
#> 3 GG_OTU_3 Archaea Euryarchaeota Methanomicrobia Meth… Metha… Meth… NA
#> 4 GG_OTU_4 Bacteria Firmicutes Clostridia Hala… Halan… Hala… Halana…
#> 5 GG_OTU_5 Bacteria Proteobacteria Gammaproteobacter… Ente… Enter… Esch… NAThe same file can be imported as a
TreeSummarizedExperiment. Rows of a TSE represent features,
columns represent samples, rowData() holds feature
annotations and colData() holds sample metadata.
tse <- mia::importBIOM(biom_file)
# This bundled example contains these seven ranks, in this order.
colnames(SummarizedExperiment::rowData(tse)) <- c(
"Kingdom", "Phylum", "Class", "Order", "Family", "Genus", "Species"
)
tse_rec <- recipe(tse)
head(dar::tax_table(tse_rec))
#> # A tibble: 5 × 8
#> taxa_id Kingdom Phylum Class Order Family Genus Species
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 GG_OTU_1 k__Bacteria p__Proteobacteria c__Gammapro… o__E… f__En… g__E… s__
#> 2 GG_OTU_2 k__Bacteria p__Cyanobacteria c__Nostocop… o__N… f__No… g__D… s__
#> 3 GG_OTU_3 k__Archaea p__Euryarchaeota c__Methanom… o__M… f__Me… g__M… s__
#> 4 GG_OTU_4 k__Bacteria p__Firmicutes c__Clostrid… o__H… f__Ha… g__H… s__Hal…
#> 5 GG_OTU_5 k__Bacteria p__Proteobacteria c__Gammapro… o__E… f__En… g__E… s__The rank relabeling above is specific to this file. Inspect the
annotations in your own data instead of assigning rank names by position
without checking their meaning. A TSE input is converted internally to
phyloseq; if the intended abundance table is not the
default assay, select it explicitly with
mia::convertToPhyloseq(..., assay.type = "your_assay")
before creating the recipe.
For other formats, consult the importers’ documentation rather than treating all formats as equivalent:
-
phyloseq::import_qiime()reads legacy QIIME tables;mia::importQIIME2()reads QIIME 2 artifacts. -
phyloseq::import_mothur()andmia::importMothur()read the supported mothur files. -
mia::importMetaPhlAn()reads MetaPhlAn abundance profiles.
For example, open the installed help with
help("importQIIME2", package = "mia") or
help("import_biom", package = "phyloseq").
Check the measurement scale
An abundance matrix can contain raw read counts, proportions, percentages or other transformed values. These are not interchangeable inputs. In particular, MetaPhlAn relative-abundance profiles are not raw read counts. Neither importing them nor converting their container makes them suitable for a count-based model; rounding percentages does not recover read counts.
Check the provenance and assay units, not just whether values happen to be integers. Retain raw counts when they are available and choose a method whose input requirements match the measurements. Missing values are also distinct from observed zeros.
For QC and filtering, continue with Quality control and preprocessing. For formulas, target variables and engine compatibility, see Statistical models and contrasts.
Session info
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] dar_1.9.12
#>
#> loaded via a namespace (and not attached):
#> [1] Rdpack_2.6.6 DBI_1.3.0
#> [3] gridExtra_2.3.1 permute_0.9-10
#> [5] rlang_1.3.0 magrittr_2.0.5
#> [7] ade4_1.7-24 scater_1.41.2
#> [9] otel_0.2.0 matrixStats_1.5.0
#> [11] compiler_4.6.1 DelayedMatrixStats_1.35.0
#> [13] mgcv_1.9-4 systemfonts_1.3.2
#> [15] vctrs_0.7.3 reshape2_1.4.5
#> [17] stringr_1.6.0 pkgconfig_2.0.3
#> [19] crayon_1.5.3 fastmap_1.2.0
#> [21] backports_1.5.1 XVector_0.53.0
#> [23] scuttle_1.23.2 utf8_1.2.6
#> [25] rmarkdown_2.32 ggbeeswarm_0.7.3
#> [27] DirichletMultinomial_1.55.1 ragg_1.5.2
#> [29] purrr_1.2.2 bluster_1.23.1
#> [31] MultiAssayExperiment_1.39.1 xfun_0.61
#> [33] cachem_1.1.0 beachmat_2.29.3
#> [35] jsonlite_2.0.0 biomformat_1.41.0
#> [37] DelayedArray_0.39.8 BiocParallel_1.47.0
#> [39] irlba_2.4.1 parallel_4.6.1
#> [41] cluster_2.1.8.3 R6_2.6.1
#> [43] bslib_0.12.0 stringi_1.8.9
#> [45] RColorBrewer_1.1-3 GenomicRanges_1.65.4
#> [47] jquerylib_0.1.4 Rcpp_1.1.2
#> [49] Seqinfo_1.3.2 SummarizedExperiment_1.43.0
#> [51] iterators_1.0.14 knitr_1.52
#> [53] DECIPHER_3.9.3 IRanges_2.47.5
#> [55] mia_1.21.11 Matrix_1.7-6
#> [57] splines_4.6.1 igraph_2.3.4
#> [59] tidyselect_1.2.1 viridis_0.6.5
#> [61] abind_1.4-8 yaml_2.3.12
#> [63] vegan_2.7-6 TreeSummarizedExperiment_2.21.0
#> [65] codetools_0.2-20 lattice_0.23-1
#> [67] tibble_3.3.1 plyr_1.8.9
#> [69] Biobase_2.73.2 treeio_1.37.1
#> [71] S7_0.2.2 evaluate_1.0.5
#> [73] desc_1.4.3 survival_3.8-12
#> [75] Biostrings_2.81.9 pillar_1.11.1
#> [77] phyloseq_1.57.0 MatrixGenerics_1.25.0
#> [79] checkmate_2.3.4 foreach_1.5.2
#> [81] stats4_4.6.1 reformulas_0.4.4
#> [83] generics_0.1.4 S4Vectors_0.51.10
#> [85] ggplot2_4.0.3 sparseMatrixStats_1.25.0
#> [87] scales_1.4.0 tidytree_0.4.8
#> [89] glue_1.8.1 lazyeval_0.2.3
#> [91] tools_4.6.1 BiocNeighbors_2.7.3
#> [93] data.table_1.18.6.1 ScaledMatrix_1.21.0
#> [95] fs_2.1.0 grid_4.6.1
#> [97] tidyr_1.3.2 ape_5.8-1
#> [99] rbibutils_2.4.1 SingleCellExperiment_1.35.2
#> [101] nlme_3.1-171 beeswarm_0.4.0
#> [103] BiocSingular_1.29.2 vipor_0.4.7
#> [105] cli_3.6.6 rsvd_1.0.5
#> [107] rappdirs_0.3.4 textshaping_1.0.5
#> [109] viridisLite_0.4.3 S4Arrays_1.13.2
#> [111] dplyr_1.2.1 gtable_0.3.6
#> [113] yulab.utils_0.2.5 sass_0.4.10
#> [115] digest_0.6.39 BiocGenerics_0.59.12
#> [117] ggrepel_0.9.8 SparseArray_1.13.4
#> [119] decontam_1.33.0 htmlwidgets_1.6.4
#> [121] farver_2.1.2 htmltools_0.5.9
#> [123] pkgdown_2.2.1 multtest_2.69.0
#> [125] lifecycle_1.0.5 MASS_7.3-66