Add external information to ImmunData¶
Description¶
Use the annotate_*() functions
to add information stored in another data frame to an ImmunData object.
For example, you can add cell types from a single-cell analysis, antigen
labels for receptors, or clinical information for samples.
When matching identifiers are unique, the functions keep every row in
idata. When a row has no match in annotations,
the new columns contain NA. Each function returns a new
ImmunData object. The original object is not changed.
Usage¶
annotate_immundata(
idata,
annotations,
by,
keep_repertoires = TRUE,
remove_limit = FALSE,
conflicts = c("error", "replace")
)
annotate(
idata,
annotations,
by,
keep_repertoires = TRUE,
remove_limit = FALSE,
conflicts = c("error", "replace")
)
annotate_receptors(
idata,
annotations,
annot_col = imd_schema("receptor"),
keep_repertoires = TRUE,
remove_limit = FALSE,
conflicts = c("error", "replace")
)
annotate_barcodes(
idata,
annotations,
annot_col = "<rownames>",
keep_repertoires = TRUE,
remove_limit = FALSE,
conflicts = c("error", "replace")
)
annotate_chains(
idata,
annotations,
annot_col = imd_schema("chain"),
keep_repertoires = TRUE,
remove_limit = FALSE,
conflicts = c("error", "replace")
)
Arguments¶
idata
|
An ImmunData object. |
annotations
|
A data frame containing the information to add. It must contain the columns used for matching and at most one row for each matching identifier or combination of identifiers. |
by
|
A named character vector describing how columns are matched. Names are
columns in idata; values are the corresponding columns in
annotations. For example, c(Response =
“response_code”).
|
keep_repertoires
|
Whether to preserve existing repertoire and strata summaries without
recalculation. The default is TRUE. If FALSE,
these summaries and their derived annotation columns are removed.
|
remove_limit
|
Whether to allow an annotation table with 100 or more columns. The
default is FALSE, which stops the operation for such
tables. Set to TRUE only when the wide join is intentional.
|
conflicts
|
How to handle new annotation columns whose names already exist in
idata. “error”, the default, stops the
operation. “replace” replaces existing columns that are not
protected by ImmunData.
|
annot_col
|
Name of the identifier column in annotations. For
annotate_receptors() and annotate_chains(),
the default is the standard ImmunData receptor or chain
identifier. For annotate_barcodes(), the default
“\ uses the row names of
annotations. Supplying an explicit barcode column is
usually clearer.
|
Details¶
The functions differ in how they select the columns used for matching. The rules for duplicate identifiers, column conflicts, and preserved summaries are the same for all functions.
Value¶
A new ImmunData object containing the added annotation columns. Existing
repertoire and strata summaries are preserved when
keep_repertoires = TRUE.
Choose a function¶
Use the function that matches the type of information you want to add:
-
annotate_barcodes()matches cell or barcode identifiers. -
annotate_receptors()matches receptor identifiers. All rows belonging to a matched receptor receive the new information. -
annotate_chains()matches chain identifiers. -
annotate()matches any one or more columns that you specify inby.
The first three functions select the correct ImmunData
identifier for you. annotate_immundata() is an alternative
name for annotate().
How matching works¶
For annotate_barcodes(), annotate_receptors(),
and annotate_chains(), annot_col names the
identifier column in annotations. For example,
annot_col = “barcode” matches the barcode
column in annotations with the barcode identifier in
idata.
For general matching, supply by in the form
c(immundata_column = “annotation_column”). For example,
by = c(Response = “response_code”) matches the
Response column in idata with the
response_code column in annotations. To match
columns with the same name, use a value such as by = c(Response =
“Response”). You can include more than one pair of columns in
by.
Columns from annotations that are not used for matching are
added to the result. Rows in idata without a match receive
NA. Rows in annotations without a match are
ignored.
Annotation identifiers must be unique¶
annotations must contain at most one row for each
identifier, or each combination of identifiers when matching several
columns. For example, a barcode annotation table must contain at most
one row per barcode.
The function does not check this rule because the annotation table may
be very large. If an identifier occurs several times, the corresponding
rows in idata are repeated. This can make receptor counts,
proportions, and other summaries incorrect.
Existing annotation columns¶
By default, the function stops if a new annotation column has the same
name as a column already present in idata. This prevents
accidental replacement.
Use conflicts = “replace” to replace existing annotation
columns. Columns that define receptors, repertoires, strata, or other
ImmunData state are protected and cannot be replaced. The
old column is removed before matching, so rows without a new match
receive NA.
Repertoire and strata summaries¶
With the default keep_repertoires = TRUE, existing
repertoire and strata summaries are copied to the new object without
recalculation. Use this option when you are only adding information and
the matching identifiers in annotations are unique.
Set keep_repertoires = FALSE when you plan to filter rows
or define new repertoires using the added information. This removes
existing repertoire and strata summaries and their derived columns.
After annotation and filtering, use agg_repertoires() to
define the new repertoires.
Very wide annotation tables¶
By default, the function stops when annotations contains
100 or more columns. Adding a very wide table, such as a complete
gene-expression matrix, can be slow and require a large amount of
memory. If you understand this cost, set remove_limit =
TRUE to allow the operation.
See Also¶
dplyr::left_join(), agg_repertoires(),
filter_immundata(), mutate_immundata(),
ImmunData
Examples¶
library("immundata")
library(immundata)
library(dplyr)
options(immundata.verbose = FALSE)
# Load data included with immundata
idata <- get_test_idata()
# Add cell types by matching barcode identifiers
cell_labels <- tibble(
barcode = c("S1_1", "S1_2"),
cell_type = c("CD8 T cell", "CD4 T cell")
)
idata_with_cells <- idata |>
annotate_barcodes(
annotations = cell_labels,
annot_col = "barcode"
)
idata_with_cells |>
collect() |>
filter(imd_barcode %in% c("S1_1", "S1_2", "S1_3")) |>
select(imd_barcode, cell_type) |>
arrange(imd_barcode)
#> # A tibble: 3 × 2
#> imd_barcode cell_type
#> * <chr> <chr>
#> 1 S1_1 CD8 T cell
#> 2 S1_2 CD4 T cell
#> 3 S1_3 <NA>
# Expected result:
# imd_barcode cell_type
# S1_1 CD8 T cell
# S1_2 CD4 T cell
# S1_3 NA
# Add antigen labels to selected receptors
receptor_labels <- tibble(
receptor_id = c(738L, 1567L),
antigen = c("CMV", "CMV")
)
idata_with_antigens <- idata |>
annotate_receptors(
annotations = receptor_labels,
annot_col = "receptor_id"
)
idata_with_antigens |>
collect() |>
filter(!is.na(antigen)) |>
distinct(imd_receptor_id, cdr3_aa, antigen) |>
arrange(imd_receptor_id)
#> # A tibble: 2 × 3
#> imd_receptor_id cdr3_aa antigen
#> * <int> <chr> <chr>
#> 1 738 SVWTSGGNNEQF CMV
#> 2 1567 ASSLEMEGTGELF CMV
# Expected result:
# imd_receptor_id cdr3_aa antigen
# 738 ASRAGAGTGELF CMV
# 1567 ASFPVLSPYNEQF CMV
# Match columns with different names
response_info <- tibble(
response_code = c("FR", "PR"),
response_label = c("Full response", "Partial response")
)
idata_with_response <- idata |>
annotate(
annotations = response_info,
by = c(Response = "response_code")
)
idata_with_response |>
collect() |>
distinct(Response, response_label) |>
arrange(Response)
#> # A tibble: 2 × 2
#> Response response_label
#> * <chr> <chr>
#> 1 FR Full response
#> 2 PR Partial response
# Expected result:
# Response response_label
# FR Full response
# PR Partial response
# Replace an annotation column intentionally
revised_cell_labels <- tibble(
barcode = c("S1_1", "S1_2"),
cell_type = c("Cytotoxic T cell", "Helper T cell")
)
idata_with_revised_cells <- idata_with_cells |>
annotate_barcodes(
annotations = revised_cell_labels,
annot_col = "barcode",
conflicts = "replace"
)
# Remove old repertoire summaries before defining repertoires by cell type
cell_repertoires <- idata |>
annotate_barcodes(
annotations = cell_labels,
annot_col = "barcode",
keep_repertoires = FALSE
) |>
filter(!is.na(cell_type)) |>
agg_repertoires(schema = "cell_type")
cell_repertoires$repertoires |>
arrange(cell_type)
#> # A tibble: 2 × 4
#> imd_repertoire_id cell_type n_barcodes n_receptors
#> * <int> <chr> <dbl> <int>
#> 1 1 CD4 T cell 1 1
#> 2 2 CD8 T cell 1 1