| Title: | Cohort Objects for Subjects and Samples in Omics Studies |
|---|---|
| Description: | Keeps the subjects, samples, and analysis outputs of a study in one validated object. It starts from a sample manifest with one row per sample, which is read, checked, and split into a subject table and a sample map. Species and assay are plain values in those tables rather than fixed types, so the same object serves any organism and any omics assay. From that object the package writes the sample sheet a pipeline expects, pairs tumor and normal samples on demand, and records where each analysis writes its output so the files can be loaded back in by subject or by pair. Manual corrections are kept in an audit trail. Results can also be translated across genome builds or species, with liftover for coordinates and ortholog mapping for genes. |
| Authors: | Samuel Bharti [aut, cre, cph] (ORCID: <https://orcid.org/0000-0003-4190-7058>), Barret Schloerke [ths] (ORCID: <https://orcid.org/0000-0001-9986-114X>), Carson Sievert [ths] (ORCID: <https://orcid.org/0000-0002-4958-2844>), Posit Software, PBC [cph, fnd] (ROR: <https://ror.org/03wc8by49>) |
| Maintainer: | Samuel Bharti <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.1 |
| Built: | 2026-09-18 16:51:25 UTC |
| Source: | https://github.com/cran/biocohort |
biocohort keeps the subjects, samples, and analysis outputs of a study in
one validated object, called a Cohort. Species and assays are values in
the data, not columns or classes, so the same functions work for a rat
exome study, a mouse single-cell study, a proteomics study, or any other
organism and assay.
read_manifest() reads a manifest from CSV, TSV, or Excel and returns
subject_tbl and sample_map. manifest_from_wide() reshapes a wide,
one-row-per-subject table into the long form first.
validate_manifest() does the actual checking: it coerces every column
to character, fills in role and species where they are missing, and
splits subject-level columns from sample-level ones.
cohort_new() builds a Cohort from validated tables. study_new()
attaches optional project metadata (title, aims, genome builds).
subjects(), samples(), and completeness() return plain tibbles.
subject() reads one subject as a Subject object.
cohort_filter() keeps a subset of subjects or assays and returns a
cohort that is still valid.
sample_pairs() derives tumor and normal pairs from sample_map on
demand, with configurable role labels.
cohort_qc() flags or drops subjects or samples, with a required
reason. qc_log() reads the audit trail every call appends to the
cohort, which survives later cohort_filter() calls.
cohort_groups() groups a cohort's subjects by one or more columns.
cohort_contrasts() enumerates every pairwise contrast between those
groups, ready to filter one side against the other.
cohort_derive() bins an existing numeric column at named cutoffs and
writes the result as a new column, so a cutoff is a value passed in,
not code. derive_log() reads its provenance.
sample_sheet() writes the sample list a pipeline expects, with
built-in templates for a few common nf-core pipelines.
check_paths() tests that the file paths named in a cohort exist.
as_coldata() and join_metadata() carry cohort metadata into a
SummarizedExperiment, a Seurat object, or a plain data frame.
write_manifest(), cohort_save(), and cohort_read() keep a cohort
as a file in a project instead of a script that rebuilds it each time.
analysis_spec_new() and analysis_register() describe where an
analysis writes its output and how to read it back.
load_analysis() and load_analyses() resolve the path for every
subject or pair, read the files, and record which ones were found.
translate() moves a feature table across genome builds or species.
Coordinate features go through a liftover backend
(liftover_intervals()). Gene features go through an ortholog backend
(ortholog_genes()). Both kinds of backend are pluggable through
register_liftover_backend() and register_ortholog_backend().
read_study_yaml() builds a cohort from one YAML file that names the
study, the manifest, the file paths, and the registered analyses.
write_study_yaml() writes one back.
apply_corrections() and read_corrections() apply documented
overrides to a manifest and keep an audit trail.
subject_tbl: one row per subject. Always has subject_id and
species, plus any other subject-level metadata (sex, genotype,
strain, ...).
sample_map: one row per sample, in long format. Always has
subject_id, assay, sample_id, and role. A new assay is a new
row, never a new column.
completeness_tbl: one row per subject_id and assay pair, with the
sample count.
Three articles ship with the package.
vignette("biocohort", package = "biocohort") walks through a manifest,
a cohort, and a sample sheet end to end.
vignette("glossary", package = "biocohort") defines the terms used
across the package.
vignette("naming-conventions", package = "biocohort") lists the
standard names for columns, objects, and files.
Maintainer: Samuel Bharti [email protected] (ORCID) [copyright holder]
Authors:
Samuel Bharti [email protected] (ORCID) [copyright holder]
Other contributors:
Barret Schloerke [email protected] (ORCID) [thesis advisor]
Carson Sievert [email protected] (ORCID) [thesis advisor]
Posit Software, PBC (ROR) [copyright holder, funder]
Useful links:
Report bugs at https://github.com/samuelbharti/biocohort/issues
After load_analyses(), returns the per-analysis file manifests (resolved
paths and whether each existed) recorded during loading.
analysis_files(cohort)analysis_files(cohort)
cohort |
A Cohort produced by |
A named list of tibbles, one per loaded analysis. Each has the unit
keys, path, and exists. When the cohort has not been loaded, an empty
tibble with columns path and exists.
analysis_files(example_cohort)analysis_files(example_cohort)
Returns a tibble with one row per registered AnalysisSpec in a Cohort. Summarizes key metadata for quick inspection of available analyses.
analysis_list(cohort)analysis_list(cohort)
cohort |
A Cohort object. |
The returned tibble includes only the most essential metadata fields
for discovery and filtering. Use analysis_spec() to retrieve the
full AnalysisSpec object including description, path_template, and
key_cols.
A tibble with the following columns:
name: Analysis name (chr)
assay: Assay type (chr)
level: Data level - "subject", "pair", or "cohort" (chr)
format: File format (chr)
reader: Reader function name (chr)
root_key: Optional root path key (chr)
If the cohort has no registered specs, returns an empty tibble with these columns.
analysis_register() for registering specs,
analysis_spec() for retrieving a full spec object
# Create and register specs study <- study_new(study_id = "STUDY001", title = "My Study") manifest <- data.frame( subject_id = c("S1", "S1", "S2", "S2"), species = c("rat", "rat", "rat", "rat"), assay = c("wes", "wes", "wes", "wes"), sample_id = c("WES_T1", "WES_N1", "WES_T2", "WES_N2"), role = c("tumor", "normal", "tumor", "normal") ) parsed <- validate_manifest(manifest) cohort <- cohort_new( subject_tbl = parsed$subject_tbl, sample_map = parsed$sample_map, study = study ) spec1 <- analysis_spec_new( name = "somatic_vars", assay = "wes", level = "pair", format = "tsv", reader = "read_tsv", key_cols = c("pair_id") ) spec2 <- analysis_spec_new( name = "gene_expr", assay = "scrna", level = "subject", format = "rds", reader = "readRDS", key_cols = c("subject_id") ) cohort <- analysis_register(cohort, spec1) cohort <- analysis_register(cohort, spec2) analysis_list(cohort)# Create and register specs study <- study_new(study_id = "STUDY001", title = "My Study") manifest <- data.frame( subject_id = c("S1", "S1", "S2", "S2"), species = c("rat", "rat", "rat", "rat"), assay = c("wes", "wes", "wes", "wes"), sample_id = c("WES_T1", "WES_N1", "WES_T2", "WES_N2"), role = c("tumor", "normal", "tumor", "normal") ) parsed <- validate_manifest(manifest) cohort <- cohort_new( subject_tbl = parsed$subject_tbl, sample_map = parsed$sample_map, study = study ) spec1 <- analysis_spec_new( name = "somatic_vars", assay = "wes", level = "pair", format = "tsv", reader = "read_tsv", key_cols = c("pair_id") ) spec2 <- analysis_spec_new( name = "gene_expr", assay = "scrna", level = "subject", format = "rds", reader = "readRDS", key_cols = c("subject_id") ) cohort <- analysis_register(cohort, spec1) cohort <- analysis_register(cohort, spec2) analysis_list(cohort)
Registers an AnalysisSpec in a Cohort's registry, enabling standardized access and discovery of analysis specifications. Returns a new Cohort object with the spec added (immutable update pattern).
analysis_register(cohort, spec)analysis_register(cohort, spec)
cohort |
A Cohort object to update. |
spec |
An AnalysisSpec object to register. The spec name is used as the registry key. |
Validates that:
cohort is a Cohort object
spec is an AnalysisSpec object
A new Cohort object with the spec added to the registry. If a spec with the same name already exists, it is replaced. Note that this follows the immutable S7 pattern: the original cohort is not modified.
analysis_spec_new() for creating specs,
analysis_list() for listing registered specs,
analysis_spec() for retrieving a spec from registry
# Create a cohort study <- study_new(study_id = "STUDY001", title = "My Study") manifest <- data.frame( subject_id = c("S1", "S1", "S2", "S2"), species = c("rat", "rat", "rat", "rat"), assay = c("wes", "wes", "wes", "wes"), sample_id = c("WES_T1", "WES_N1", "WES_T2", "WES_N2"), role = c("tumor", "normal", "tumor", "normal") ) parsed <- validate_manifest(manifest) cohort <- cohort_new( subject_tbl = parsed$subject_tbl, sample_map = parsed$sample_map, study = study ) # Create and register an analysis spec spec <- analysis_spec_new( name = "somatic_vars", assay = "wes", level = "pair", format = "tsv", reader = "read_tsv", key_cols = c("pair_id") ) cohort_with_spec <- analysis_register(cohort, spec) print(analysis_list(cohort_with_spec))# Create a cohort study <- study_new(study_id = "STUDY001", title = "My Study") manifest <- data.frame( subject_id = c("S1", "S1", "S2", "S2"), species = c("rat", "rat", "rat", "rat"), assay = c("wes", "wes", "wes", "wes"), sample_id = c("WES_T1", "WES_N1", "WES_T2", "WES_N2"), role = c("tumor", "normal", "tumor", "normal") ) parsed <- validate_manifest(manifest) cohort <- cohort_new( subject_tbl = parsed$subject_tbl, sample_map = parsed$sample_map, study = study ) # Create and register an analysis spec spec <- analysis_spec_new( name = "somatic_vars", assay = "wes", level = "pair", format = "tsv", reader = "read_tsv", key_cols = c("pair_id") ) cohort_with_spec <- analysis_register(cohort, spec) print(analysis_list(cohort_with_spec))
Retrieves a fully-specified AnalysisSpec object from a Cohort's registry by name. Useful for accessing all properties of a registered analysis (description, path_template, key_cols, etc.).
analysis_spec(cohort, name)analysis_spec(cohort, name)
cohort |
A Cohort object. |
name |
Character scalar with the name of the AnalysisSpec to retrieve. |
Raises an informative error if the spec name is not found in the registry.
The AnalysisSpec object if found.
analysis_register() for registering specs,
analysis_list() for listing all registered specs
# Create and register a spec study <- study_new(study_id = "STUDY001", title = "My Study") manifest <- data.frame( subject_id = c("S1", "S1", "S2", "S2"), species = c("rat", "rat", "rat", "rat"), assay = c("wes", "wes", "wes", "wes"), sample_id = c("WES_T1", "WES_N1", "WES_T2", "WES_N2"), role = c("tumor", "normal", "tumor", "normal") ) parsed <- validate_manifest(manifest) cohort <- cohort_new( subject_tbl = parsed$subject_tbl, sample_map = parsed$sample_map, study = study ) spec <- analysis_spec_new( name = "somatic_vars", assay = "wes", level = "pair", format = "tsv", reader = "read_tsv", key_cols = c("pair_id") ) cohort_with_spec <- analysis_register(cohort, spec) # Retrieve the spec retrieved_spec <- analysis_spec(cohort_with_spec, "somatic_vars") print(retrieved_spec@reader) # "read_tsv"# Create and register a spec study <- study_new(study_id = "STUDY001", title = "My Study") manifest <- data.frame( subject_id = c("S1", "S1", "S2", "S2"), species = c("rat", "rat", "rat", "rat"), assay = c("wes", "wes", "wes", "wes"), sample_id = c("WES_T1", "WES_N1", "WES_T2", "WES_N2"), role = c("tumor", "normal", "tumor", "normal") ) parsed <- validate_manifest(manifest) cohort <- cohort_new( subject_tbl = parsed$subject_tbl, sample_map = parsed$sample_map, study = study ) spec <- analysis_spec_new( name = "somatic_vars", assay = "wes", level = "pair", format = "tsv", reader = "read_tsv", key_cols = c("pair_id") ) cohort_with_spec <- analysis_register(cohort, spec) # Retrieve the spec retrieved_spec <- analysis_spec(cohort_with_spec, "somatic_vars") print(retrieved_spec@reader) # "read_tsv"
Constructs an AnalysisSpec object that defines how to locate, read, and
interpret a specific analysis output. Validates all required fields and
fills format, reader, and key_cols with defaults when they are not
given.
analysis_spec_new( name, assay, level, format = NA_character_, description = NA_character_, path_template = NA_character_, root_key = NA_character_, reader = NA_character_, key_cols = NULL, feature_type = NA_character_, gene_col = NA_character_, id_type = NA_character_, tumor_role = "tumor", normal_role = "normal", pair_sep = "__" )analysis_spec_new( name, assay, level, format = NA_character_, description = NA_character_, path_template = NA_character_, root_key = NA_character_, reader = NA_character_, key_cols = NULL, feature_type = NA_character_, gene_col = NA_character_, id_type = NA_character_, tumor_role = "tumor", normal_role = "normal", pair_sep = "__" )
name |
Character scalar for unique analysis name. Must be at least 1 character long. Serves as key in the cohort registry. |
assay |
Character scalar for the assay label, spelled as in the
cohort's |
level |
Character scalar for the granularity at which the analysis
produces results. Must be one of |
format |
Character scalar for file format (e.g., "rds", "tsv", "txt").
Optional. Defaults to the extension of |
description |
Character scalar for human-readable description. Optional, defaults to NA. |
path_template |
Character scalar for templated file path. Supports
tokens: |
root_key |
Character scalar for key in cohort@paths to use as |
reader |
Character scalar for reader function name (e.g.,
"readr::read_tsv", "read.csv"). Optional. Defaults by |
key_cols |
Character vector of column names that must be present in
the loaded table. Optional. Defaults by |
feature_type |
Optional character scalar declaring how this analysis's
features are translated across species by |
gene_col |
Optional character scalar naming the gene-identifier column,
used when |
id_type |
Optional gene identifier type for |
tumor_role |
Character scalar naming the sample role on the tumor (or
case) side of a pair. Passed to |
normal_role |
Character scalar naming the sample role on the normal (or
control) side of a pair. Passed to |
pair_sep |
Character scalar placed between the two sample ids in
|
This constructor validates that:
name and assay are non-empty strings
level is one of: "subject", "pair", "cohort"
format and reader, if given, are non-empty strings
key_cols is a character vector, non-empty for subject and pair specs
feature_type, if given, is one of "interval" or "gene"
id_type, if given, is one of "symbol", "entrez", "ensembl"
tumor_role, normal_role, and pair_sep are non-empty strings
An AnalysisSpec object with validated fields.
AnalysisSpec for class documentation,
analysis_register() for registering in a Cohort
# A pair-level somatic variant spec. format, reader, and key_cols come # from the template extension and the level. spec_sv <- analysis_spec_new( name = "somatic_vars", assay = "wes", level = "pair", description = "Somatic variants in tumor-normal pairs", path_template = "{root}/somatic/{pair_id}.variants.tsv", root_key = "wes_root" ) spec_sv@format spec_sv@reader spec_sv@key_cols # A subject-level gene expression spec with an explicit reader. spec_expr <- analysis_spec_new( name = "gene_expression", assay = "scrna", level = "subject", format = "rds", description = "Gene expression by subject", path_template = "{root}/{subject_id}/expr.rds", root_key = "scrna_root", reader = "readRDS", key_cols = c("subject_id", "gene") ) # A pair spec for a sample map that labels roles case and control. spec_cc <- analysis_spec_new( name = "case_control", assay = "wgs", level = "pair", path_template = "{root}/{pair_id}.csv", root_key = "wgs_root", tumor_role = "case", normal_role = "control", pair_sep = "_vs_" )# A pair-level somatic variant spec. format, reader, and key_cols come # from the template extension and the level. spec_sv <- analysis_spec_new( name = "somatic_vars", assay = "wes", level = "pair", description = "Somatic variants in tumor-normal pairs", path_template = "{root}/somatic/{pair_id}.variants.tsv", root_key = "wes_root" ) spec_sv@format spec_sv@reader spec_sv@key_cols # A subject-level gene expression spec with an explicit reader. spec_expr <- analysis_spec_new( name = "gene_expression", assay = "scrna", level = "subject", format = "rds", description = "Gene expression by subject", path_template = "{root}/{subject_id}/expr.rds", root_key = "scrna_root", reader = "readRDS", key_cols = c("subject_id", "gene") ) # A pair spec for a sample map that labels roles case and control. spec_cc <- analysis_spec_new( name = "case_control", assay = "wgs", level = "pair", path_template = "{root}/{pair_id}.csv", root_key = "wgs_root", tumor_role = "case", normal_role = "control", pair_sep = "_vs_" )
An immutable S7 class for defining analysis specifications in a Cohort. AnalysisSpec objects describe how to locate, read, and interpret analysis output files with templated paths and standardized readers.
AnalysisSpec( name = character(0), assay = character(0), level = character(0), format = NA_character_, description = NA_character_, path_template = NA_character_, root_key = NA_character_, reader = NA_character_, key_cols = character(0), feature_type = NA_character_, gene_col = NA_character_, id_type = NA_character_, tumor_role = "tumor", normal_role = "normal", pair_sep = "__" )AnalysisSpec( name = character(0), assay = character(0), level = character(0), format = NA_character_, description = NA_character_, path_template = NA_character_, root_key = NA_character_, reader = NA_character_, key_cols = character(0), feature_type = NA_character_, gene_col = NA_character_, id_type = NA_character_, tumor_role = "tumor", normal_role = "normal", pair_sep = "__" )
name |
Character scalar for unique analysis name (key in registry). |
assay |
Character scalar for the assay label, spelled as in the
cohort's |
level |
Character scalar for the granularity at which the analysis produces results. Must be one of:
Required. |
format |
Character scalar for file format (e.g., "rds", "tsv", "txt").
Optional. |
description |
Character scalar for human-readable description of the analysis. Optional, defaults to NA. |
path_template |
Character scalar for templated path to analysis output.
Supports substitution tokens: |
root_key |
Character scalar for key in cohort@paths list to use as
the |
reader |
Character scalar for function name to read files matching
this spec (e.g., "readr::read_tsv", "read.csv"). Optional.
|
key_cols |
Character vector of column names that must be present in
the loaded analysis table. |
feature_type |
Optional character scalar declaring how this analysis's
features translate across species in |
gene_col |
Optional character scalar naming the gene-identifier column
for |
id_type |
Optional gene identifier type for |
tumor_role |
Character scalar naming the sample role on the tumor (or
case) side of a pair. Used for |
normal_role |
Character scalar naming the sample role on the normal (or
control) side of a pair. Used for |
pair_sep |
Character scalar placed between the two sample ids when
|
Use analysis_spec_new() to construct AnalysisSpec objects with immediate
validation. AnalysisSpec objects are typically registered in a Cohort via
analysis_register().
Access properties via the @ operator:
spec@name spec@assay spec@level spec@format spec@description spec@path_template spec@root_key spec@reader spec@key_cols spec@tumor_role spec@normal_role spec@pair_sep
An AnalysisSpec object with the given properties.
analysis_spec_new() for object construction,
analysis_register() for registering specs in a Cohort
# The raw constructor. analysis_spec_new() fills format, reader, and # key_cols in from the path template and the level; this does not. spec <- AnalysisSpec( name = "somatic_vars", assay = "wes", level = "pair", format = "tsv", reader = "readr::read_tsv", key_cols = c("subject_id", "pair_id") ) spec@level spec@key_cols# The raw constructor. analysis_spec_new() fills format, reader, and # key_cols in from the path template and the level; this does not. spec <- AnalysisSpec( name = "somatic_vars", assay = "wes", level = "pair", format = "tsv", reader = "readr::read_tsv", key_cols = c("subject_id", "pair_id") ) spec@level spec@key_cols
Applies a corrections table to a long-format manifest, one row per sample, and records what changed. A study keeps its overrides in one table with a reason for each, instead of inline edits spread over scripts.
apply_corrections(manifest, corrections)apply_corrections(manifest, corrections)
manifest |
A data frame with one row per sample and at least a
|
corrections |
A data frame with columns |
A subject correction changes every manifest row for that subject. A sample
correction changes the row or rows for that sample. Corrections are
applied in order, so a later row can overwrite an earlier one for the same
cell. A corrected column becomes character, and an NA value clears the
cell.
The audit table has one row per correction: level, id, column,
old_value, new_value, reason, and n_rows, the number of manifest
rows that changed. When the old values differ across those rows they are
joined with "; ". Applying corrections to an already corrected manifest
appends to the existing audit table.
The function errors when a required column of corrections is missing,
when a level is not "subject" or "sample", when an id is not in the
manifest, or when a column is not in the manifest.
The corrected manifest as a tibble. The "corrections" attribute
holds the audit table, which corrections_log() returns.
read_corrections(), corrections_log()
manifest <- tibble::tibble( subject_id = c("R1", "R1", "R2"), assay = c("wes", "wes", "wes"), sample_id = c("R1_T", "R1_N", "R2_T"), genotype = c("WT", "WT", "KO"), fastq = c("r1_t.fq.gz", "r1_n.fq.gz", "r2_t.fq.gz") ) corrections <- tibble::tibble( level = c("subject", "sample"), id = c("R1", "R2_T"), column = c("genotype", "fastq"), value = c("KO", "r2_tumor.fq.gz"), reason = c("genotyping rerun on 2026-03-01", "vendor renamed the file") ) corrected <- apply_corrections(manifest, corrections) corrected corrections_log(corrected)manifest <- tibble::tibble( subject_id = c("R1", "R1", "R2"), assay = c("wes", "wes", "wes"), sample_id = c("R1_T", "R1_N", "R2_T"), genotype = c("WT", "WT", "KO"), fastq = c("r1_t.fq.gz", "r1_n.fq.gz", "r2_t.fq.gz") ) corrections <- tibble::tibble( level = c("subject", "sample"), id = c("R1", "R2_T"), column = c("genotype", "fastq"), value = c("KO", "r2_tumor.fq.gz"), reason = c("genotyping rerun on 2026-03-01", "vendor renamed the file") ) corrected <- apply_corrections(manifest, corrections) corrected corrections_log(corrected)
Joins a cohort's sample map and subject table for one assay, and returns
the result as a base data.frame with row names set to a sample id column.
This is the shape colData (SummarizedExperiment, DESeq2) and similar
analysis objects expect.
as_coldata(cohort, assay, samples = NULL, rownames = "sample_id", ref = NULL)as_coldata(cohort, assay, samples = NULL, rownames = "sample_id", ref = NULL)
cohort |
A Cohort object. |
assay |
Character scalar naming the assay to include. |
samples |
Optional character vector of sample ids, in the order they
should appear (matching, for example, the column order of a count
matrix). Every id must be one of the cohort's samples for |
rownames |
Character scalar naming the column to use as row names.
Default |
ref |
Optional named list. Each name is a column to convert to a
factor, and each value the level to use as the reference (first) level,
as in |
A data.frame with one row per sample, row names set to
rownames, ordered to match samples when given.
data(example_cohort) coldata <- as_coldata(example_cohort, assay = "wes") coldata as_coldata(example_cohort, assay = "wes", ref = list(genotype = "WT"))data(example_cohort) coldata <- as_coldata(example_cohort, assay = "wes") coldata as_coldata(example_cohort, assay = "wes", ref = list(genotype = "WT"))
Tests every path a cohort references: the file-like columns of its sample
map (fastq_1, bam, and similar), and every entry of cohort@paths.
Never errors; a summary is reported when something is missing.
check_paths(cohort, cols = NULL)check_paths(cohort, cols = NULL)
cohort |
A Cohort object. |
cols |
Optional character vector of |
A tibble with one row per checked path and columns source
("sample_map" or "paths"), key (sample_id, or the name in
cohort@paths), column (the sample_map column, NA for a
cohort@paths entry), path, and exists. exists is NA for a
missing (NA) path, so an unset path is not read as a broken one.
data(example_cohort) check_paths(example_cohort)data(example_cohort) check_paths(example_cohort)
An S7 class that keeps the subjects and samples of a study in one object. A Cohort holds a subject table, a long-format sample map, an optional Study, file paths, analysis tables, and a registry of analysis specs.
Cohort( study = NULL, subject_tbl = tibble::tibble(subject_id = character(), species = character()), sample_map = tibble::tibble(subject_id = character(), assay = character(), sample_id = character(), role = character()), paths = list(), analyses = list(), registry = list(), cache = list(), qc = tibble::tibble(scope = character(), id = character(), action = character(), reason = character(), previous_status = character(), timestamp = as.POSIXct(character())), derived = tibble::tibble(name = character(), from = character(), level = character(), cutoffs = list(), n_derived = integer(), n_na = integer(), timestamp = as.POSIXct(character())) )Cohort( study = NULL, subject_tbl = tibble::tibble(subject_id = character(), species = character()), sample_map = tibble::tibble(subject_id = character(), assay = character(), sample_id = character(), role = character()), paths = list(), analyses = list(), registry = list(), cache = list(), qc = tibble::tibble(scope = character(), id = character(), action = character(), reason = character(), previous_status = character(), timestamp = as.POSIXct(character())), derived = tibble::tibble(name = character(), from = character(), level = character(), cutoffs = list(), n_derived = integer(), n_na = integer(), timestamp = as.POSIXct(character())) )
study |
A Study object with project-level context, or NULL. |
subject_tbl |
A data frame with one row per subject. Required columns:
|
sample_map |
A long-format data frame with one row per sample.
Required columns: |
paths |
Named list of file paths to data files or result folders. Defaults to an empty list. |
analyses |
Named list of analysis tables or other data objects. Defaults to an empty list. |
registry |
Named list of AnalysisSpec objects. Names match
|
cache |
Named list used to memoize loaded analysis data. Cleared by
|
qc |
A tibble recording every |
derived |
A tibble recording every |
Use cohort_new() to build a Cohort. It checks the input types, converts
both tables to tibbles, and runs validate_cohort(). Construction itself
also checks subject_tbl and sample_map with the same rules, so building
a Cohort any other way still enforces the required columns.
Subjects live only in subject_tbl. Use subject() to read one row as a
Subject object.
Access properties with the @ operator:
cohort@study # Study object or NULL cohort@subject_tbl # Subject metadata table cohort@sample_map # Sample mapping table cohort@paths # File paths cohort@analyses # Stored analysis results cohort@registry # Named list of AnalysisSpec objects cohort@cache # Memoization cache cohort@qc # QC audit log cohort@derived # Derived-column provenance
A Cohort object with the given properties.
cohort_new() for object construction,
subject() for reading one subject,
validate_cohort() for validation details,
validate_manifest() for manifest preparation,
read_manifest_csv() for loading manifest from file,
analysis_register() for registering analyses
# An empty cohort has the required columns and nothing else. empty <- Cohort() empty@subject_tbl empty@sample_map # The raw constructor runs the same checks as cohort_new(). cohort <- Cohort( subject_tbl = data.frame(subject_id = "R1", species = "rat"), sample_map = data.frame( subject_id = "R1", assay = "wes", sample_id = "T1", role = "tumor" ) ) cohort# An empty cohort has the required columns and nothing else. empty <- Cohort() empty@subject_tbl empty@sample_map # The raw constructor runs the same checks as cohort_new(). cohort <- Cohort( subject_tbl = data.frame(subject_id = "R1", species = "rat"), sample_map = data.frame( subject_id = "R1", assay = "wes", sample_id = "T1", role = "tumor" ) ) cohort
Enumerates every pairwise combination of the groups in x, so a caller
can turn each pair into a comparison (for example, filtering a cohort down
to one side and diffing an analysis table against the other).
cohort_contrasts(x, by = NULL)cohort_contrasts(x, by = NULL)
x |
Either a Cohort (then |
by |
Character vector of |
This is deliberately minimal: it does not repeat the raw by values on
each row. Join back to cohort_groups()'s output on group_label for
those.
A tibble with one row per pair: group_a, group_b (the two
groups' labels), subject_ids_a, subject_ids_b (list-columns of
subject ids), and n_a, n_b (their sizes).
cohort_groups(), cohort_filter()
data(example_cohort) contrasts <- cohort_contrasts(example_cohort, by = "species") contrasts cohort_filter(example_cohort, subject_ids = contrasts$subject_ids_a[[1]])data(example_cohort) contrasts <- cohort_contrasts(example_cohort, by = "species") contrasts cohort_filter(example_cohort, subject_ids = contrasts$subject_ids_a[[1]])
Bins an existing numeric column into named groups at one or more cutoff values, and writes the result as a new column, so a rule like "early onset is 120 days or under" is a value you pass in, not code you write.
cohort_derive(cohort, name, from, cutoffs, level)cohort_derive(cohort, name, from, cutoffs, level)
cohort |
A Cohort object. |
name |
Character scalar naming the new column. |
from |
Character scalar naming an existing numeric (or numeric-coercible) column to bin. |
cutoffs |
A named numeric vector. Sorted internally, so the order given does not matter. See Details for how names become bins. |
level |
One of |
Sort cutoffs by value. Bin i is everything up to and including
cutoffs[i], labeled names(cutoffs)[i]. The bin above the highest
cutoff is NA, unless the highest cutoff is itself Inf with its own
name, in which case that bin is fully covered.
So cutoffs = c(early_onset = 120) gives two groups: "early_onset" for
values at or under 120, and NA above it, a legitimate pattern when only
the named group matters. To cover every value, name the top bin too:
cutoffs = c(early_onset = 120, late_onset = Inf). More than one real
cutoff works the same way, at no extra cost.
A value in from that is not already missing but fails to parse as
numeric is an error naming the offending ids, never a silent NA. A
value that was already missing stays NA in the derived column.
Re-deriving with the same name overwrites the column, the same way
analysis_register() replaces a spec of the same name. Every call is
recorded in derive_log(), which, like qc_log(), is not cleared by
cohort_filter().
A new Cohort.
manifest <- data.frame( subject_id = c("S1", "S2", "S3"), species = "rat", onset_days = c(90, 150, 200), assay = "wes", sample_id = c("a", "b", "c"), role = "tumor" ) parsed <- validate_manifest(manifest) cohort <- cohort_new(parsed$subject_tbl, parsed$sample_map) # Only the named group matters; everything above 120 is NA. only_named <- cohort_derive( cohort, "early_only", from = "onset_days", cutoffs = c(early_onset = 120), level = "subject" ) subjects(only_named) # Fully covering two groups with an Inf-capped top cutoff. covered <- cohort_derive( cohort, "onset_group", from = "onset_days", cutoffs = c(early = 120, late = Inf), level = "subject" ) subjects(covered) derive_log(covered)manifest <- data.frame( subject_id = c("S1", "S2", "S3"), species = "rat", onset_days = c(90, 150, 200), assay = "wes", sample_id = c("a", "b", "c"), role = "tumor" ) parsed <- validate_manifest(manifest) cohort <- cohort_new(parsed$subject_tbl, parsed$sample_map) # Only the named group matters; everything above 120 is NA. only_named <- cohort_derive( cohort, "early_only", from = "onset_days", cutoffs = c(early_onset = 120), level = "subject" ) subjects(only_named) # Fully covering two groups with an Inf-capped top cutoff. covered <- cohort_derive( cohort, "onset_group", from = "onset_days", cutoffs = c(early = 120, late = Inf), level = "subject" ) subjects(covered) derive_log(covered)
Filters a cohort's subject table and sample map together, so the result
stays a valid Cohort. Any loaded analysis table that has a subject_id
column is filtered to match; the registry and paths are kept as they are.
cohort_filter( cohort, ..., subject_ids = NULL, assays = NULL, drop_sample_ids = NULL, drop_empty = TRUE )cohort_filter( cohort, ..., subject_ids = NULL, assays = NULL, drop_sample_ids = NULL, drop_empty = TRUE )
cohort |
A Cohort object. |
... |
Data-masked filter expressions evaluated against
|
subject_ids |
Optional character vector. Keep only these subject ids. |
assays |
Optional character vector. Keep only sample rows with these assays. |
drop_sample_ids |
Optional character vector. Remove sample rows with
these sample ids. Unlike |
drop_empty |
Logical. When |
The five ways to narrow a cohort combine: ... and subject_ids both
narrow subject_tbl, and assays/drop_sample_ids narrow sample_map.
sample_map is always restricted to the subjects that remain in
subject_tbl after ... and subject_ids, regardless of drop_empty.
A new Cohort. The cache is reset, since it can hold loaded
data or a translation result computed for the full set of subjects.
subjects(), samples(), cohort_new()
data(example_cohort) # By an expression on subject_tbl cohort_filter(example_cohort, species == "rat") # By explicit ids cohort_filter(example_cohort, subject_ids = c("RAT001", "MOUSE001")) # By assay, dropping subjects left with no sample cohort_filter(example_cohort, assays = "scrna") # By excluding specific sample ids (e.g. samples that failed QC) bad_id <- samples(example_cohort)$sample_id[[1]] cohort_filter(example_cohort, drop_sample_ids = bad_id)data(example_cohort) # By an expression on subject_tbl cohort_filter(example_cohort, species == "rat") # By explicit ids cohort_filter(example_cohort, subject_ids = c("RAT001", "MOUSE001")) # By assay, dropping subjects left with no sample cohort_filter(example_cohort, assays = "scrna") # By excluding specific sample ids (e.g. samples that failed QC) bad_id <- samples(example_cohort)$sample_id[[1]] cohort_filter(example_cohort, drop_sample_ids = bad_id)
Groups cohort@subject_tbl by the given columns and returns one row per
combination that actually occurs, with the matching subject ids.
cohort_groups(cohort, by)cohort_groups(cohort, by)
cohort |
A Cohort object. |
by |
Character vector of one or more |
Only combinations that occur in subject_tbl appear; this never invents
a row for a combination of values that no subject has. An NA in a by
column forms its own group rather than being dropped.
A tibble with the by columns, group_label (the by values
pasted together with "/"), n (the number of subjects), and
subject_ids (a list-column of sorted, unique subject ids).
cohort_contrasts(), subjects()
data(example_cohort) cohort_groups(example_cohort, by = "species")data(example_cohort) cohort_groups(example_cohort, by = "species")
Builds a Cohort from a subject table and a sample map, with an optional
Study, file paths, and analysis tables. The two tables are usually the
output of validate_manifest().
cohort_new( subject_tbl, sample_map, study = NULL, paths = list(), analyses = list() )cohort_new( subject_tbl, sample_map, study = NULL, paths = list(), analyses = list() )
subject_tbl |
A data frame with one row per subject. Required columns:
|
sample_map |
A long-format data frame with one row per sample.
Required columns: |
study |
A Study object, or NULL. Defaults to NULL. |
paths |
Named list of file paths to data files or result folders. Defaults to an empty list. |
analyses |
Named list of analysis tables or other data objects. Defaults to an empty list. |
The steps are:
Check that subject_tbl and sample_map are data frames.
Convert both to tibbles.
Build the Cohort.
Run validate_cohort().
The function does not build Subject objects. Use subject() to read one
subject from the cohort when an object is needed.
A Cohort object. An error when the tables fail
validate_cohort().
validate_manifest() for preparing input tables,
validate_cohort() for the checks,
subject() for reading one subject,
Study for study metadata
study <- study_new( study_id = "STUDY001", title = "Cross-species study", assays = c("WES", "snRNA-seq") ) # A long-format manifest: one row per sample manifest <- data.frame( subject_id = c("RAT001", "RAT001", "MOUSE1", "MOUSE1"), species = c("rat", "rat", "mouse", "mouse"), sex = c("M", "M", "F", "F"), assay = c("wes", "scrna", "wes", "atac"), sample_id = c("WES_T1", "RNA_1", "WES_T2", "ATAC_1"), role = c("tumor", "tumor", "tumor", NA) ) parsed <- validate_manifest(manifest) cohort <- cohort_new( study = study, subject_tbl = parsed$subject_tbl, sample_map = parsed$sample_map ) print(cohort) # Read one subject as a Subject object subject(cohort, "RAT001")study <- study_new( study_id = "STUDY001", title = "Cross-species study", assays = c("WES", "snRNA-seq") ) # A long-format manifest: one row per sample manifest <- data.frame( subject_id = c("RAT001", "RAT001", "MOUSE1", "MOUSE1"), species = c("rat", "rat", "mouse", "mouse"), sex = c("M", "M", "F", "F"), assay = c("wes", "scrna", "wes", "atac"), sample_id = c("WES_T1", "RNA_1", "WES_T2", "ATAC_1"), role = c("tumor", "tumor", "tumor", NA) ) parsed <- validate_manifest(manifest) cohort <- cohort_new( study = study, subject_tbl = parsed$subject_tbl, sample_map = parsed$sample_map ) print(cohort) # Read one subject as a Subject object subject(cohort, "RAT001")
Records a QC decision against a cohort: either annotate matching rows
with a status and reason (action = "flag"), or remove them
(action = "drop"). Every call is recorded in the cohort's QC log (see
qc_log()), which is not cleared by cohort_filter(), so the record of
why something was dropped survives later structural changes.
cohort_qc(cohort, ids, scope, action, reason)cohort_qc(cohort, ids, scope, action, reason)
cohort |
A Cohort object. |
ids |
Character vector of ids to act on. At least one, no |
scope |
One of |
action |
One of |
reason |
A single, non-empty string explaining the decision. |
An id in ids that does not exist for the given scope is an error; it
is never silently ignored.
action = "flag", scope = "sample" sets qc_status/qc_reason on
sample_map, creating the columns if they are absent. scope = "subject"
sets the same two column names on subject_tbl instead; these are a
separate pair of columns from the sample-level ones, and both can be set
on the same cohort for different reasons. Flagging an id that already has
a qc_reason appends the new reason rather than replacing it.
action = "drop" delegates to cohort_filter(): scope = "sample" uses
its drop_sample_ids argument, with drop_empty = FALSE so a subject
left with no samples is not also removed; scope = "subject" uses its
subject_ids argument to keep every other subject. Either way, the
resulting cache reset is the same one a direct cohort_filter() call
would produce.
sample_id is normally unique, so qc_log()'s previous_status reflects
the one matching row. If sample_map holds duplicate sample_ids (built
with allow_duplicates = TRUE), every matching row is still flagged or
dropped correctly, but the logged previous_status reflects only one of
them.
A new Cohort.
data(example_cohort) # Flag one sample, keeping it bad_id <- samples(example_cohort)$sample_id[[1]] flagged <- cohort_qc( example_cohort, bad_id, scope = "sample", action = "flag", reason = "failed QC review" ) samples(flagged) qc_log(flagged) # Drop the same sample instead dropped <- cohort_qc( example_cohort, bad_id, scope = "sample", action = "drop", reason = "failed QC review" ) nrow(samples(dropped)) < nrow(samples(example_cohort))data(example_cohort) # Flag one sample, keeping it bad_id <- samples(example_cohort)$sample_id[[1]] flagged <- cohort_qc( example_cohort, bad_id, scope = "sample", action = "flag", reason = "failed QC review" ) samples(flagged) qc_log(flagged) # Drop the same sample instead dropped <- cohort_qc( example_cohort, bad_id, scope = "sample", action = "drop", reason = "failed QC review" ) nrow(samples(dropped)) < nrow(samples(example_cohort))
Reads the RDS file, checks it is a cohort file, and re-validates the cohort before returning it.
cohort_read(path)cohort_read(path)
path |
Path to a file written by |
The Cohort object.
data(example_cohort) path <- tempfile(fileext = ".rds") cohort_save(example_cohort, path) restored <- cohort_read(path) identical(subjects(restored), subjects(example_cohort)) unlink(path)data(example_cohort) path <- tempfile(fileext = ".rds") cohort_save(example_cohort, path) restored <- cohort_read(path) identical(subjects(restored), subjects(example_cohort)) unlink(path)
Wraps a Cohort with a small format marker and the package version, and
writes it with saveRDS(). Read it back with cohort_read().
cohort_save(cohort, path)cohort_save(cohort, path)
cohort |
A Cohort object. |
path |
Output file path, conventionally ending in |
path, invisibly.
cohort_read(), write_manifest()
data(example_cohort) path <- tempfile(fileext = ".rds") cohort_save(example_cohort, path) cohort_read(path) unlink(path)data(example_cohort) path <- tempfile(fileext = ".rds") cohort_save(example_cohort, path) cohort_read(path) unlink(path)
Summarizes how many samples each subject has for each assay. This is the table most studies ask for first: which subjects are missing which assay.
completeness(cohort, wide = FALSE)completeness(cohort, wide = FALSE)
cohort |
A Cohort object. |
wide |
Logical. When |
The wide form always has one row per subject in cohort@subject_tbl, even
a subject with zero samples for every assay, and one column per assay
that appears anywhere in cohort@sample_map.
A tibble. See wide above for its shape.
subjects(), samples(), validate_manifest()
data(example_cohort) completeness(example_cohort) completeness(example_cohort, wide = TRUE)data(example_cohort) completeness(example_cohort) completeness(example_cohort, wide = TRUE)
Reads the "corrections" attribute that apply_corrections() sets.
corrections_log(x)corrections_log(x)
x |
A manifest, corrected or not. |
A tibble with columns level, id, column, old_value,
new_value, reason, and n_rows. It has no rows when x has not been
corrected.
manifest <- tibble::tibble(subject_id = "R1", sample_id = "R1_T") corrections_log(manifest)manifest <- tibble::tibble(subject_id = "R1", sample_id = "R1_T") corrections_log(manifest)
A thin, named accessor for cohort@derived, the provenance every
cohort_derive() call appends to.
derive_log(cohort)derive_log(cohort)
cohort |
A Cohort object. |
cohort@derived as a tibble.
data(example_cohort) derive_log(example_cohort)data(example_cohort) derive_log(example_cohort)
Creates path and its parents with fs::dir_create() when the folder does
not exist yet. An existing folder is left alone.
ensure_dir(path)ensure_dir(path)
path |
Folder to create. |
path, invisibly.
out <- fs::path(tempfile(), "results", "qc") ensure_dir(out) fs::dir_exists(out) unlink(fs::path_dir(fs::path_dir(out)), recursive = TRUE)out <- fs::path(tempfile(), "results", "qc") ensure_dir(out) fs::dir_exists(out) unlink(fs::path_dir(fs::path_dir(out)), recursive = TRUE)
A small Cohort with two rat and two mouse subjects. Use it to explore the data model, to try the API, or as a template for a cohort built from real data.
example_cohortexample_cohort
A Cohort object (S7 class) with the following structure:
study: A Study object with metadata for a cross-species genomics project
subject_tbl (tibble): 4 subjects (2 rat, 2 mouse) with species, sex, strain, genotype, cohort, timepoint
sample_map (tibble): Long-format map (subject_id, assay, sample_id, role, fastq_1, fastq_2) covering WES tumor/normal and snRNA-seq samples. fastq_1/fastq_2 show that an extra sample-level column survives validate_manifest() alongside the four canonical ones.
paths (list): Empty, ready for file paths
analyses (list): Empty, ready for analysis results
The cohort shows:
Two species in one subject table
Two assays per subject in one long-format sample map
A Study object for project context
Subjects are stored as rows of subject_tbl. Use subject() to read one
of them as a Subject object.
cohort_new() for creating Cohort objects,
subject() for reading one subject,
validate_manifest() for preparing manifest data,
read_manifest_csv() for loading manifest from CSV file
# Load the example cohort data(example_cohort) # View the study metadata example_cohort@study # Read one subject as a Subject object rat1 <- subject(example_cohort, "RAT001") rat1@species rat1@sex # List all subject ids example_cohort@subject_tbl$subject_id # View all subjects with metadata example_cohort@subject_tbl # View the sample map example_cohort@sample_map # Count subjects by species table(example_cohort@subject_tbl$species)# Load the example cohort data(example_cohort) # View the study metadata example_cohort@study # Read one subject as a Subject object rat1 <- subject(example_cohort, "RAT001") rat1@species rat1@sex # List all subject ids example_cohort@subject_tbl$subject_id # View all subjects with metadata example_cohort@subject_tbl # View the sample map example_cohort@sample_map # Count subjects by species table(example_cohort@subject_tbl$species)
Joins a cohort's sample and subject metadata onto a data.frame, a
SummarizedExperiment, or a Seurat object, matched by sample id.
join_metadata(object, cohort, assay = NULL, by = "sample_id", col = NULL)join_metadata(object, cohort, assay = NULL, by = "sample_id", col = NULL)
object |
A data.frame, a |
cohort |
A Cohort object. |
assay |
Optional character scalar restricting the join to one
assay's samples. Defaults to |
by |
Character scalar naming the sample id column to join on.
Default |
col |
For a |
A SummarizedExperiment or Seurat column that does not match any
sample in the cohort is an error, naming the unmatched ids. A data.frame
join is a plain left join, so it keeps every row of object and leaves
an unmatched row's new columns as NA.
object, with the cohort's metadata columns added: joined
columns for a data.frame, added colData columns for a
SummarizedExperiment, added meta.data columns for a Seurat object.
data(example_cohort) expr <- data.frame( sample_id = example_cohort@sample_map$sample_id[1:2], value = c(1, 2) ) join_metadata(expr, example_cohort)data(example_cohort) expr <- data.frame( sample_id = example_cohort@sample_map$sample_id[1:2], value = c(1, 2) ) join_metadata(expr, example_cohort)
List registered liftover backends
liftover_backends()liftover_backends()
A character vector of registered backend names.
register_liftover_backend(), liftover_intervals()
liftover_backends()liftover_backends()
Liftover backend that shells out to the external
CrossMap tool (CrossMap bed).
CrossMap must be installed and on the PATH. For most interval workflows the
R-native liftover_rtracklayer() backend is sufficient and easier to deploy;
CrossMap is most valuable for allele-aware variant translation (see
liftover_vcf()).
liftover_crossmap(intervals, chain, crossmap = NULL, ...)liftover_crossmap(intervals, chain, crossmap = NULL, ...)
intervals |
A tibble of intervals (see |
chain |
Path to a chain file. |
crossmap |
Path or name of the CrossMap executable. Defaults to
auto-detection on the |
... |
Unused. |
A list with mapped and unmapped tibbles.
liftover_intervals(), liftover_rtracklayer(), liftover_vcf()
if (nzchar(Sys.which("CrossMap")) || nzchar(Sys.which("CrossMap.py"))) { chain <- tempfile(fileext = ".chain") writeLines( c( "chain 1000 chr1 100000 + 0 1000 chrT 200000 + 10000 11000 1", "1000", "" ), chain ) ints <- tibble::tibble( seqnames = c("chr1", "chr1"), start = c(100, 5000), end = c(200, 5100), .feature_id = 1:2 ) out <- liftover_crossmap(ints, chain) out$mapped unlink(chain) }if (nzchar(Sys.which("CrossMap")) || nzchar(Sys.which("CrossMap.py"))) { chain <- tempfile(fileext = ".chain") writeLines( c( "chain 1000 chr1 100000 + 0 1000 chrT 200000 + 10000 11000 1", "1000", "" ), chain ) ints <- tibble::tibble( seqnames = c("chr1", "chr1"), start = c(100, 5000), end = c(200, 5100), .feature_id = 1:2 ) out <- liftover_crossmap(ints, chain) out$mapped unlink(chain) }
Translates coordinate features (intervals such as variants, peaks, or regions) from one genome assembly or species to another using a chain file, via a pluggable backend. Returns a TranslationResult that keeps both the mapped and the unmapped features, so loss is explicit.
liftover_intervals( intervals, chain, from = NA_character_, to = NA_character_, backend = "rtracklayer", ... )liftover_intervals( intervals, chain, from = NA_character_, to = NA_character_, backend = "rtracklayer", ... )
intervals |
A data.frame or tibble of intervals. Required columns:
|
chain |
Path to a chain file (e.g. a UCSC |
from, to
|
Optional character scalars recording the source and target assembly/species for provenance. |
backend |
Either the name of a registered backend (see
|
... |
Additional arguments passed to the backend. |
Cross-species liftover is inherently lossy and limited to syntenic, alignable
regions; non-conserved regions (and many regulatory elements) will not map.
Always inspect translation_stats() and the unmapped table rather than
assuming full recovery. For allele-aware variant (VCF) translation, see
liftover_vcf().
liftover_rtracklayer(), liftover_crossmap(), translate()
ints <- data.frame( seqnames = c("chr1", "chr1"), start = c(100, 5000), end = c(200, 5100) ) # Illustrative in-memory backend (maps the first interval, drops the rest): backend <- function(intervals, chain, ...) { list( mapped = tibble::tibble( .feature_id = intervals$.feature_id[1], seqnames = "chrT", start = 1L, end = 100L, strand = "*" ), unmapped = intervals[-1, , drop = FALSE] ) } res <- liftover_intervals(ints, chain = "none", to = "human", backend = backend) translation_stats(res)ints <- data.frame( seqnames = c("chr1", "chr1"), start = c(100, 5000), end = c(200, 5100) ) # Illustrative in-memory backend (maps the first interval, drops the rest): backend <- function(intervals, chain, ...) { list( mapped = tibble::tibble( .feature_id = intervals$.feature_id[1], seqnames = "chrT", start = 1L, end = 100L, strand = "*" ), unmapped = intervals[-1, , drop = FALSE] ) } res <- liftover_intervals(ints, chain = "none", to = "human", backend = backend) translation_stats(res)
R-native liftover backend using rtracklayer::liftOver() with a UCSC chain
file. This is the default backend for liftover_intervals(); it requires no
external tools but needs the Bioconductor packages rtracklayer,
GenomicRanges, IRanges, and S4Vectors.
liftover_rtracklayer(intervals, chain, ...)liftover_rtracklayer(intervals, chain, ...)
intervals |
A tibble of intervals with |
chain |
Path to a UCSC chain file. |
... |
Unused. |
A list with mapped and unmapped tibbles.
liftover_intervals(), liftover_crossmap()
# rtracklayer and the packages it depends on take a few seconds to load. if ( requireNamespace("rtracklayer", quietly = TRUE) && requireNamespace("GenomicRanges", quietly = TRUE) ) { chain <- tempfile(fileext = ".chain") writeLines( c( "chain 1000 chr1 100000 + 0 1000 chrT 200000 + 10000 11000 1", "1000", "" ), chain ) ints <- tibble::tibble( seqnames = c("chr1", "chr1"), start = c(100, 5000), end = c(200, 5100), .feature_id = 1:2 ) out <- liftover_rtracklayer(ints, chain) out$mapped unlink(chain) }# rtracklayer and the packages it depends on take a few seconds to load. if ( requireNamespace("rtracklayer", quietly = TRUE) && requireNamespace("GenomicRanges", quietly = TRUE) ) { chain <- tempfile(fileext = ".chain") writeLines( c( "chain 1000 chr1 100000 + 0 1000 chrT 200000 + 10000 11000 1", "1000", "" ), chain ) ints <- tibble::tibble( seqnames = c("chr1", "chr1"), start = c(100, 5000), end = c(200, 5100), .feature_id = 1:2 ) out <- liftover_rtracklayer(ints, chain) out$mapped unlink(chain) }
Thin, experimental wrapper around CrossMap vcf, which performs allele-aware
variant liftover (updating the REF allele against the target genome and
handling strand flips) – something plain interval liftover does not do.
Requires CrossMap on the PATH and a target-genome FASTA.
liftover_vcf( vcf, chain, ref_fasta, out = tempfile(fileext = ".vcf"), from = NA_character_, to = NA_character_, crossmap = NULL )liftover_vcf( vcf, chain, ref_fasta, out = tempfile(fileext = ".vcf"), from = NA_character_, to = NA_character_, crossmap = NULL )
vcf |
Path to the input VCF. |
chain |
Path to a chain file. |
ref_fasta |
Path to the target-genome FASTA. |
out |
Output VCF path. Defaults to a temporary file. |
from, to
|
Optional provenance strings. |
crossmap |
Path or name of the CrossMap executable. Defaults to
auto-detection on the |
This function is experimental and intentionally minimal: it runs CrossMap and
reports the produced paths and unmapped count rather than parsing variants
into R. Parse the output VCF with your tool of choice (e.g.
VariantAnnotation).
A TranslationResult whose mapped and unmapped carry the output
and unmapped VCF paths; stats records the number of unmapped records.
liftover_intervals(), liftover_crossmap()
## Not run: # Not run: needs CrossMap on the PATH, a chain file, and the target # genome as a FASTA file, none of which ship with the package. res <- liftover_vcf( vcf = "calls.rn7.vcf", chain = "rn7ToHg38.over.chain", ref_fasta = "hg38.fa", from = "rn7", to = "hg38" ) res@mapped$path # the lifted VCF res@unmapped$path # the records CrossMap could not place res@stats$n_unmapped ## End(Not run)## Not run: # Not run: needs CrossMap on the PATH, a chain file, and the target # genome as a FASTA file, none of which ship with the package. res <- liftover_vcf( vcf = "calls.rn7.vcf", chain = "rn7ToHg38.over.chain", ref_fasta = "hg38.fa", from = "rn7", to = "hg38" ) res@mapped$path # the lifted VCF res@unmapped$path # the records CrossMap could not place res@stats$n_unmapped ## End(Not run)
Loads the feature table for each registered AnalysisSpec (via
load_analysis()) and returns a new Cohort with analyses populated. The
per-analysis file manifests are stored in the cohort cache and retrievable
with analysis_files(). This is the step that takes a cohort from paths to
loaded feature tables, ready for translate().
load_analyses(cohort, analyses = NULL, readers = NULL)load_analyses(cohort, analyses = NULL, readers = NULL)
cohort |
A Cohort with registered specs (see |
analyses |
Optional character vector restricting which registered
analyses to load. Defaults to all that have a |
readers |
Optional named list of reader overrides, keyed by analysis
name (each a function or |
Specs without a path_template are skipped with a warning. Use
analysis_files() to inspect which files were found or missing.
A new Cohort with analyses populated for the loaded specs.
load_analysis(), analysis_files(), translate()
# One per-subject CSV on disk, one registered spec that points at it. dir <- tempfile() dir.create(dir) write.csv( data.frame(gene = "TP53", value = 1), file.path(dir, "S1.csv"), row.names = FALSE ) manifest <- data.frame( subject_id = "S1", species = "human", assay = "rna", sample_id = "x" ) parsed <- validate_manifest(manifest) cohort <- cohort_new( parsed$subject_tbl, parsed$sample_map, paths = list(rna_root = dir) ) spec <- analysis_spec_new( name = "expr", assay = "rna", level = "subject", path_template = "{root}/{subject_id}.csv", root_key = "rna_root" ) cohort <- analysis_register(cohort, spec) loaded <- load_analyses(cohort) loaded@analyses$expr analysis_files(loaded) unlink(dir, recursive = TRUE)# One per-subject CSV on disk, one registered spec that points at it. dir <- tempfile() dir.create(dir) write.csv( data.frame(gene = "TP53", value = 1), file.path(dir, "S1.csv"), row.names = FALSE ) manifest <- data.frame( subject_id = "S1", species = "human", assay = "rna", sample_id = "x" ) parsed <- validate_manifest(manifest) cohort <- cohort_new( parsed$subject_tbl, parsed$sample_map, paths = list(rna_root = dir) ) spec <- analysis_spec_new( name = "expr", assay = "rna", level = "subject", path_template = "{root}/{subject_id}.csv", root_key = "rna_root" ) cohort <- analysis_register(cohort, spec) loaded <- load_analyses(cohort) loaded@analyses$expr analysis_files(loaded) unlink(dir, recursive = TRUE)
Resolves an AnalysisSpec's path_template for each unit implied by its
level (one file per subject, per pair, or one for the whole cohort), reads
the existing files with the spec's reader, and row-binds them into a single
feature table annotated with provenance keys (subject_id and/or pair_id).
load_analysis(cohort, spec, reader = NULL)load_analysis(cohort, spec, reader = NULL)
cohort |
A Cohort providing |
spec |
An AnalysisSpec or the name of one registered in |
reader |
Optional reader override: a function, or a |
Units follow the spec's assay. A subject-level spec enumerates only the
subjects with at least one sample of that assay. A pair-level spec calls
sample_pairs() with the spec's assay, tumor_role, normal_role, and
pair_sep. When no subject or pair matches, the function warns and returns
empty tables.
Path tokens supported: {root} (from cohort@paths[[root_key]]),
{subject_id}, and for pair-level specs {tumor_sample_id},
{normal_sample_id}, {pair_id} (derived via sample_pairs()). Missing
files are skipped (with a warning) and recorded in files, so loading is
never silently partial.
The reader comes from the reader argument, else from the spec. The
function errors when neither names one. After each file is read, the spec's
key_cols must be present in the table (the provenance keys count), or the
function errors and names the missing columns.
A list with:
data: a tibble of all loaded rows (empty if no files were found),
with provenance key columns added.
files: a tibble with one row per unit: its keys, the resolved path,
and whether it exists.
# Write a per-subject CSV, then load it. dir <- tempfile() dir.create(dir) write.csv( data.frame(gene = "TP53", value = 1), file.path(dir, "S1.csv"), row.names = FALSE ) manifest <- data.frame( subject_id = "S1", species = "human", assay = "rna", sample_id = "x" ) parsed <- validate_manifest(manifest) cohort <- cohort_new( subject_tbl = parsed$subject_tbl, sample_map = parsed$sample_map, paths = list(rna_root = dir) ) # format, reader, and key_cols come from the template and the level. spec <- analysis_spec_new( name = "expr", assay = "rna", level = "subject", path_template = "{root}/{subject_id}.csv", root_key = "rna_root", feature_type = "gene" ) loaded <- load_analysis(cohort, spec) loaded$data loaded$files# Write a per-subject CSV, then load it. dir <- tempfile() dir.create(dir) write.csv( data.frame(gene = "TP53", value = 1), file.path(dir, "S1.csv"), row.names = FALSE ) manifest <- data.frame( subject_id = "S1", species = "human", assay = "rna", sample_id = "x" ) parsed <- validate_manifest(manifest) cohort <- cohort_new( subject_tbl = parsed$subject_tbl, sample_map = parsed$sample_map, paths = list(rna_root = dir) ) # format, reader, and key_cols come from the template and the level. spec <- analysis_spec_new( name = "expr", assay = "rna", level = "subject", path_template = "{root}/{subject_id}.csv", root_key = "rna_root", feature_type = "gene" ) loaded <- load_analysis(cohort, spec) loaded$data loaded$files
Many sample sheets start wide: one row per subject, with one column per
assay-and-role combination (e.g. wes_tumor_id, wes_normal_id,
scrna_id). This turns such a table into the long format
validate_manifest() expects, one row per non-missing sample id.
manifest_from_wide(x, id_cols, subject_id = "subject_id")manifest_from_wide(x, id_cols, subject_id = "subject_id")
x |
A data.frame or tibble, one row per subject. |
id_cols |
A data.frame or tibble describing the columns of
|
subject_id |
Character scalar naming the subject id column in |
A blank or NA value in an id column contributes no row, so a subject
missing one assay is not stamped with an empty sample id.
A long-format tibble: one row per non-missing sample id in any
id_cols$column, with subject_id, assay, sample_id, role, and
every column of x that is not in id_cols$column. Pass it to
validate_manifest() next.
read_manifest(), validate_manifest()
wide <- data.frame( subject_id = c("R1", "R2"), species = "rat", wes_tumor_id = c("WES_T1", "WES_T2"), wes_normal_id = c("WES_N1", NA), scrna_id = c("SC_1", "SC_2") ) id_cols <- data.frame( column = c("wes_tumor_id", "wes_normal_id", "scrna_id"), assay = c("wes", "wes", "scrna"), role = c("tumor", "normal", NA) ) long <- manifest_from_wide(wide, id_cols) long validate_manifest(long)wide <- data.frame( subject_id = c("R1", "R2"), species = "rat", wes_tumor_id = c("WES_T1", "WES_T2"), wes_normal_id = c("WES_N1", NA), scrna_id = c("SC_1", "SC_2") ) id_cols <- data.frame( column = c("wes_tumor_id", "wes_normal_id", "scrna_id"), assay = c("wes", "wes", "scrna"), role = c("tumor", "normal", NA) ) long <- manifest_from_wide(wide, id_cols) long validate_manifest(long)
Gene-ortholog backend using the offline babelgene package, which ships
precomputed orthologs between human and a range of model organisms. This is
the default backend for ortholog_genes().
ortholog_babelgene(features, from, to, gene_col, id_type, cache = NULL, ...)ortholog_babelgene(features, from, to, gene_col, id_type, cache = NULL, ...)
features |
A tibble of features with a gene column and a |
from, to
|
Source and target species (e.g. |
gene_col |
Name of the gene-identifier column. |
id_type |
One of |
cache |
Optional path to a TSV file caching prior lookups. When
given, a gene already in the file is read from there instead of
queried again, and a newly queried gene is appended for next time. The
cache is shared across |
... |
Passed to |
A list with mapped and unmapped tibbles.
if (requireNamespace("babelgene", quietly = TRUE)) { feats <- tibble::tibble(gene = c("TP53", "MYC"), .feature_id = 1:2) out <- ortholog_babelgene( feats, from = "human", to = "mouse", gene_col = "gene", id_type = "symbol" ) out$mapped }if (requireNamespace("babelgene", quietly = TRUE)) { feats <- tibble::tibble(gene = c("TP53", "MYC"), .feature_id = 1:2) out <- ortholog_babelgene( feats, from = "human", to = "mouse", gene_col = "gene", id_type = "symbol" ) out$mapped }
List registered ortholog backends
ortholog_backends()ortholog_backends()
A character vector of registered backend names.
register_ortholog_backend(), ortholog_genes()
ortholog_backends()ortholog_backends()
Translates gene-level features (a table with a gene-identifier column) from one species to another via a pluggable ortholog backend. Returns a TranslationResult retaining both mapped and unmapped rows, so loss is explicit.
ortholog_genes( features, from, to, gene_col = "gene", id_type = c("symbol", "entrez", "ensembl"), backend = "babelgene", ... )ortholog_genes( features, from, to, gene_col = "gene", id_type = c("symbol", "entrez", "ensembl"), backend = "babelgene", ... )
features |
A data.frame or tibble with one column of gene identifiers
( |
from, to
|
Character scalars naming the source and target species (e.g.
|
gene_col |
Name of the column in |
id_type |
Identifier type: one of |
backend |
Either the name of a registered backend (see
|
... |
Additional arguments passed to the backend. |
Ortholog mapping is many-to-many in general: a gene may have zero, one, or
several orthologs. Inspect translation_stats() and the unmapped table
rather than assuming one-to-one correspondence.
A TranslationResult. mapped contains the input columns plus an
ortholog column with target-species identifiers (one input gene may yield
multiple ortholog rows).
translate(), ortholog_babelgene(), TranslationResult
features <- data.frame( gene = c("TP53", "MYC", "NOT_A_GENE"), expr = c(1.2, 3.4, 5.6) ) # Illustrative in-memory backend (uppercases to a fake "ortholog"): backend <- function(features, from, to, gene_col, id_type, ...) { ok <- features[[gene_col]] != "NOT_A_GENE" mapped <- features[ok, , drop = FALSE] mapped$ortholog <- tolower(mapped[[gene_col]]) list(mapped = mapped, unmapped = features[!ok, , drop = FALSE]) } ortholog_genes(features, from = "human", to = "mouse", backend = backend)features <- data.frame( gene = c("TP53", "MYC", "NOT_A_GENE"), expr = c(1.2, 3.4, 5.6) ) # Illustrative in-memory backend (uppercases to a fake "ortholog"): backend <- function(features, from, to, gene_col, id_type, ...) { ok <- features[[gene_col]] != "NOT_A_GENE" mapped <- features[ok, , drop = FALSE] mapped$ortholog <- tolower(mapped[[gene_col]]) list(mapped = mapped, unmapped = features[!ok, , drop = FALSE]) } ortholog_genes(features, from = "human", to = "mouse", backend = backend)
orthologize() is the earlier name for translate(). It still works and
calls translate() with the same arguments, and warns once per session.
New code should call translate() directly.
orthologize(x, to, from = NULL, ...)orthologize(x, to, from = NULL, ...)
x |
The thing to translate. Either:
|
to |
Character scalar naming the target species/assembly. |
from |
For a feature table, a character scalar naming the source
species/assembly; required for the |
... |
Strategy-specific arguments. For a feature table:
For a Cohort:
|
See translate().
Joins path pieces to the project root with fs::path(). Nothing is
created on disk.
project_path(..., root = project_root())project_path(..., root = project_root())
... |
Path pieces, as in |
root |
Folder to join to. Defaults to |
An fs_path.
project_path("data", "manifest.csv", root = "/study")project_path("data", "manifest.csv", root = "/study")
Walks up from start until a folder holds one of the markers. The
default markers are a .git entry, a DESCRIPTION file, or any file that
ends in .Rproj. Scripts can then build paths from the root instead of
from the working directory.
project_root(start = ".", markers = c(".git", "DESCRIPTION", ".Rproj"))project_root(start = ".", markers = c(".git", "DESCRIPTION", ".Rproj"))
start |
Folder to start from. Defaults to the working directory. |
markers |
Character vector of names to look for. A marker matches an
entry with the same name. A marker that starts with a dot, such as
|
The absolute, normalized path of the first folder that holds a
marker, as an fs_path.
project_path() to join paths under the root.
root <- fs::path(tempfile(), "study") fs::dir_create(fs::path(root, "scripts", "qc")) fs::file_create(fs::path(root, "DESCRIPTION")) project_root(fs::path(root, "scripts", "qc")) unlink(fs::path_dir(root), recursive = TRUE)root <- fs::path(tempfile(), "study") fs::dir_create(fs::path(root, "scripts", "qc")) fs::file_create(fs::path(root, "DESCRIPTION")) project_root(fs::path(root, "scripts", "qc")) unlink(fs::path_dir(root), recursive = TRUE)
A thin, named accessor for cohort@qc, the audit trail every
cohort_qc() call appends to.
qc_log(cohort)qc_log(cohort)
cohort |
A Cohort object. |
cohort@qc as a tibble.
data(example_cohort) qc_log(example_cohort)data(example_cohort) qc_log(example_cohort)
Reads a CSV or TSV file, chosen by extension, with every column as
character, and checks that the columns apply_corrections() needs are
present. An empty value or NA in the file becomes NA.
read_corrections(path)read_corrections(path)
path |
Path to a |
A tibble with character columns level, id, column, value,
and reason, plus any other column in the file.
path <- tempfile(fileext = ".csv") writeLines( c( "level,id,column,value,reason", "subject,R1,genotype,KO,genotyping rerun", "sample,R2_T,fastq,r2_tumor.fq.gz,vendor renamed the file" ), path ) read_corrections(path) unlink(path)path <- tempfile(fileext = ".csv") writeLines( c( "level,id,column,value,reason", "subject,R1,genotype,KO,genotyping rerun", "sample,R2_T,fastq,r2_tumor.fq.gz,vendor renamed the file" ), path ) read_corrections(path) unlink(path)
Reads KEY=value lines from a dotenv file and sets them with
Sys.setenv(). Blank lines and lines that start with # are skipped.
Whitespace around keys and values is trimmed. One pair of matching single
or double quotes around a value is removed. A key that is already set in
the environment is left alone unless overwrite = TRUE. When a key repeats
in the file, the last line wins. Values are never printed.
read_dotenv(path = NULL, overwrite = FALSE)read_dotenv(path = NULL, overwrite = FALSE)
path |
Path to the file. Defaults to |
overwrite |
Replace variables that are already set? Defaults to
|
A named character vector of every value read from the file, invisibly. Keys that were skipped because they were already set are included.
env_file <- tempfile(fileext = ".env") writeLines( c( "# analysis settings", "BIOCOHORT_EXAMPLE_THREADS = 4", "BIOCOHORT_EXAMPLE_LABEL = 'batch one'" ), env_file ) vars <- read_dotenv(env_file) names(vars) Sys.getenv("BIOCOHORT_EXAMPLE_LABEL") Sys.unsetenv(names(vars)) unlink(env_file)env_file <- tempfile(fileext = ".env") writeLines( c( "# analysis settings", "BIOCOHORT_EXAMPLE_THREADS = 4", "BIOCOHORT_EXAMPLE_LABEL = 'batch one'" ), env_file ) vars <- read_dotenv(env_file) names(vars) Sys.getenv("BIOCOHORT_EXAMPLE_LABEL") Sys.unsetenv(names(vars)) unlink(env_file)
Reads a manifest from CSV, TSV, or Excel and delegates to
validate_manifest() for validation and structuring. Every column is
read as character, so an id like "007" or "1.10" is never silently
turned into a number.
read_manifest( path, ..., delim = NULL, sheet = NULL, sample_cols = NULL, species = NULL, allow_duplicates = FALSE )read_manifest( path, ..., delim = NULL, sheet = NULL, sample_cols = NULL, species = NULL, allow_duplicates = FALSE )
path |
Character scalar with the file path. The format is chosen
from the file extension ( |
... |
Additional named arguments passed to the underlying reader:
|
delim |
Optional character scalar overriding delimiter detection for a delimited text file. Ignored for Excel files. |
sheet |
Optional sheet name or number, passed to
|
sample_cols, species, allow_duplicates
|
Passed to
|
The file must be in long format with one row per sample. See
validate_manifest() for the required columns and the full validation
rules. Reading an Excel file needs the readxl package.
The list returned by validate_manifest(): subject_tbl,
sample_map, and completeness_tbl.
validate_manifest() for the validation rules,
manifest_from_wide() for reshaping a wide table first,
cohort_new() for creating a Cohort from manifest data
manifest_file <- tempfile(fileext = ".csv") writeLines( c( "subject_id,species,assay,sample_id,role", "RAT001,rat,wes,WES_T1,tumor", "RAT001,rat,wes,WES_N1,normal", "MOUSE1,mouse,atac,ATAC_1,NA" ), manifest_file ) parsed <- read_manifest(manifest_file) parsed$subject_tbl parsed$sample_mapmanifest_file <- tempfile(fileext = ".csv") writeLines( c( "subject_id,species,assay,sample_id,role", "RAT001,rat,wes,WES_T1,tumor", "RAT001,rat,wes,WES_N1,normal", "MOUSE1,mouse,atac,ATAC_1,NA" ), manifest_file ) parsed <- read_manifest(manifest_file) parsed$subject_tbl parsed$sample_map
Reads a tidy, long-format manifest CSV (one row per sample) and delegates to
validate_manifest() for validation and structuring.
read_manifest_csv(path, ..., allow_duplicates = FALSE)read_manifest_csv(path, ..., allow_duplicates = FALSE)
path |
Character scalar with file path to a CSV manifest file. Path must exist and the file must be readable. |
... |
Additional named arguments passed to |
allow_duplicates |
Logical. If |
Superseded by read_manifest(), which also reads TSV and Excel files.
This function stays for existing code; new code should call
read_manifest() instead. Every column is read as character unless ...
supplies its own col_types.
The list returned by validate_manifest(): subject_tbl,
sample_map, and completeness_tbl.
read_manifest() for CSV, TSV, and Excel in one function,
validate_manifest() for the validation rules,
cohort_new() for creating a Cohort from manifest data
# Create a temporary long-format CSV manifest manifest_file <- tempfile(fileext = ".csv") writeLines( c( "subject_id,species,assay,sample_id,role", "RAT001,rat,wes,WES_T1,tumor", "RAT001,rat,wes,WES_N1,normal", "RAT001,rat,scrna,RNA_1,tumor", "MOUSE1,mouse,atac,ATAC_1,NA", "HUM01,human,wgs,WGS_T1,tumor" ), manifest_file ) # Read and validate the manifest parsed <- read_manifest_csv(manifest_file) parsed$subject_tbl parsed$sample_map parsed$completeness_tbl# Create a temporary long-format CSV manifest manifest_file <- tempfile(fileext = ".csv") writeLines( c( "subject_id,species,assay,sample_id,role", "RAT001,rat,wes,WES_T1,tumor", "RAT001,rat,wes,WES_N1,normal", "RAT001,rat,scrna,RNA_1,tumor", "MOUSE1,mouse,atac,ATAC_1,NA", "HUM01,human,wgs,WGS_T1,tumor" ), manifest_file ) # Read and validate the manifest parsed <- read_manifest_csv(manifest_file) parsed$subject_tbl parsed$sample_map parsed$completeness_tbl
Reads a study, its manifest, its file paths, and its registered analyses
from one YAML file, and returns a ready-to-use Cohort. This turns the
handful of calls a study's setup script usually makes (study_new(),
read_manifest(), cohort_new(), one analysis_spec_new() per analysis)
into one function call and one file to edit.
read_study_yaml(path, strict = TRUE)read_study_yaml(path, strict = TRUE)
path |
Path to the study YAML file. |
strict |
Logical. When |
The file has these top-level keys, all optional except manifest:
study: fields for study_new() (study_id, title, description,
hypotheses, aims, assays, genome_builds, tags).
manifest: path to the manifest file, read with read_manifest().
Required.
sample_cols: extra sample-level columns, passed to
validate_manifest().
species: fills a species column when the manifest has none.
paths: a map of root name to path, stored as cohort@paths.
corrections: path to a corrections file, applied to the manifest with
apply_corrections() before it is validated.
analyses: a list of analysis_spec_new() field sets, one per
registered analysis.
Every path (manifest, an entry of paths, corrections) is resolved
relative to the YAML file's own directory unless it is already absolute.
A Cohort built from the file.
write_study_yaml(), read_manifest(), cohort_new()
dir <- tempfile() dir.create(dir) writeLines( c( "subject_id,species,assay,sample_id,role", "R1,rat,wes,T1,tumor", "R1,rat,wes,N1,normal" ), file.path(dir, "manifest.csv") ) writeLines( c( "study:", " study_id: PILOT", " title: Example pilot", "manifest: manifest.csv" ), file.path(dir, "study.yaml") ) cohort <- read_study_yaml(file.path(dir, "study.yaml")) cohortdir <- tempfile() dir.create(dir) writeLines( c( "subject_id,species,assay,sample_id,role", "R1,rat,wes,T1,tumor", "R1,rat,wes,N1,normal" ), file.path(dir, "manifest.csv") ) writeLines( c( "study:", " study_id: PILOT", " title: Example pilot", "manifest: manifest.csv" ), file.path(dir, "study.yaml") ) cohort <- read_study_yaml(file.path(dir, "study.yaml")) cohort
Adds a named liftover backend so it can be selected by name in
liftover_intervals(). A backend is a function that performs coordinate
translation for a set of intervals; this pluggable design lets the package
default to an R-native engine while allowing external tools (e.g. CrossMap)
to be swapped in.
register_liftover_backend(name, fn)register_liftover_backend(name, fn)
name |
Character scalar naming the backend. |
fn |
A function with signature
|
intervals passed to a backend is guaranteed to have columns seqnames,
start, end, an optional strand, and a .feature_id integer key added
by liftover_intervals().
Invisibly, the backend name.
liftover_backends(), liftover_intervals(),
liftover_rtracklayer(), liftover_crossmap()
# A backend that maps every interval onto itself, then use it by name. passthrough <- function(intervals, chain, ...) { list( mapped = tibble::tibble( .feature_id = intervals$.feature_id, seqnames = intervals$seqnames, start = intervals$start, end = intervals$end, strand = "*" ), unmapped = intervals[0, , drop = FALSE] ) } register_liftover_backend("passthrough", passthrough) "passthrough" %in% liftover_backends() ints <- data.frame(seqnames = "chr1", start = 100, end = 200) liftover_intervals(ints, chain = "none", to = "human", backend = "passthrough")# A backend that maps every interval onto itself, then use it by name. passthrough <- function(intervals, chain, ...) { list( mapped = tibble::tibble( .feature_id = intervals$.feature_id, seqnames = intervals$seqnames, start = intervals$start, end = intervals$end, strand = "*" ), unmapped = intervals[0, , drop = FALSE] ) } register_liftover_backend("passthrough", passthrough) "passthrough" %in% liftover_backends() ints <- data.frame(seqnames = "chr1", start = 100, end = 200) liftover_intervals(ints, chain = "none", to = "human", backend = "passthrough")
Adds a named ortholog backend so it can be selected by name in
ortholog_genes(). A backend performs gene-level cross-species mapping; this
pluggable design mirrors the liftover backends used for coordinate features.
register_ortholog_backend(name, fn)register_ortholog_backend(name, fn)
name |
Character scalar naming the backend. |
fn |
A function with signature
|
Invisibly, the backend name.
ortholog_backends(), ortholog_genes(), ortholog_babelgene()
# A backend that upper-cases rodent symbols into human ones, used by name. to_upper <- function(features, from, to, gene_col, id_type, ...) { mapped <- features mapped$ortholog <- toupper(mapped[[gene_col]]) list(mapped = mapped, unmapped = features[0, , drop = FALSE]) } register_ortholog_backend("to_upper", to_upper) "to_upper" %in% ortholog_backends() genes <- data.frame(gene = c("Tp53", "Myc")) ortholog_genes(genes, from = "rat", to = "human", backend = "to_upper")# A backend that upper-cases rodent symbols into human ones, used by name. to_upper <- function(features, from, to, gene_col, id_type, ...) { mapped <- features mapped$ortholog <- toupper(mapped[[gene_col]]) list(mapped = mapped, unmapped = features[0, , drop = FALSE]) } register_ortholog_backend("to_upper", to_upper) "to_upper" %in% ortholog_backends() genes <- data.frame(gene = c("Tp53", "Myc")) ortholog_genes(genes, from = "rat", to = "human", backend = "to_upper")
Builds tumor/normal (or, more generally, paired) sample combinations from a
canonical long-format sample_map. Pairing is assay-agnostic: any assay that
records two roles (e.g. WGS, WES) can be paired with the same helper. Within
each subject_id x assay, every sample with tumor_role is paired with
every sample carrying normal_role.
sample_pairs( sample_map, assays = NULL, tumor_role = "tumor", normal_role = "normal", sep = "__" )sample_pairs( sample_map, assays = NULL, tumor_role = "tumor", normal_role = "normal", sep = "__" )
sample_map |
A long-format sample map (e.g. from |
assays |
Optional character vector of assays to restrict pairing to.
|
tumor_role |
Character scalar naming the role treated as the tumor (or
"case") side of a pair. Default |
normal_role |
Character scalar naming the role treated as the normal (or
"control") side of a pair. Default |
sep |
Character scalar placed between the two sample ids in |
A tibble with one row per derived pair and columns:
subject_id: subject the pair belongs to.
assay: assay the pair was derived within.
tumor_sample_id: sample id of the tumor_role member.
normal_sample_id: sample id of the normal_role member.
pair_id: composite id, paste0(tumor_sample_id, sep, normal_sample_id).
Subjects lacking either role within an assay contribute no rows. When a subject has multiple tumor and/or normal samples in an assay, all tumor x normal combinations are enumerated.
validate_manifest() for producing a sample_map
manifest <- data.frame( subject_id = c("S1", "S1", "S1", "S2"), species = c("rat", "rat", "rat", "rat"), assay = c("wes", "wes", "scrna", "wes"), sample_id = c("T1", "N1", "R1", "N2"), role = c("tumor", "normal", "tumor", "normal"), stringsAsFactors = FALSE ) parsed <- validate_manifest(manifest) # S1 has a WES tumor/normal pair; S2 has only a normal, so it is dropped. sample_pairs(parsed$sample_map) # Restrict to specific assays sample_pairs(parsed$sample_map, assays = "wes") # Match a pipeline that names files tumor_vs_normal sample_pairs(parsed$sample_map, sep = "_vs_")manifest <- data.frame( subject_id = c("S1", "S1", "S1", "S2"), species = c("rat", "rat", "rat", "rat"), assay = c("wes", "wes", "scrna", "wes"), sample_id = c("T1", "N1", "R1", "N2"), role = c("tumor", "normal", "tumor", "normal"), stringsAsFactors = FALSE ) parsed <- validate_manifest(manifest) # S1 has a WES tumor/normal pair; S2 has only a normal, so it is dropped. sample_pairs(parsed$sample_map) # Restrict to specific assays sample_pairs(parsed$sample_map, assays = "wes") # Match a pipeline that names files tumor_vs_normal sample_pairs(parsed$sample_map, sep = "_vs_")
Builds the sample sheet a pipeline expects, from a cohort's sample map and
subject table. A few common shapes ship with the package (see
sample_sheet_templates()); pass a custom mapping or a function for
anything else.
sample_sheet( cohort, template = "nf-core/rnaseq", assay = NULL, path = NULL, ... )sample_sheet( cohort, template = "nf-core/rnaseq", assay = NULL, path = NULL, ... )
cohort |
A Cohort object. |
template |
One of:
Default |
assay |
Character scalar naming the assay to include. Required when the cohort has more than one assay; optional when it has exactly one. |
path |
Optional output file path. When given, the sheet is written there as CSV and returned invisibly. |
... |
Passed to a function |
The built-in templates are:
"nf-core/rnaseq": sample, fastq_1, fastq_2, strandedness
("auto" when the manifest has no strandedness column).
"nf-core/rnavar": sample, fastq_1, fastq_2.
"nf-core/atacseq": sample, fastq_1, fastq_2, replicate
(1 when the manifest has no replicate column).
"nf-core/sarek": patient, sex ("XX"/"XY", from a sex column
of "F"/"M"), status (1 for a "tumor" or "resistant" role,
0 otherwise), sample, lane (1 when absent), fastq_1,
fastq_2.
Every template needs fastq_1 in the sample map (and fastq_2 where the
template writes it); declare it with validate_manifest(sample_cols = )
or read_manifest(sample_cols = ) if your manifest names it differently.
A tibble with one row per sample. Invisible when path is given.
sample_sheet_templates(), samples(), check_paths()
manifest <- data.frame( subject_id = c("R1", "R1"), species = "rat", sex = "F", assay = "wes", sample_id = c("T1", "N1"), role = c("tumor", "normal"), fastq_1 = c("t1_R1.fq.gz", "n1_R1.fq.gz"), fastq_2 = c("t1_R2.fq.gz", "n1_R2.fq.gz"), stringsAsFactors = FALSE ) parsed <- validate_manifest(manifest) cohort <- cohort_new(parsed$subject_tbl, parsed$sample_map) sample_sheet(cohort, template = "nf-core/sarek") # A custom mapping sample_sheet(cohort, template = c(sample = "sample_id", read1 = "fastq_1"))manifest <- data.frame( subject_id = c("R1", "R1"), species = "rat", sex = "F", assay = "wes", sample_id = c("T1", "N1"), role = c("tumor", "normal"), fastq_1 = c("t1_R1.fq.gz", "n1_R1.fq.gz"), fastq_2 = c("t1_R2.fq.gz", "n1_R2.fq.gz"), stringsAsFactors = FALSE ) parsed <- validate_manifest(manifest) cohort <- cohort_new(parsed$subject_tbl, parsed$sample_map) sample_sheet(cohort, template = "nf-core/sarek") # A custom mapping sample_sheet(cohort, template = c(sample = "sample_id", read1 = "fastq_1"))
List the built-in sample sheet templates
sample_sheet_templates()sample_sheet_templates()
A character vector of template names accepted by
sample_sheet()'s template argument.
sample_sheet_templates()sample_sheet_templates()
A thin, named accessor for cohort@sample_map, with optional filters and
an optional join to the subject table.
samples(cohort, assay = NULL, role = NULL, with_subjects = FALSE)samples(cohort, assay = NULL, role = NULL, with_subjects = FALSE)
cohort |
A Cohort object. |
assay |
Optional character vector. Keep only these assays. |
role |
Optional character vector. Keep only these roles. |
with_subjects |
Logical. When |
A tibble with the sample map, filtered and optionally joined.
subjects(), completeness(), sample_pairs()
data(example_cohort) samples(example_cohort, assay = "wes") samples(example_cohort, role = "tumor", with_subjects = TRUE)data(example_cohort) samples(example_cohort, assay = "wes") samples(example_cohort, role = "tumor", with_subjects = TRUE)
An immutable S7 class for storing project-level metadata for a study. Study objects provide high-level context and configuration for cohorts and analyses, for any organism and any omics assay.
Study( study_id = character(0), title = character(0), description = NA_character_, hypotheses = character(0), aims = character(0), assays = character(0), genome_builds = list(), created_at = Sys.time(), tags = character(0) )Study( study_id = character(0), title = character(0), description = NA_character_, hypotheses = character(0), aims = character(0), assays = character(0), genome_builds = list(), created_at = Sys.time(), tags = character(0) )
study_id |
Character scalar for study identifier. Unique within a project. |
title |
Character scalar for study name/title. |
description |
Character scalar for longer description of study purpose, design, or protocols. Optional. |
hypotheses |
Character vector of research hypotheses. Accepts multiple hypotheses. Optional. |
aims |
Character vector of specific research aims. Accepts multiple aims. Optional. |
assays |
Character vector of assay types used (e.g., "wes", "scrna"). Optional. |
genome_builds |
Named list mapping species to genome build versions,
e.g. |
created_at |
POSIXct timestamp for creation. Defaults to the time the object is built. |
tags |
Character vector of arbitrary tags for categorization. Optional. |
Use study_new() to construct Study objects with immediate validation.
Construction also validates study_id and title directly, so building a
Study any other way still enforces the two required fields.
Access properties via the @ operator:
study@study_id study@title study@description study@hypotheses study@aims study@assays study@genome_builds study@created_at study@tags
A Study object with the given properties.
study_new() for object construction,
Cohort for combining studies with subject data
# The raw constructor; study_new() is the usual way in. study <- Study(study_id = "PILOT", title = "Pilot study") study@study_id study@assays # empty until set# The raw constructor; study_new() is the usual way in. study <- Study(study_id = "PILOT", title = "Pilot study") study@study_id study@assays # empty until set
Constructs a Study object to describe the overall research project, including study metadata, research hypotheses and aims, assay types, and genome build information. Studies serve as the container for cohorts and provide context for cross-species genomics analysis.
study_new( study_id, title, description = NA_character_, description_file = NULL, hypotheses = character(), aims = character(), assays = character(), genome_builds = list(), created_at = Sys.time(), tags = character() )study_new( study_id, title, description = NA_character_, description_file = NULL, hypotheses = character(), aims = character(), assays = character(), genome_builds = list(), created_at = Sys.time(), tags = character() )
study_id |
Character scalar providing a unique identifier for the study. Must be at least 1 character long. |
title |
Character scalar with the study name/title. Must be at least 1 character long. |
description |
Character scalar with an optional longer description of
the study purpose and design. Always read as plain text. Defaults to NA.
Use |
description_file |
Optional path to a text file whose content becomes
|
hypotheses |
Character vector of research hypotheses. Accepts multiple hypotheses. Optional and defaults to empty vector. |
aims |
Character vector of specific research aims. Accepts multiple aims. Optional and defaults to empty vector. |
assays |
Character vector of assay types used in the study (e.g., "WES", "snRNA-seq"). Optional and defaults to empty vector. |
genome_builds |
Named list mapping species names to genome build versions
(e.g., |
created_at |
POSIXct timestamp for study creation. Defaults to current time. |
tags |
Character vector of arbitrary tags for categorization. Optional and defaults to empty vector. |
Study objects are S7 classes that immutably store research project metadata. They provide context for cohorts and support cross-species genomics analysis. The study_id and title are required; all other fields are optional.
description is always plain text, never a path. To store the content of a
README or protocol file, pass its path as description_file; the file is
read and its content becomes description. An error names the path when
the file does not exist.
A Study object containing the provided metadata.
Cohort for combining studies with subject data
# Example with multiple hypotheses and aims study <- study_new( study_id = "STUDY001", title = "Cross-species genomics comparison", description = "Comparing rat and mouse genomes", hypotheses = c( "Orthologous genes show conserved expression patterns", "Disease genes are enriched in specific pathways" ), aims = c( "Map regulatory regions across species", "Identify conserved non-coding elements" ), assays = c("WES", "snRNA-seq"), genome_builds = list(rat = "rn7", mouse = "mm10", human = "hg38") ) print(study) # Example with a file as the description readme <- tempfile(fileext = ".md") writeLines("# My Study\n\nBackground and design.", readme) study2 <- study_new( study_id = "STUDY002", title = "My Study", description_file = readme ) study2@description# Example with multiple hypotheses and aims study <- study_new( study_id = "STUDY001", title = "Cross-species genomics comparison", description = "Comparing rat and mouse genomes", hypotheses = c( "Orthologous genes show conserved expression patterns", "Disease genes are enriched in specific pathways" ), aims = c( "Map regulatory regions across species", "Identify conserved non-coding elements" ), assays = c("WES", "snRNA-seq"), genome_builds = list(rat = "rn7", mouse = "mm10", human = "hg38") ) print(study) # Example with a file as the description readme <- tempfile(fileext = ".md") writeLines("# My Study\n\nBackground and design.", readme) study2 <- study_new( study_id = "STUDY002", title = "My Study", description_file = readme ) study2@description
Reads the row of cohort@subject_tbl whose subject_id equals id and
returns it as a Subject object. A cohort stores its subjects as a table.
Use this function when one subject is needed as an object.
subject(cohort, id)subject(cohort, id)
cohort |
A Cohort object. |
id |
Character scalar with the |
The Subject fields are read from the columns subject_id, species,
sex, strain, genotype, cohort, timepoint, and notes. Values are
coerced to character and missing values stay missing. A column that is
absent from subject_tbl gives NA. Other columns are ignored.
An unknown id is an error. The error lists up to five ids that the
cohort does have.
A Subject built from the matching row.
Subject, subject_new(), cohort_new()
data(example_cohort) rat1 <- subject(example_cohort, "RAT001") rat1@species rat1@sexdata(example_cohort) rat1 <- subject(example_cohort, "RAT001") rat1@species rat1@sex
An immutable S7 class for storing individual-level metadata in cross-species genomics studies. Subject objects represent individual animals or biological samples and are grouped into Cohort objects for collective analysis.
Subject( subject_id = character(0), species = character(0), sex = NA_character_, strain = NA_character_, genotype = NA_character_, cohort = NA_character_, timepoint = NA_character_, notes = NA_character_ )Subject( subject_id = character(0), species = character(0), sex = NA_character_, strain = NA_character_, genotype = NA_character_, cohort = NA_character_, timepoint = NA_character_, notes = NA_character_ )
subject_id |
Character scalar for unique subject identifier. |
species |
Character scalar naming the species. Any value is allowed;
|
sex |
Character scalar for biological sex (e.g., "M", "F"). Optional. |
strain |
Character scalar for strain or breed designation. Optional. |
genotype |
Character scalar for genetic background or modification (e.g., "WT", "KO"). Optional. |
cohort |
Character scalar for cohort membership or treatment group. Optional. |
timepoint |
Character scalar for study timepoint or collection date. Optional. |
notes |
Character scalar for free-form annotations. Optional. |
Use subject_new() to construct Subject objects; it lower-cases species.
Construction also validates that subject_id and species are present, so
building a Subject any other way still enforces the two required fields.
Individual subjects are typically read from a Cohort with subject().
Access properties via the @ operator:
subject@subject_id subject@species subject@sex subject@strain subject@genotype subject@cohort subject@timepoint subject@notes
A Subject object with the given properties.
subject_new() for object construction,
Cohort for managing groups of subjects
# The raw constructor; subject_new() is the usual way in. rat <- Subject(subject_id = "R1", species = "rat", sex = "F") rat@species rat@genotype # NA until set# The raw constructor; subject_new() is the usual way in. rat <- Subject(subject_id = "R1", species = "rat", sex = "F") rat@species rat@genotype # NA until set
Constructs a Subject object representing an individual animal or biological sample in a study. Subjects must have a unique identifier and a species. All other attributes are optional.
subject_new( subject_id, species, sex = NA_character_, strain = NA_character_, genotype = NA_character_, cohort = NA_character_, timepoint = NA_character_, notes = NA_character_ )subject_new( subject_id, species, sex = NA_character_, strain = NA_character_, genotype = NA_character_, cohort = NA_character_, timepoint = NA_character_, notes = NA_character_ )
subject_id |
Character scalar providing a unique identifier for the subject. Must be at least 1 character long. |
species |
Character scalar naming the species (e.g., "rat", "mouse", "human", "zebrafish"). Any value is allowed; it is stored lower-cased so that "Rat" and "rat" are the same species. Required. |
sex |
Character scalar indicating biological sex (e.g., "M", "F"). Optional and defaults to NA. |
strain |
Character scalar for strain or breed designation. Optional and defaults to NA. |
genotype |
Character scalar describing the genetic background or modification (e.g., "WT", "KO"). Optional and defaults to NA. |
cohort |
Character scalar for cohort membership or treatment group. Optional and defaults to NA. |
timepoint |
Character scalar indicating study timepoint or collection date. Optional and defaults to NA. |
notes |
Character scalar for additional metadata or observations. Optional and defaults to NA. |
Subject objects are S7 classes for storing individual-level metadata in
cross-species studies. The design is species-agnostic: species is a
free-form value, lower-cased so that a study can group subjects by species
without also matching on case. Individual subjects are typically read from
a Cohort with subject().
A Subject object with the species stored lower-cased.
Cohort for managing groups of subjects
# Create a rat subject rat_subject <- subject_new( subject_id = "RAT001", species = "rat", sex = "M", strain = "Lewis", genotype = "WT", cohort = "Control" ) print(rat_subject) # Create a mouse subject mouse_subject <- subject_new( subject_id = "MOUSE001", species = "mouse", sex = "F", strain = "C57BL/6", genotype = "KO" ) print(mouse_subject)# Create a rat subject rat_subject <- subject_new( subject_id = "RAT001", species = "rat", sex = "M", strain = "Lewis", genotype = "WT", cohort = "Control" ) print(rat_subject) # Create a mouse subject mouse_subject <- subject_new( subject_id = "MOUSE001", species = "mouse", sex = "F", strain = "C57BL/6", genotype = "KO" ) print(mouse_subject)
A thin, named accessor for cohort@subject_tbl. Prefer it over the @
operator in pipelines and scripts, so the accessor is the one place that
would change if the underlying property ever did.
subjects(cohort)subjects(cohort)
cohort |
A Cohort object. |
cohort@subject_tbl as a tibble.
samples(), completeness(), subject()
data(example_cohort) subjects(example_cohort)data(example_cohort) subjects(example_cohort)
The one entry point for cross-species translation. Coordinate features (variants, peaks, intervals) route to liftover, and gene-level features route to ortholog mapping. Given a Cohort, it translates every registered analysis according to its AnalysisSpec and returns a new, target-species cohort.
translate(x, to, from = NULL, ...)translate(x, to, from = NULL, ...)
x |
The thing to translate. Either:
|
to |
Character scalar naming the target species/assembly. |
from |
For a feature table, a character scalar naming the source
species/assembly; required for the |
... |
Strategy-specific arguments. For a feature table:
For a Cohort:
|
This function is experimental while the API settles.
Cohort-level translation keeps subjects and the sample map unchanged (the
same biological subjects, viewed in another species' coordinate/gene space)
and re-expresses each analysis's feature table. Analyses without a registered
AnalysisSpec or without a feature_type are skipped with a warning rather
than guessed at.
When the source species is inferred per subject, the combined
TranslationResult for that analysis carries from as a vector (one
entry per source species involved) and adds a .source_species column to
mapped and unmapped, so a row's original species is never lost.
A TranslationResult (feature table input) or a new Cohort whose
analyses are expressed in to (Cohort input). For a cohort, per-analysis
TranslationResults (including unmapped features) are retrievable with
translation_report().
liftover_intervals(), ortholog_genes(), translation_report(),
TranslationResult
# Feature-table input ----------------------------------------------------- ints <- data.frame(seqnames = "chr1", start = 100, end = 200) backend <- function(intervals, chain, ...) { list( mapped = tibble::tibble( .feature_id = intervals$.feature_id, seqnames = "chrT", start = 1L, end = 100L, strand = "*" ), unmapped = intervals[0, , drop = FALSE] ) } translate( ints, to = "human", from = "rat", strategy = "liftover", chain = "none", backend = backend ) # Cohort input ------------------------------------------------------------ # One registered gene-level analysis, translated by an in-memory backend. # The source species is inferred from the cohort's subjects. manifest <- data.frame( subject_id = c("S1", "S2"), species = "rat", assay = "rna", sample_id = c("R1", "R2"), role = "tumor" ) parsed <- validate_manifest(manifest) cohort <- cohort_new( parsed$subject_tbl, parsed$sample_map, analyses = list(expr = data.frame(gene = c("Tp53", "Myc"), value = c(1, 2))) ) spec <- analysis_spec_new( name = "expr", assay = "rna", level = "subject", feature_type = "gene", gene_col = "gene", id_type = "symbol" ) cohort <- analysis_register(cohort, spec) to_upper <- function(features, from, to, gene_col, id_type, ...) { mapped <- features mapped$ortholog <- toupper(mapped[[gene_col]]) list(mapped = mapped, unmapped = features[0, , drop = FALSE]) } human <- translate(cohort, to = "human", ortholog_backend = to_upper) human@analyses$expr# Feature-table input ----------------------------------------------------- ints <- data.frame(seqnames = "chr1", start = 100, end = 200) backend <- function(intervals, chain, ...) { list( mapped = tibble::tibble( .feature_id = intervals$.feature_id, seqnames = "chrT", start = 1L, end = 100L, strand = "*" ), unmapped = intervals[0, , drop = FALSE] ) } translate( ints, to = "human", from = "rat", strategy = "liftover", chain = "none", backend = backend ) # Cohort input ------------------------------------------------------------ # One registered gene-level analysis, translated by an in-memory backend. # The source species is inferred from the cohort's subjects. manifest <- data.frame( subject_id = c("S1", "S2"), species = "rat", assay = "rna", sample_id = c("R1", "R2"), role = "tumor" ) parsed <- validate_manifest(manifest) cohort <- cohort_new( parsed$subject_tbl, parsed$sample_map, analyses = list(expr = data.frame(gene = c("Tp53", "Myc"), value = c(1, 2))) ) spec <- analysis_spec_new( name = "expr", assay = "rna", level = "subject", feature_type = "gene", gene_col = "gene", id_type = "symbol" ) cohort <- analysis_register(cohort, spec) to_upper <- function(features, from, to, gene_col, id_type, ...) { mapped <- features mapped$ortholog <- toupper(mapped[[gene_col]]) list(mapped = mapped, unmapped = features[0, , drop = FALSE]) } human <- translate(cohort, to = "human", ortholog_backend = to_upper) human@analyses$expr
After translate() has translated a Cohort, this returns the
per-analysis TranslationResult objects (including the unmapped features and
mapping statistics) recorded during translation.
translation_report(cohort)translation_report(cohort)
cohort |
A Cohort produced by |
A named list with from, to, and results (a named list of
TranslationResult objects, one per translated analysis), or NULL if the
cohort has not been translated.
translate(), TranslationResult
# A cohort with one gene-level analysis, translated by an in-memory backend. manifest <- data.frame( subject_id = "S1", species = "rat", assay = "rna", sample_id = "R1" ) parsed <- validate_manifest(manifest) cohort <- cohort_new( parsed$subject_tbl, parsed$sample_map, analyses = list(expr = data.frame(gene = c("Tp53", "Myc"))) ) spec <- analysis_spec_new( name = "expr", assay = "rna", level = "subject", feature_type = "gene", gene_col = "gene", id_type = "symbol" ) cohort <- analysis_register(cohort, spec) to_upper <- function(features, from, to, gene_col, id_type, ...) { mapped <- features mapped$ortholog <- toupper(mapped[[gene_col]]) list(mapped = mapped, unmapped = features[0, , drop = FALSE]) } human <- translate(cohort, to = "human", ortholog_backend = to_upper) report <- translation_report(human) report$from report$to translation_stats(report$results$expr) # NULL for a cohort that has not been translated translation_report(cohort)# A cohort with one gene-level analysis, translated by an in-memory backend. manifest <- data.frame( subject_id = "S1", species = "rat", assay = "rna", sample_id = "R1" ) parsed <- validate_manifest(manifest) cohort <- cohort_new( parsed$subject_tbl, parsed$sample_map, analyses = list(expr = data.frame(gene = c("Tp53", "Myc"))) ) spec <- analysis_spec_new( name = "expr", assay = "rna", level = "subject", feature_type = "gene", gene_col = "gene", id_type = "symbol" ) cohort <- analysis_register(cohort, spec) to_upper <- function(features, from, to, gene_col, id_type, ...) { mapped <- features mapped$ortholog <- toupper(mapped[[gene_col]]) list(mapped = mapped, unmapped = features[0, , drop = FALSE]) } human <- translate(cohort, to = "human", ortholog_backend = to_upper) report <- translation_report(human) report$from report$to translation_stats(report$results$expr) # NULL for a cohort that has not been translated translation_report(cohort)
Returns the per-translation summary counts as a one-row tibble: number of input features, how many mapped, how many failed, and how many mapped to more than one location.
translation_stats(x)translation_stats(x)
x |
A TranslationResult object. |
A one-row tibble with columns from, to, backend, n_input,
n_mapped, n_unmapped, n_multi, and prop_mapped.
ints <- data.frame( seqnames = c("chr1", "chr1"), start = c(100, 5000), end = c(200, 5100) ) # Using a trivial in-memory backend for illustration: backend <- function(intervals, chain, ...) { list( mapped = tibble::tibble( .feature_id = intervals$.feature_id[1], seqnames = "chrT", start = 1L, end = 100L, strand = "*" ), unmapped = intervals[-1, , drop = FALSE] ) } res <- liftover_intervals( ints, chain = "none", to = "human", backend = backend ) translation_stats(res)ints <- data.frame( seqnames = c("chr1", "chr1"), start = c(100, 5000), end = c(200, 5100) ) # Using a trivial in-memory backend for illustration: backend <- function(intervals, chain, ...) { list( mapped = tibble::tibble( .feature_id = intervals$.feature_id[1], seqnames = "chrT", start = 1L, end = 100L, strand = "*" ), unmapped = intervals[-1, , drop = FALSE] ) } res <- liftover_intervals( ints, chain = "none", to = "human", backend = backend ) translation_stats(res)
An S7 class holding the outcome of translating coordinate features or gene-level features from one species or assembly to another. It keeps the successfully translated features, the features that failed to map, and provenance so that translation is never lossy silently.
TranslationResult( mapped = NULL, unmapped = NULL, from = NA_character_, to = NA_character_, backend = NA_character_, stats = list() )TranslationResult( mapped = NULL, unmapped = NULL, from = NA_character_, to = NA_character_, backend = NA_character_, stats = list() )
mapped |
A tibble of successfully translated features. Includes a
|
unmapped |
A tibble of input features that produced no output. |
from |
Character scalar naming the source species/assembly. Optional. |
to |
Character scalar naming the target species/assembly. Optional. |
backend |
Character scalar naming the translation backend used. Optional. |
stats |
Named list of summary counts ( |
Construct these via liftover_intervals() or translate() rather than
directly. Access the pieces with result@mapped, result@unmapped, and
translation_stats().
A TranslationResult object with the given properties.
liftover_intervals(), translate(), translation_stats()
# Built by hand here to show the shape; translate() builds them for you. res <- TranslationResult( mapped = tibble::tibble(.feature_id = 1L, gene = "Tp53", ortholog = "TP53"), unmapped = tibble::tibble(.feature_id = 2L, gene = "Gm12345"), from = "rat", to = "human", backend = "by_hand", stats = list(n_input = 2L, n_mapped = 1L, n_unmapped = 1L, n_multi = 0L) ) res@unmapped translation_stats(res)# Built by hand here to show the shape; translate() builds them for you. res <- TranslationResult( mapped = tibble::tibble(.feature_id = 1L, gene = "Tp53", ortholog = "TP53"), unmapped = tibble::tibble(.feature_id = 2L, gene = "Gm12345"), from = "rat", to = "human", backend = "by_hand", stats = list(n_input = 2L, n_mapped = 1L, n_unmapped = 1L, n_multi = 0L) ) res@unmapped translation_stats(res)
Checks the subject table, the sample map, and the link between them.
cohort_new() calls this function after it builds the object. Call it
directly to check a cohort that was built or changed by other means.
validate_cohort(x)validate_cohort(x)
x |
A Cohort object. |
The checks are:
x is a Cohort object.
subject_tbl and sample_map are data frames.
subject_tbl has the columns subject_id and species, both
character, with no missing value. An empty string counts as missing.
species is a free-form value; any organism is allowed.
subject_tbl$subject_id has no duplicate.
sample_map has the columns subject_id, assay, sample_id, and
role, all character. The first three have no missing value.
Every sample_map$subject_id exists in subject_tbl.
TRUE, invisibly, when the cohort is valid. Otherwise an error
that lists every problem found.
cohort_new() for Cohort construction,
validate_manifest() for manifest validation
subjects <- data.frame( subject_id = "RAT001", species = "rat", sex = "M" ) samples <- data.frame( subject_id = "RAT001", assay = "wes", sample_id = "WES_R001", role = "tumor" ) cohort <- cohort_new( subject_tbl = subjects, sample_map = samples ) # cohort_new() already ran the checks. Run them again by hand. validate_cohort(cohort)subjects <- data.frame( subject_id = "RAT001", species = "rat", sex = "M" ) samples <- data.frame( subject_id = "RAT001", assay = "wes", sample_id = "WES_R001", role = "tumor" ) cohort <- cohort_new( subject_tbl = subjects, sample_map = samples ) # cohort_new() already ran the checks. Run them again by hand. validate_cohort(cohort)
Validates a tidy, long-format manifest (one row per sample) and structures it into a subject metadata table and a canonical long-format sample map. The design is deliberately species- and assay-agnostic: any organism and any assay (WGS, WES, ATAC-seq, bulk RNA, single-cell, ...) are represented as values, never as bespoke columns or per-assay tables.
validate_manifest( manifest, sample_cols = NULL, species = NULL, allow_duplicates = FALSE )validate_manifest( manifest, sample_cols = NULL, species = NULL, allow_duplicates = FALSE )
manifest |
A data.frame or tibble in long format, one row per sample. Required columns:
Optional sample-level columns:
Any remaining columns (e.g. |
sample_cols |
Optional character vector naming additional columns to
keep at the sample level (in |
species |
Optional character scalar. When |
allow_duplicates |
Logical. If |
Every column is coerced to character, so a numeric, logical, or factor
column never reaches cohort_new() in a form that would fail there.
Empty strings are treated as missing. Every sample row must carry a
non-missing subject_id, assay, and sample_id.
Beyond the four canonical columns, these names are always kept at the
sample level when present: specimen_id, library_id, vendor_id,
replicate, lane, run, flowcell, strandedness, fastq_1,
fastq_2, bam, cram, vcf, matrix_dir, h5, qc_status, and
qc_reason. Add any other column that varies per sample with
sample_cols; a column that varies within a subject but is not
recognized or declared raises the conflicting-metadata error below.
species, when present (in the manifest or filled from the species
argument), is lower-cased so that "Rat" and "rat" are the same
subject-level value. Any species value is allowed; the manifest layer
does not restrict it to a fixed list of organisms.
sample_id must be unique across the whole manifest, not only within a
subject or assay, unless allow_duplicates = TRUE.
Per-assay wide views (e.g. tumor/normal pairs) are not part of the core
contract; derive them on demand from sample_map with sample_pairs().
A list with three elements:
subject_tbl: Tibble with one row per subject_id containing the
subject-level metadata columns, all character.
sample_map: Canonical long-format tibble with columns subject_id,
assay, sample_id, role, and any recognized or declared extra
sample-level columns, all character.
completeness_tbl: Tibble with one row per subject_id x assay
summarizing the number of samples (n_samples).
read_manifest_csv() for reading a manifest from CSV,
cohort_new() for creating a Cohort from manifest data
manifest <- data.frame( subject_id = c("RAT001", "RAT001", "MOUSE1", "HUM01"), species = c("rat", "rat", "mouse", "human"), assay = c("wes", "wes", "atac", "wgs"), sample_id = c("WES_T1", "WES_N1", "ATAC_1", "WGS_T1"), role = c("tumor", "normal", NA, "tumor"), fastq_1 = c("t1_R1.fq.gz", "n1_R1.fq.gz", "a1_R1.fq.gz", "g1_R1.fq.gz"), stringsAsFactors = FALSE ) parsed <- validate_manifest(manifest) parsed$subject_tbl parsed$sample_map parsed$completeness_tblmanifest <- data.frame( subject_id = c("RAT001", "RAT001", "MOUSE1", "HUM01"), species = c("rat", "rat", "mouse", "human"), assay = c("wes", "wes", "atac", "wgs"), sample_id = c("WES_T1", "WES_N1", "ATAC_1", "WGS_T1"), role = c("tumor", "normal", NA, "tumor"), fastq_1 = c("t1_R1.fq.gz", "n1_R1.fq.gz", "a1_R1.fq.gz", "g1_R1.fq.gz"), stringsAsFactors = FALSE ) parsed <- validate_manifest(manifest) parsed$subject_tbl parsed$sample_map parsed$completeness_tbl
Joins a cohort's (or a validate_manifest() result's) sample_map and
subject_tbl back into one long-format manifest and writes it to a CSV,
TSV, or other delimited file.
write_manifest(x, path, delim = NULL)write_manifest(x, path, delim = NULL)
x |
A Cohort object, or the list returned by |
path |
Output file path. The delimiter is chosen from the extension
unless |
delim |
Optional character scalar overriding delimiter detection. |
Columns are ordered subject_id, then the other subject-level columns,
then the sample-level columns (assay, sample_id, role, and any
extra ones). A missing value is written as an empty field.
The written manifest tibble, invisibly.
read_manifest(), validate_manifest(), cohort_save()
manifest <- data.frame( subject_id = "R1", species = "rat", assay = "wes", sample_id = "T1", role = "tumor", stringsAsFactors = FALSE ) parsed <- validate_manifest(manifest) out <- tempfile(fileext = ".csv") write_manifest(parsed, out) readLines(out)manifest <- data.frame( subject_id = "R1", species = "rat", assay = "wes", sample_id = "T1", role = "tumor", stringsAsFactors = FALSE ) parsed <- validate_manifest(manifest) out <- tempfile(fileext = ".csv") write_manifest(parsed, out) readLines(out)
The inverse of read_study_yaml(): writes the cohort's study metadata,
its manifest, its paths, and its registered analysis specs to a study
YAML file and a manifest file alongside it.
write_study_yaml(cohort, path, manifest = "manifest.csv")write_study_yaml(cohort, path, manifest = "manifest.csv")
cohort |
A Cohort object. |
path |
Output path for the study YAML file. |
manifest |
Path for the manifest file, resolved relative to |
A cohort has no stored corrections file, so a corrections: key is never
written; the manifest written out already reflects any correction that
was applied before the cohort was built.
path, invisibly.
read_study_yaml(), write_manifest()
data(example_cohort) dir <- tempfile() dir.create(dir) write_study_yaml(example_cohort, file.path(dir, "study.yaml")) cat(readLines(file.path(dir, "study.yaml")), sep = "\n")data(example_cohort) dir <- tempfile() dir.create(dir) write_study_yaml(example_cohort, file.path(dir, "study.yaml")) cat(readLines(file.path(dir, "study.yaml")), sep = "\n")