This vignette provides detailed examples for loading gene expression and V(D)J data into a single object. For the examples shown below, we use data for splenocytes from BL6 and MD4 mice collected using the 10X Genomics scRNA-seq platform. MD4 B cells are monoclonal and specifically bind hen egg lysozyme.
Basic usage
To load and parse V(D)J data, FASTQ files must first be processed
using Cell
Ranger. The data used for this vignette was processed using Cell
Ranger v7.0. Cell Ranger generates several files that djvdj uses for the
downstream analysis. This includes the
outs/filtered_contig_annotations.csv file, which contains basic
information about each chain and is required for the
import_vdj()
function.
The simplest use case for import_vdj()
involves creating
an object using data from a single run.
library(djvdj)
library(Seurat)
library(dplyr)
# Create Seurat object
data_dir <- system.file("extdata/splen", package = "djvdj")
so <- file.path(data_dir, "BL6_GEX/filtered_feature_bc_matrix") |>
Read10X() |>
CreateSeuratObject()
# Add V(D)J data to object
so_vdj <- so |>
import_vdj(vdj_dir = file.path(data_dir, "BL6_BCR"))
import_vdj()
adds a variety of per-chain metrics to the
object meta.data. Information for each chain identified for the cell is
separated by a semicolon. The separator used for storing and parsing
per-chain V(D)J data can be specified using the sep
argument included for most djvdj functions. NA
s will be
included for cells that lack V(D)J data.
so_vdj |>
slot("meta.data") |>
filter(n_chains > 1) |>
head(2)
#> orig.ident nCount_RNA nFeature_RNA clonotype_id
#> ACACCAAAGAATTGTG-1 SeuratProject 38 21 clonotype2492
#> ACACCGGCACAAGTAA-1 SeuratProject 80 30 clonotype3124
#> exact_subclonotype_id chains n_chains
#> ACACCAAAGAATTGTG-1 1 IGH;IGK 2
#> ACACCGGCACAAGTAA-1 1 IGH;IGK 2
#> cdr3
#> ACACCAAAGAATTGTG-1 CAHGSRDFDVW;CWQGTHFPQTF
#> ACACCGGCACAAGTAA-1 CARHEGYYEAMDYW;CQQGNTLPLTF
#> cdr3_nt
#> ACACCAAAGAATTGTG-1 TGTGCTCACGGTAGTCGAGACTTCGATGTCTGG;TGCTGGCAAGGTACACATTTTCCTCAGACGTTC
#> ACACCGGCACAAGTAA-1 TGTGCAAGACATGAGGGGTACTACGAGGCTATGGACTACTGG;TGCCAACAGGGTAATACGCTTCCTCTCACGTTC
#> cdr3_length cdr3_nt_length v_gene
#> ACACCAAAGAATTGTG-1 11;11 33;33 IGHV1-75;IGKV1-135
#> ACACCGGCACAAGTAA-1 14;11 42;33 IGHV5-15;IGKV10-96
#> d_gene j_gene c_gene isotype reads umis
#> ACACCAAAGAATTGTG-1 None;None IGHJ1;IGKJ1 IGHM;IGKC IGHM 20;208 2;11
#> ACACCGGCACAAGTAA-1 None;None IGHJ4;IGKJ5 IGHM;IGKC IGHM 80;174 6;12
#> productive full_length paired
#> ACACCAAAGAATTGTG-1 TRUE;TRUE TRUE;TRUE TRUE
#> ACACCGGCACAAGTAA-1 TRUE;TRUE TRUE;TRUE TRUE
To modify/filter/plot per-chain data, djvdj provides a range of
functions that make it easy to parse and visualize this information. For
detailed examples refer to the vignettes and documentation for the
following functions: filter_vdj()
,
mutate_vdj()
, summarize_vdj()
,
plot_histogram()
, plot_scatter()
.
Loading multiple runs
When combining gene expression and V(D)J data from multiple runs into
the same Seurat object, we must ensure that import_vdj()
is
able to match the cell barcodes from the two data types. The easiest way
to do this is to load the gene expression and V(D)J samples in the same
order.
If the V(D)J samples are not loaded in the same order as the gene expression data, the cell barcodes will not match and you will receive an error.
# Load GEX data
gex_dirs <- c(
file.path(data_dir, "BL6_GEX/filtered_feature_bc_matrix"),
file.path(data_dir, "MD4_GEX/filtered_feature_bc_matrix")
)
so <- gex_dirs |>
Read10X() |>
CreateSeuratObject()
# Load BCR data
# note that the BL6 and MD4 paths are in the same order as the gene
# expression data
vdj_dirs <- c(
file.path(data_dir, "BL6_BCR"),
file.path(data_dir, "MD4_BCR")
)
so_vdj <- so |>
import_vdj(vdj_dir = vdj_dirs)
Another way to ensure the cell barcodes from the gene expression and
V(D)J data are able to be matched is to specify cell barcode prefixes
for each sample. For both the Seurat::Read10X()
and
import_vdj()
functions this can be done by passing a named
vector. In this scenario, the names will be added as prefixes for the
cell barcodes.
# Load GEX data
gex_dirs <- c(
BL6 = file.path(data_dir, "BL6_GEX/filtered_feature_bc_matrix"),
MD4 = file.path(data_dir, "MD4_GEX/filtered_feature_bc_matrix")
)
so <- gex_dirs |>
Read10X() |>
CreateSeuratObject()
# Load BCR data
# note that the samples are not in the same order as the gene expression data,
# but this is okay since cell prefixes are provided as names for the
# input vector
vdj_dirs <- c(
MD4 = file.path(data_dir, "MD4_BCR"),
BL6 = file.path(data_dir, "BL6_BCR")
)
so_vdj <- so |>
import_vdj(vdj_dir = vdj_dirs)
Defining clonotypes
When results from multiple Cell Ranger runs are added to the object,
the clonotype IDs will not match, i.e. clonotype1 will not be the same
for all samples. To allow clonotypes to be directly compared between
multiple samples, the clonotypes can be recalculated using the
define_clonotypes
argument. This argument will assign new
clonotype IDs using information available for each chain. There are
three options to specify how this step is performed:
- ‘cdr3aa’: use only the CDR3 amino acid sequence
- ‘cdr3nt’: use only the CDR3 nucleotide sequence
- ‘cdr3_gene’: use both the CDR3 nucleotide sequence and the combination of all V(D)J genes identified for the cell
so_vdj <- so |>
import_vdj(
vdj_dir = vdj_dirs,
define_clonotypes = "cdr3_gene"
)
The clonotype IDs can also be adjusted for multiple samples using the
aggregate
function available with Cell Ranger. To load aggregated output files
just pass the cellranger aggr
output directory to the
aggr_dir
argument. To correctly match cell barcodes from
aggregated V(D)J data with the gene expression data, the gene expression
samples must be loaded into the object in the same order the samples
were listed in the cellranger aggr
config
file.
Filtering chains
The import_vdj()
function has several arguments that can
be used to perform basic filtering for each chain. The
filter_chains
argument will only include chains with at
least one productive and full length contig. However, it should be noted
that in recent versions of Cell Ranger the output files are already
filtered based on this criteria, so this argument is only relevant when
loading data processed with earlier versions such as Cell Ranger
v3.0.
The filter_paired
argument will only include clonotypes
with paired chains. For TCR data, this means each clonotype must have at
least one TRA and TRB chain. For BCR data each clonotype must have at
least one IGH chain and at least one IGK or IGL chain. It should be
noted that if a clonotype has multiple chains of the same type, it will
still be included, e.g. TRA;TRB;TRB or IGH;IGK;IGK will still be
included. Clonotypes that include more than two chains can be filtered
using filter_vdj()
.
vdj_dirs <- c(
MD4 = file.path(data_dir, "MD4_BCR"),
BL6 = file.path(data_dir, "BL6_BCR")
)
so_vdj <- so |>
import_vdj(
vdj_dir = vdj_dirs,
filter_chains = TRUE,
filter_paired = TRUE
)
# To only include clonotypes with exactly 2 chains
so_vdj <- so_vdj |>
filter_vdj(n_chains == 2)
Loading mutation information
Mutation information for each chain can be parsed using two additional output files from Cell Ranger:
- outs/concat_ref.bam: this file contains alignment information used to quantify insertions, deletions, and mismatches for each chain.
- outs/airr_rearrangement.tsv: this file contains coordinates for each V(D)J gene segment and is used to quantify mutations for each segment and/or junction.
vdj_dirs <- c(
MD4 = file.path(data_dir, "MD4_BCR"),
BL6 = file.path(data_dir, "BL6_BCR")
)
so_vdj <- so |>
import_vdj(
vdj_dir = vdj_dirs,
include_mutations = TRUE
)
The additional columns added to the meta.data will include the number of insertions, deletions, and mismatches (ending in ‘ins’, ‘del’, or ‘mis’) for each V(D)J segment (prefixed with ‘v’, ‘d’, ‘j’, or ‘c’). Columns containing junction information will be prefixed with either ‘vd’ or ‘dj’. Columns ending in ‘freq’ show the event frequency which is calculated as the number of events divided by the length of the region.
so_vdj |>
slot("meta.data") |>
filter(n_chains > 1) |>
head(2)
#> orig.ident nCount_RNA nFeature_RNA clonotype_id
#> BL6_ACACCAAAGAATTGTG-1 BL6 38 21 clonotype2492
#> BL6_ACACCGGCACAAGTAA-1 BL6 80 30 clonotype3124
#> exact_subclonotype_id chains n_chains
#> BL6_ACACCAAAGAATTGTG-1 1 IGH;IGK 2
#> BL6_ACACCGGCACAAGTAA-1 1 IGH;IGK 2
#> cdr3
#> BL6_ACACCAAAGAATTGTG-1 CAHGSRDFDVW;CWQGTHFPQTF
#> BL6_ACACCGGCACAAGTAA-1 CARHEGYYEAMDYW;CQQGNTLPLTF
#> cdr3_nt
#> BL6_ACACCAAAGAATTGTG-1 TGTGCTCACGGTAGTCGAGACTTCGATGTCTGG;TGCTGGCAAGGTACACATTTTCCTCAGACGTTC
#> BL6_ACACCGGCACAAGTAA-1 TGTGCAAGACATGAGGGGTACTACGAGGCTATGGACTACTGG;TGCCAACAGGGTAATACGCTTCCTCTCACGTTC
#> cdr3_length cdr3_nt_length v_gene
#> BL6_ACACCAAAGAATTGTG-1 11;11 33;33 IGHV1-75;IGKV1-135
#> BL6_ACACCGGCACAAGTAA-1 14;11 42;33 IGHV5-15;IGKV10-96
#> d_gene j_gene c_gene isotype reads
#> BL6_ACACCAAAGAATTGTG-1 None;None IGHJ1;IGKJ1 IGHM;IGKC IGHM 20;208
#> BL6_ACACCGGCACAAGTAA-1 None;None IGHJ4;IGKJ5 IGHM;IGKC IGHM 80;174
#> umis productive full_length paired v_ins v_del
#> BL6_ACACCAAAGAATTGTG-1 2;11 TRUE;TRUE TRUE;TRUE TRUE 2;0 0;0
#> BL6_ACACCGGCACAAGTAA-1 6;12 TRUE;TRUE TRUE;TRUE TRUE 0;0 0;3
#> v_mis d_ins d_del d_mis j_ins j_del j_mis c_ins
#> BL6_ACACCAAAGAATTGTG-1 1;0 0;0 0;0 0;0 0;0 0;3 0;0 0;0
#> BL6_ACACCGGCACAAGTAA-1 0;0 0;0 0;0 0;0 0;0 0;3 3;0 0;0
#> c_del c_mis all_ins all_del all_mis vd_ins vd_del
#> BL6_ACACCAAAGAATTGTG-1 0;0 0;0 2;0 0;3 1;0 0;0 0;0
#> BL6_ACACCGGCACAAGTAA-1 0;0 0;0 0;0 0;6 3;0 0;0 0;0
#> dj_ins dj_del v_mis_freq d_mis_freq j_mis_freq
#> BL6_ACACCAAAGAATTGTG-1 0;0 0;0 0.002525;0 0;0 0;0
#> BL6_ACACCGGCACAAGTAA-1 0;0 0;0 0;0 0;0 0.007371;0
#> c_mis_freq all_mis_freq
#> BL6_ACACCAAAGAATTGTG-1 0;0 0.002525;0
#> BL6_ACACCGGCACAAGTAA-1 0;0 0.007371;0
Loading additional sequence information
By default the only sequence information loaded by
import_vdj()
will be for the CDR3 region. Newer versions of
Cell Ranger will include additional sequences in the
filtered_contig_annotations.csv file. This includes the FWR1, CDR1,
FWR2, CDR2, FWR3, and FWR4 regions. These additional sequences can be
loaded using the data_cols
argument.
so_vdj <- so |>
import_vdj(
vdj_dir = vdj_dirs,
data_cols = c("cdr1", "cdr1_nt", "cdr2", "cdr2_nt")
)
so_vdj |>
slot("meta.data") |>
head(3)
#> orig.ident nCount_RNA nFeature_RNA clonotype_id
#> BL6_AAACGGGGTTCTGTTT-1 BL6 202 25 <NA>
#> BL6_AAAGATGCAACAACCT-1 BL6 42 20 clonotype7
#> BL6_AACGTTGCACGACTCG-1 BL6 32 19 clonotype32
#> exact_subclonotype_id chains n_chains
#> BL6_AAACGGGGTTCTGTTT-1 NA <NA> NA
#> BL6_AAAGATGCAACAACCT-1 1 IGK 1
#> BL6_AACGTTGCACGACTCG-1 1 IGK 1
#> cdr1
#> BL6_AAACGGGGTTCTGTTT-1 <NA>
#> BL6_AAAGATGCAACAACCT-1 RSSQSIVHSNGNTYLE
#> BL6_AACGTTGCACGACTCG-1 KASQNVGTNVA
#> cdr1_nt
#> BL6_AAACGGGGTTCTGTTT-1 <NA>
#> BL6_AAAGATGCAACAACCT-1 AGATCTAGTCAGAGCATTGTACATAGTAATGGAAACACCTATTTAGAA
#> BL6_AACGTTGCACGACTCG-1 AAGGCCAGTCAGAATGTGGGTACTAATGTAGCC
#> cdr2 cdr2_nt cdr3
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 KVSNRFS AAAGTTTCCAACCGATTTTCT CFQGSHVPWTF
#> BL6_AACGTTGCACGACTCG-1 SASYRYS TCGGCATCCTACCGGTACAGT CQQYNSYPLTF
#> cdr3_nt cdr1_length
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 TGCTTTCAAGGTTCACATGTTCCGTGGACGTTC 16
#> BL6_AACGTTGCACGACTCG-1 TGTCAGCAATATAACAGCTATCCTCTCACGTTC 11
#> cdr1_nt_length cdr2_length cdr2_nt_length
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 48 7 21
#> BL6_AACGTTGCACGACTCG-1 33 7 21
#> cdr3_length cdr3_nt_length v_gene d_gene j_gene
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> <NA> <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 11 33 IGKV1-117 None IGKJ1
#> BL6_AACGTTGCACGACTCG-1 11 33 IGKV6-15 None IGKJ5
#> c_gene isotype reads umis productive full_length
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> <NA> <NA> <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 IGKC None 352 21 TRUE TRUE
#> BL6_AACGTTGCACGACTCG-1 IGKC None 342 18 TRUE TRUE
#> paired
#> BL6_AAACGGGGTTCTGTTT-1 NA
#> BL6_AAAGATGCAACAACCT-1 FALSE
#> BL6_AACGTTGCACGACTCG-1 FALSE
Loading TCR and BCR data
To add both BCR and TCR data to the object, run
import_vdj()
separately for each data type. To distinguish
between columns containing BCR or TCR data, use the prefix
argument to add unique column names.
bcr_dirs <- c(
MD4 = file.path(data_dir, "MD4_BCR"),
BL6 = file.path(data_dir, "BL6_BCR")
)
tcr_dirs <- c(
MD4 = file.path(data_dir, "MD4_TCR"),
BL6 = file.path(data_dir, "BL6_TCR")
)
so_vdj <- so |>
import_vdj(bcr_dirs, prefix = "bcr_") |>
import_vdj(tcr_dirs, prefix = "tcr_")
This results in two sets of new columns being added to the meta.data. When performing downstream analysis using other djvdj functions, be sure to specify the correct columns, i.e. ‘bcr_clonotype_id’ or ‘tcr_clonotype_id’.
so_vdj |>
slot("meta.data") |>
head(3)
#> orig.ident nCount_RNA nFeature_RNA
#> BL6_AAACGGGGTTCTGTTT-1 BL6 202 25
#> BL6_AAAGATGCAACAACCT-1 BL6 42 20
#> BL6_AACGTTGCACGACTCG-1 BL6 32 19
#> bcr_clonotype_id bcr_exact_subclonotype_id
#> BL6_AAACGGGGTTCTGTTT-1 <NA> NA
#> BL6_AAAGATGCAACAACCT-1 clonotype7 1
#> BL6_AACGTTGCACGACTCG-1 clonotype32 1
#> bcr_chains bcr_n_chains bcr_cdr3
#> BL6_AAACGGGGTTCTGTTT-1 <NA> NA <NA>
#> BL6_AAAGATGCAACAACCT-1 IGK 1 CFQGSHVPWTF
#> BL6_AACGTTGCACGACTCG-1 IGK 1 CQQYNSYPLTF
#> bcr_cdr3_nt bcr_cdr3_length
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 TGCTTTCAAGGTTCACATGTTCCGTGGACGTTC 11
#> BL6_AACGTTGCACGACTCG-1 TGTCAGCAATATAACAGCTATCCTCTCACGTTC 11
#> bcr_cdr3_nt_length bcr_v_gene bcr_d_gene
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 33 IGKV1-117 None
#> BL6_AACGTTGCACGACTCG-1 33 IGKV6-15 None
#> bcr_j_gene bcr_c_gene bcr_isotype bcr_reads
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 IGKJ1 IGKC None 352
#> BL6_AACGTTGCACGACTCG-1 IGKJ5 IGKC None 342
#> bcr_umis bcr_productive bcr_full_length bcr_paired
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> <NA> NA
#> BL6_AAAGATGCAACAACCT-1 21 TRUE TRUE FALSE
#> BL6_AACGTTGCACGACTCG-1 18 TRUE TRUE FALSE
#> tcr_clonotype_id tcr_chains tcr_n_chains tcr_cdr3
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> NA <NA>
#> BL6_AAAGATGCAACAACCT-1 <NA> <NA> NA <NA>
#> BL6_AACGTTGCACGACTCG-1 <NA> <NA> NA <NA>
#> tcr_cdr3_nt tcr_cdr3_length tcr_cdr3_nt_length
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 <NA> <NA> <NA>
#> BL6_AACGTTGCACGACTCG-1 <NA> <NA> <NA>
#> tcr_v_gene tcr_d_gene tcr_j_gene tcr_c_gene
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 <NA> <NA> <NA> <NA>
#> BL6_AACGTTGCACGACTCG-1 <NA> <NA> <NA> <NA>
#> tcr_reads tcr_umis tcr_productive tcr_full_length
#> BL6_AAACGGGGTTCTGTTT-1 <NA> <NA> <NA> <NA>
#> BL6_AAAGATGCAACAACCT-1 <NA> <NA> <NA> <NA>
#> BL6_AACGTTGCACGACTCG-1 <NA> <NA> <NA> <NA>
#> tcr_paired
#> BL6_AAACGGGGTTCTGTTT-1 NA
#> BL6_AAAGATGCAACAACCT-1 NA
#> BL6_AACGTTGCACGACTCG-1 NA
Other object types
In addition to Seurat objects, djvdj also works with
SingleCellExperiment objects and with data.frames. If no input object is
provided to import_vdj()
, a data.frame containing V(D)J
information will be returned. This data.frame can be used with other
djvdj functions to perform further downstream analysis.
vdj_dirs <- c(
MD4 = file.path(data_dir, "MD4_BCR"),
BL6 = file.path(data_dir, "BL6_BCR")
)
# This will load V(D)J data and return a data.frame
df_vdj <- import_vdj(vdj_dir = vdj_dirs)
Session info
#> R version 4.3.1 (2023-06-16)
#> Platform: x86_64-pc-linux-gnu (64-bit)
#> Running under: Ubuntu 22.04.3 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so; LAPACK version 3.10.0
#>
#> locale:
#> [1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8
#> [4] LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
#> [7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
#> [10] LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] dplyr_1.1.3 SeuratObject_4.1.4 Seurat_4.4.0
#> [4] djvdj_0.1.0
#>
#> loaded via a namespace (and not attached):
#> [1] RColorBrewer_1.1-3 jsonlite_1.8.7
#> [3] magrittr_2.0.3 spatstat.utils_3.0-3
#> [5] rmarkdown_2.25 zlibbioc_1.46.0
#> [7] fs_1.6.3 ragg_1.2.6
#> [9] vctrs_0.6.4 ROCR_1.0-11
#> [11] Rsamtools_2.16.0 memoise_2.0.1
#> [13] spatstat.explore_3.2-5 RCurl_1.98-1.12
#> [15] htmltools_0.5.6.1 sass_0.4.7
#> [17] sctransform_0.4.1 parallelly_1.36.0
#> [19] KernSmooth_2.23-21 bslib_0.5.1
#> [21] htmlwidgets_1.6.2 desc_1.4.2
#> [23] ica_1.0-3 plyr_1.8.9
#> [25] plotly_4.10.3 zoo_1.8-12
#> [27] cachem_1.0.8 igraph_1.5.1
#> [29] mime_0.12 lifecycle_1.0.3
#> [31] pkgconfig_2.0.3 Matrix_1.6-1.1
#> [33] R6_2.5.1 fastmap_1.1.1
#> [35] GenomeInfoDbData_1.2.10 fitdistrplus_1.1-11
#> [37] future_1.33.0 shiny_1.7.5.1
#> [39] digest_0.6.33 colorspace_2.1-0
#> [41] S4Vectors_0.38.2 patchwork_1.1.3
#> [43] rprojroot_2.0.3 tensor_1.5
#> [45] irlba_2.3.5.1 GenomicRanges_1.52.1
#> [47] textshaping_0.3.7 progressr_0.14.0
#> [49] fansi_1.0.5 spatstat.sparse_3.0-2
#> [51] httr_1.4.7 polyclip_1.10-6
#> [53] abind_1.4-5 compiler_4.3.1
#> [55] withr_2.5.1 bit64_4.0.5
#> [57] BiocParallel_1.34.2 MASS_7.3-60
#> [59] tools_4.3.1 lmtest_0.9-40
#> [61] httpuv_1.6.12 future.apply_1.11.0
#> [63] goftest_1.2-3 glue_1.6.2
#> [65] nlme_3.1-162 promises_1.2.1
#> [67] grid_4.3.1 Rtsne_0.16
#> [69] cluster_2.1.4 reshape2_1.4.4
#> [71] generics_0.1.3 gtable_0.3.4
#> [73] spatstat.data_3.0-1 tzdb_0.4.0
#> [75] tidyr_1.3.0 data.table_1.14.8
#> [77] hms_1.1.3 XVector_0.40.0
#> [79] sp_2.1-1 utf8_1.2.4
#> [81] BiocGenerics_0.46.0 spatstat.geom_3.2-7
#> [83] RcppAnnoy_0.0.21 ggrepel_0.9.4
#> [85] RANN_2.6.1 pillar_1.9.0
#> [87] stringr_1.5.0 vroom_1.6.4
#> [89] later_1.3.1 splines_4.3.1
#> [91] lattice_0.21-8 bit_4.0.5
#> [93] survival_3.5-5 deldir_1.0-9
#> [95] tidyselect_1.2.0 Biostrings_2.68.1
#> [97] miniUI_0.1.1.1 pbapply_1.7-2
#> [99] knitr_1.44 gridExtra_2.3
#> [101] IRanges_2.34.1 scattermore_1.2
#> [103] stats4_4.3.1 xfun_0.40
#> [105] matrixStats_1.0.0 stringi_1.7.12
#> [107] lazyeval_0.2.2 yaml_2.3.7
#> [109] evaluate_0.22 codetools_0.2-19
#> [111] tibble_3.2.1 cli_3.6.1
#> [113] uwot_0.1.16 xtable_1.8-4
#> [115] reticulate_1.34.0 systemfonts_1.0.5
#> [117] munsell_0.5.0 jquerylib_0.1.4
#> [119] GenomeInfoDb_1.36.4 Rcpp_1.0.11
#> [121] globals_0.16.2 spatstat.random_3.2-1
#> [123] png_0.1-8 parallel_4.3.1
#> [125] ellipsis_0.3.2 pkgdown_2.0.7
#> [127] ggplot2_3.4.4 readr_2.1.4
#> [129] bitops_1.0-7 listenv_0.9.0
#> [131] viridisLite_0.4.2 scales_1.2.1
#> [133] ggridges_0.5.4 crayon_1.5.2
#> [135] leiden_0.4.3 purrr_1.0.2
#> [137] rlang_1.1.1 cowplot_1.1.1