Cell type mapping with NNLS
Last compiled: 18 September 2024
cell_type_mapping_with_NNLS.rmd
Cell type mapping with SRT data refers to a set of methods which
allows you to infer the quantity of cells from SRT expression profiles.
semla
offers a quick method based on Non-Negative Least
Squares to infer cell type proportions directly from Visium spot
expression profiles. We utilize the NNLS method implemented in the RcppML v0.3.7
package available on CRAN: https://cran.r-project.org/web/packages/RcppML/index.html.
Please ensure you have the correct version installed before proceeding
with this tutorial.
In this tutorial, we’ll take a look at two examples. First, we have two tissue sections of a mouse brain and a single cell RNA-seq dataset from the Allen Brain Atlas. In the second example, we have a mouse kidney section and single cell RNA-seq data from the Tabula Muris Senis.
library(semla)
library(tibble)
library(dplyr)
if (!requireNamespace('TabulaMurisSenisData', quietly = TRUE)) {
BiocManager::install("TabulaMurisSenisData")
}
library(TabulaMurisSenisData)
library(SingleCellExperiment)
library(Seurat)
library(purrr)
library(patchwork)
library(ggplot2)
library(RcppML)
Mouse brain
For this tutorial, we will use a single-cell data set from the Allen Brain Atlas. You can check the code chunk below or follow this link to download it manually.
options(timeout=200)
tmpdir <- "." # Set current wd or change to tmpdir()
dir.create(paste0(tmpdir, "/mousebrain"))
targetdir <- paste0(tmpdir, "/mousebrain")
dir.create(paste0(targetdir, "/single-cell"))
destfile <- paste0(targetdir, "/single-cell/allen_brain.rds")
download.file("https://www.dropbox.com/s/cuowvm4vrf65pvq/allen_cortex.rds?dl=1", destfile = destfile)
We will also need to download the 10x Visium data from 10x Genomics website. You can download the files directly with R by following the code chunk below or download the data directly from here.
dir.create(paste0(targetdir, "/visium"))
# Download section 1
dir.create(paste0(targetdir, "/visium/S1"))
download.file(url = "https://cf.10xgenomics.com/samples/spatial-exp/1.0.0/V1_Mouse_Brain_Sagittal_Anterior/V1_Mouse_Brain_Sagittal_Anterior_filtered_feature_bc_matrix.h5",
destfile = paste0(targetdir, "/visium/S1/filtered_feature_bc_matrix.h5"))
download.file(url = "https://cf.10xgenomics.com/samples/spatial-exp/1.0.0/V1_Mouse_Brain_Sagittal_Anterior/V1_Mouse_Brain_Sagittal_Anterior_spatial.tar.gz",
destfile = paste0(targetdir, "/visium/S1/spatial.tar.gz"))
untar(tarfile = paste0(targetdir, "/visium/S1/spatial.tar.gz"),
exdir = paste0(targetdir, "/visium/S1/"))
file.remove(paste0(targetdir, "/visium/S1/spatial.tar.gz"))
# Download section 2
dir.create(paste0(targetdir, "/visium/S2"))
download.file(url = "https://cf.10xgenomics.com/samples/spatial-exp/1.0.0/V1_Mouse_Brain_Sagittal_Posterior/V1_Mouse_Brain_Sagittal_Posterior_filtered_feature_bc_matrix.h5",
destfile = paste0(targetdir, "/visium/S2/filtered_feature_bc_matrix.h5"))
download.file(url = "https://cf.10xgenomics.com/samples/spatial-exp/1.0.0/V1_Mouse_Brain_Sagittal_Posterior/V1_Mouse_Brain_Sagittal_Posterior_spatial.tar.gz",
destfile = paste0(targetdir, "/visium/S2/spatial.tar.gz"))
untar(tarfile = paste0(targetdir, "/visium/S2/spatial.tar.gz"),
exdir = paste0(targetdir, "/visium/S2/"))
file.remove(paste0(targetdir, "/visium/S2/spatial.tar.gz"))
Load Visium data with semla into a Seurat object. The following steps
assumes that the mouse brain 10x Visium data is located in
./mousebrain/visium/
.
# Assemble spaceranger output files
samples <- Sys.glob("./mousebrain/visium/*/filtered_feature_bc_matrix.h5")
imgs <- Sys.glob("./mousebrain/visium/*/spatial/tissue_hires_image.png")
spotfiles <- Sys.glob("./mousebrain/visium/*/spatial/tissue_positions_list.csv")
json <- Sys.glob("./mousebrain/visium/*/spatial/scalefactors_json.json")
infoTable <- tibble(samples, imgs, spotfiles, json,
section_id = paste0("section_", 1:2))
# Create Seurat object with 1 Sagittal Anterior section and 1 Sagittal Posterior section
se_brain_spatial <- ReadVisiumData(infoTable)
Load single-cell data
se_allen <- readRDS("./mousebrain/single-cell/allen_brain.rds")
Normalize data
Here we will apply the same log-normalization procedure to both the
10x Visium data (se_brain_spatial
) and to the single-cell
data (se_brain_singlecell
). We set the number of variable
features quite high because later on we will use the intersect between
the variable features in the single-cell data and the variable features
in the 10x Visium data for NNLS. The NNLS method is quite fast so there
is actually no need to select only a subset of features. Instead, we can
just use all genes that are shared across the single-cell and 10x Visium
data.
# Normalize data and find variable features for Visium data
se_brain_spatial <- se_brain_spatial |>
NormalizeData() |>
FindVariableFeatures(nfeatures = 10000)
# Normalize data and run vanilla analysis to create UMAP embedding
se_allen <- se_allen |>
NormalizeData() |>
FindVariableFeatures() |>
ScaleData() |>
RunPCA() |>
RunUMAP(reduction = "pca", dims = 1:30)
# Rerun FindVariableFeatures to increase the number before cell type deconvolution
se_allen <- se_allen |>
FindVariableFeatures(nfeatures = 10000)
We can visualize the available cell types in our UMAP embedding of the cells. We have access to 23 annotated cell types, including L2-L6 layer neurons which have a distinct spatial distribution in the tissue.
DimPlot(se_allen, group.by = "subclass")
Run NNLS
The RunNNLS()
method requires a normalized
Seurat
object with 10x Visium data and a a normalized
Seurat
object with single-cell data. The
groups
argument defines where the cell type labels should
be taken from in the single-cell Seurat
object. In our
single-cell Seurat
object, the labels are stored in the
“subclass” column.
DefaultAssay(se_brain_spatial) <- "Spatial"
ti <- Sys.time()
se_brain_spatial <- RunNNLS(object = se_brain_spatial,
singlecell_object = se_allen,
groups = "subclass")
##
## ── Predicting cell type proportions ──
##
## ℹ Fetching data from Seurat objects
## → Filtering out features that are only present in one data set
## → Kept 3378 features for deconvolution
## Warning: The NNLS function might break if a dev version of RcppML is used.
## • If RcppML::project(...) fails, try installing CRAN version 0.3.7 of RcppML.
## ℹ Preparing data for NNLS
## → Downsampling scRNA-seq data to include a maximum of 50 cells per cell type
## → Cell type(s) CR have too few cells (<10) and will be excluded
## → Kept 22 cell types after filtering
## → Calculating cell type expression profiles
## ℹ Predicting cell type proportions with NNLS for 22 cell types
## ℹ Returning results in a new 'Assay' named 'celltypeprops'
## ℹ Setting default assay to 'celltypeprops'
## ✔ Finished
## [1] "RunNNLS completed in 0.84 seconds"
# Check available cell types
rownames(se_brain_spatial)
## [1] "Astro" "Endo" "L2/3 IT" "L4" "L5 IT"
## [6] "L5 PT" "L6 CT" "L6 IT" "L6b" "Lamp5"
## [11] "Macrophage" "Meis2" "NP" "Oligo" "Peri"
## [16] "Pvalb" "SMC" "Serpinf1" "Sncg" "Sst"
## [21] "VLMC" "Vip"
NB: the CR cell type was discarded because the number of cell was
lower than 10. 10 is the lower limit for the allowed number of cells per
cell type but this can be overridden with
minCells_per_celltype
.
The plots below show the spatial distributions of proportions for a selected set of cell types.
# Plot selected cell types
DefaultAssay(se_brain_spatial) <- "celltypeprops"
selected_celltypes <- c("L2/3 IT", "L4", "L5 IT",
"L5 PT", "L6 CT", "L6 IT", "L6b",
"Oligo", "Pvalb", "Meis2", "Astro",
"VLMC", "SMC")
se_brain_spatial <- LoadImages(se_brain_spatial, image_height = 1e3)
##
## ── Loading H&E images ──
##
## ℹ Loading image from ./mousebrain/visium/S1/spatial/tissue_hires_image.png
## ℹ Scaled image from 1998x2000 to 1000x1001 pixels
## ℹ Loading image from ./mousebrain/visium/S2/spatial/tissue_hires_image.png
## ℹ Scaled image from 1998x2000 to 1000x1001 pixels
## ℹ Saving loaded H&E images as 'rasters' in Seurat object
plots <- lapply(seq_along(selected_celltypes), function(i) {
MapFeatures(se_brain_spatial, pt_size = 1.3,
features = selected_celltypes[i], image_use = "raw",
arrange_features = "row", scale = "shared",
override_plot_dims = TRUE,
colors = RColorBrewer::brewer.pal(n = 9, name = "Spectral") |> rev(),
scale_alpha = TRUE) +
plot_layout(guides = "collect") &
theme(legend.position = "right", legend.margin = margin(b = 50),
legend.text = element_text(angle = 0),
plot.title = element_blank())
}) |> setNames(nm = selected_celltypes)
Visualize multiple cell types
We can also visualize some of these cell types in one single plot
with MapMultipleFeatures()
.
# Load H&E images
se_brain_spatial <- se_brain_spatial |>
LoadImages()
# Plot multiple features
MapMultipleFeatures(se_brain_spatial,
image_use = "raw",
pt_size = 2, max_cutoff = 0.99,
override_plot_dims = TRUE,
colors = c("#332288", "#88CCEE", "#44AA99", "#117733", "#DDCC77", "#CC6677","#AA4499"),
features = selected_celltypes[1:7]) +
plot_layout(guides = "collect")
Cell type co-localization
By computing the pair-wise correlation between cell types across spots, we can get an idea of which cell types often appear together in the same spots.
cor_matrix <- FetchData(se_brain_spatial, selected_celltypes) |>
mutate_all(~ if_else(.x<0.1, 0, .x)) |> # Filter lowest values (-> set as 0)
cor()
diag(cor_matrix) <- NA
max_val <- max(cor_matrix, na.rm = T)
cols <- RColorBrewer::brewer.pal(7, "RdYlBu") |> rev(); cols[4] <- "white"
pheatmap::pheatmap(cor_matrix,
breaks = seq(-max_val, max_val, length.out = 100),
color=colorRampPalette(cols)(100),
cellwidth = 14, cellheight = 14,
treeheight_col = 10, treeheight_row = 10,
main = "Cell type correlation\nwithin spots")
We can also use the predicted cell type proportions to compute factors using NMF, and thereby summarizing the cell types presence within the same location into a set of predefined factors. Each factor can be viewed as a niche of a certain cell type composition.
nmf_data <- FetchData(se_brain_spatial, selected_celltypes) |>
RcppML::nmf(k = 10, verbose = F)
nmf_data_h <- nmf_data@h |> as.data.frame()
rownames(nmf_data_h) <- paste0("Factor_", 1:10)
colnames(nmf_data_h) <- selected_celltypes
nmf_data_h <- nmf_data_h |>
mutate_at(colnames(nmf_data_h),
~(scale(., center = FALSE, scale = max(., na.rm = TRUE)/1)))
nmf_data_h$Factor <- rownames(nmf_data_h) |>
factor(levels = paste0("Factor_", 1:10))
nmf_data_h_df <- nmf_data_h |>
tidyr::pivot_longer(cols = all_of(selected_celltypes),
names_to = "Cell",
values_to = "Weight")
ggplot(nmf_data_h_df, aes(x=Factor, y=Cell, size=Weight, color=Weight)) +
geom_point() +
labs(title="Cell type contribution", x="Factor", y = "Cell type",
color = "", size = "Scaled weight") +
scale_color_viridis_c(direction = -1, option = "magma") +
theme_bw() +
theme(axis.text.x = element_text(angle=45, hjust=1),
panel.grid = element_blank())
Mouse kidney
In the second example, we’ll look at data from mouse kidney. We can
obtain the single-cell data with the TabulaMurisSenisData
R
package from bioconductor. Let’s load the data and create a
Seurat
object from it.
sce <- TabulaMurisSenisDroplet(tissues = "Kidney")$Kidney
umis <- as(counts(sce), "dgCMatrix")
se_kidney_singlecell <- CreateSeuratObject(counts = umis, meta.data = colData(sce) |> as.data.frame())
The 10x Visium mouse kidney data can be downloaded from the 10x genomics website.
dir.create(paste0(tmpdir, "/kidney"))
targetdir <- paste0(tmpdir, "/kidney")
dir.create(paste0(targetdir, "/visium"))
# Download section 1
download.file(url = "https://cf.10xgenomics.com/samples/spatial-exp/1.1.0/V1_Mouse_Kidney/V1_Mouse_Kidney_filtered_feature_bc_matrix.h5",
destfile = paste0(targetdir, "/visium/filtered_feature_bc_matrix.h5"))
download.file(url = "https://cf.10xgenomics.com/samples/spatial-exp/1.1.0/V1_Mouse_Kidney/V1_Mouse_Kidney_spatial.tar.gz",
destfile = paste0(targetdir, "/visium/spatial.tar.gz"))
untar(tarfile = paste0(targetdir, "/visium/spatial.tar.gz"),
exdir = paste0(targetdir, "/visium/"))
file.remove(paste0(targetdir, "/visium/spatial.tar.gz"))
samples <- "./kidney/visium/filtered_feature_bc_matrix.h5"
imgs <- "./kidney/visium/spatial/tissue_hires_image.png"
spotfiles <- "./kidney/visium/spatial/tissue_positions_list.csv"
json <- "./kidney/visium/spatial/scalefactors_json.json"
infoTable <- tibble::tibble(samples, imgs, spotfiles, json)
se_kidney_spatial <- ReadVisiumData(infoTable)
Normalize data
We apply the same normalization procedure to
se_kidney_spatial
and se_kidney_singlecell
and
run FindVariableFeatures()
to detect the top most variable
genes.
se_kidney_spatial <- se_kidney_spatial |>
NormalizeData() |>
FindVariableFeatures(nfeatures = 10000)
For the single-cell kidney data, we’ll also filter the data prior to normalization to include cells collected at age 18m and remove cells with labels “nan” and “CD45”. This leaves us with 17 cell types.
keep_cells <- colnames(se_kidney_singlecell)[se_kidney_singlecell$age == "18m" & (!se_kidney_singlecell$free_annotation %in% c("nan", "CD45"))]
se_kidney_singlecell <- subset(se_kidney_singlecell, cells = keep_cells)
se_kidney_singlecell <- se_kidney_singlecell |>
NormalizeData() |>
FindVariableFeatures() |>
ScaleData() |>
RunPCA() |>
RunUMAP(reduction = "pca", dims = 1:30)
se_kidney_singlecell <- se_kidney_singlecell |>
FindVariableFeatures(nfeatures = 10000)
Run NNLS
Again, the RunNNLS()
method requires a single-cell
Seurat
object and a 10x Visium Seurat
object.
The cell type annotations are stored in the “free_annotation”
column.
ti <- Sys.time()
DefaultAssay(se_kidney_spatial) <- "Spatial"
se_kidney_spatial <- RunNNLS(object = se_kidney_spatial,
singlecell_object = se_kidney_singlecell,
groups = "free_annotation")
##
## ── Predicting cell type proportions ──
##
## ℹ Fetching data from Seurat objects
## → Filtering out features that are only present in one data set
## → Kept 4993 features for deconvolution
## Warning: The NNLS function might break if a dev version of RcppML is used.
## • If RcppML::project(...) fails, try installing CRAN version 0.3.7 of RcppML.
## ℹ Preparing data for NNLS
## → Downsampling scRNA-seq data to include a maximum of 50 cells per cell type
## → Cell type(s) CD45 NK cell,CD45 plasma cell have too few cells (<10) and will be excluded
## → Kept 15 cell types after filtering
## → Calculating cell type expression profiles
## ℹ Predicting cell type proportions with NNLS for 15 cell types
## ℹ Returning results in a new 'Assay' named 'celltypeprops'
## ℹ Setting default assay to 'celltypeprops'
## ✔ Finished
## [1] "RunNNLS finished in 0.24 seconds"
# Check available cell types
rownames(se_kidney_spatial)
## [1] "CD45 B cell"
## [2] "CD45 T cell"
## [3] "CD45 macrophage"
## [4] "Epcam kidney distal convoluted tubule epithelial cell"
## [5] "Epcam brush cell"
## [6] "Epcam kidney collecting duct principal cell"
## [7] "Epcam kidney proximal convoluted tubule epithelial cell"
## [8] "Epcam podocyte"
## [9] "Epcam proximal tube epithelial cell"
## [10] "Epcam thick ascending tube S epithelial cell"
## [11] "Pecam Kidney cortex artery cell"
## [12] "Pecam fenestrated capillary endothelial"
## [13] "Pecam kidney capillary endothelial cell"
## [14] "Stroma fibroblast"
## [15] "Stroma kidney mesangial cell"
NB: two cell types were discarded as they didn’t pass the minimum allowed cells per cell type threshold. The cell types discarded were NK cells and plasma cells.
# Plot selected cell types
DefaultAssay(se_kidney_spatial) <- "celltypeprops"
selected_celltypes <- c("Epcam kidney distal convoluted tubule epithelial cell",
"Epcam brush cell",
"Epcam kidney collecting duct principal cell",
"Epcam kidney proximal convoluted tubule epithelial cell",
"Epcam podocyte",
"Epcam proximal tube epithelial cell",
"Epcam thick ascending tube S epithelial cell",
"Pecam fenestrated capillary endothelial",
"Pecam kidney capillary endothelial cell",
"Stroma kidney mesangial cell")
plots <- lapply(seq_along(selected_celltypes), function(i) {
MapFeatures(se_kidney_spatial, pt_size = 1.3,
features = selected_celltypes[i],
override_plot_dims = TRUE) &
theme(plot.title = element_blank())
}) |> setNames(nm = selected_celltypes)
Visualize multiple cell types
We can select some of these cell types and visualize them in one plot
# Load H&E images
se_kidney_spatial <- se_kidney_spatial |>
LoadImages()
# Plot multiple features
MapMultipleFeatures(se_kidney_spatial,
image_use = "raw",
pt_size = 2, max_cutoff = 0.95,
override_plot_dims = TRUE,
colors = c("#332288", "#88CCEE", "#117733", "#DDCC77", "#CC6677","#AA4499"),
features = selected_celltypes[c(1, 2, 3, 4, 6, 7)]) +
plot_layout(guides = "collect")
Or zoom in on a region of interest
# Reload H&E image in higher resolution
se_kidney_spatial <- LoadImages(se_kidney_spatial, image_height = 1500)
# Plot H&E image
rst <- GetImages(se_kidney_spatial)[[1]]
p1 <- ggplot() +
ggtitle("H&E image of zoomed in area") +
theme(plot.title = element_text(hjust = 0.2)) +
inset_element(p = rst[(0.5*nrow(rst)):(0.7*nrow(rst)), (0.5*ncol(rst)):(0.7*ncol(rst))],
left = 0, bottom = 0, right = 1, top = 1)
# Plot multiple features with zoom
p2 <- MapMultipleFeatures(se_kidney_spatial,
image_use = "raw",
pt_size = 4.5, max_cutoff = 0.95,
crop_area = c(0.5, 0.5, 0.7, 0.7),
colors = c("#332288", "#88CCEE", "#117733", "#DDCC77", "#CC6677","#AA4499"),
features = selected_celltypes[c(1, 2, 3, 4, 6, 7)]) +
plot_layout(guides = "collect") &
theme(plot.title = element_blank())
p1 / p2
Package versions
semla
: 1.1.6RcppML
: 0.5.6
Session info
## R version 4.4.0 (2024-04-24)
## Platform: aarch64-apple-darwin20
## Running under: macOS Sonoma 14.5
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## time zone: Europe/Stockholm
## tzcode source: internal
##
## attached base packages:
## [1] stats4 stats graphics grDevices datasets utils methods
## [8] base
##
## other attached packages:
## [1] RcppML_0.5.6 patchwork_1.3.0
## [3] purrr_1.0.2 SingleCellExperiment_1.26.0
## [5] SummarizedExperiment_1.34.0 Biobase_2.64.0
## [7] GenomicRanges_1.56.1 GenomeInfoDb_1.40.1
## [9] IRanges_2.38.1 S4Vectors_0.42.1
## [11] BiocGenerics_0.50.0 MatrixGenerics_1.16.0
## [13] matrixStats_1.4.1 TabulaMurisSenisData_1.10.0
## [15] tibble_3.2.1 semla_1.1.6
## [17] ggplot2_3.5.1 dplyr_1.1.4
## [19] SeuratObject_4.1.4 Seurat_4.3.0.1
##
## loaded via a namespace (and not attached):
## [1] RcppAnnoy_0.0.22 splines_4.4.0
## [3] later_1.3.2 bitops_1.0-8
## [5] filelock_1.0.3 polyclip_1.10-7
## [7] lifecycle_1.0.4 globals_0.16.3
## [9] lattice_0.22-6 MASS_7.3-60.2
## [11] magrittr_2.0.3 plotly_4.10.4
## [13] sass_0.4.9 rmarkdown_2.28
## [15] jquerylib_0.1.4 yaml_2.3.10
## [17] httpuv_1.6.15 sctransform_0.4.1
## [19] spam_2.10-0 sp_2.1-4
## [21] spatstat.sparse_3.1-0 reticulate_1.39.0
## [23] cowplot_1.1.3 pbapply_1.7-2
## [25] DBI_1.2.3 RColorBrewer_1.1-3
## [27] abind_1.4-8 zlibbioc_1.50.0
## [29] Rtsne_0.17 RCurl_1.98-1.16
## [31] rappdirs_0.3.3 GenomeInfoDbData_1.2.12
## [33] ggrepel_0.9.6 irlba_2.3.5.1
## [35] listenv_0.9.1 spatstat.utils_3.1-0
## [37] gdata_3.0.0 pheatmap_1.0.12
## [39] goftest_1.2-3 spatstat.random_3.3-1
## [41] fitdistrplus_1.2-1 parallelly_1.38.0
## [43] pkgdown_2.1.0 DelayedArray_0.30.1
## [45] leiden_0.4.3.1 codetools_0.2-20
## [47] tidyselect_1.2.1 UCSC.utils_1.0.0
## [49] farver_2.1.2 BiocFileCache_2.12.0
## [51] spatstat.explore_3.3-2 jsonlite_1.8.8
## [53] progressr_0.14.0 ggridges_0.5.6
## [55] survival_3.6-4 systemfonts_1.1.0
## [57] dbscan_1.2-0 ggnewscale_0.5.0
## [59] tools_4.4.0 ragg_1.3.3
## [61] ica_1.0-3 Rcpp_1.0.13
## [63] glue_1.7.0 SparseArray_1.4.8
## [65] gridExtra_2.3 xfun_0.47
## [67] HDF5Array_1.32.1 withr_3.0.1
## [69] BiocManager_1.30.25 fastmap_1.2.0
## [71] rhdf5filters_1.16.0 fansi_1.0.6
## [73] shinyjs_2.1.0 digest_0.6.37
## [75] R6_2.5.1 mime_0.12
## [77] textshaping_0.4.0 colorspace_2.1-1
## [79] scattermore_1.2 gtools_3.9.5
## [81] tensor_1.5 spatstat.data_3.1-2
## [83] RSQLite_2.3.7 utf8_1.2.4
## [85] tidyr_1.3.1 generics_0.1.3
## [87] renv_1.0.2 data.table_1.16.0
## [89] S4Arrays_1.4.1 httr_1.4.7
## [91] htmlwidgets_1.6.4 uwot_0.2.2
## [93] pkgconfig_2.0.3 gtable_0.3.5
## [95] blob_1.2.4 lmtest_0.9-40
## [97] XVector_0.44.0 htmltools_0.5.8.1
## [99] dotCall64_1.1-1 scales_1.3.0
## [101] png_0.1-8 spatstat.univar_3.0-1
## [103] knitr_1.48 rstudioapi_0.16.0
## [105] reshape2_1.4.4 nlme_3.1-164
## [107] curl_5.2.2 rhdf5_2.48.0
## [109] cachem_1.1.0 zoo_1.8-12
## [111] stringr_1.5.1 BiocVersion_3.19.1
## [113] KernSmooth_2.23-24 parallel_4.4.0
## [115] miniUI_0.1.1.1 AnnotationDbi_1.60.2
## [117] desc_1.4.3 pillar_1.9.0
## [119] grid_4.4.0 vctrs_0.6.5
## [121] RANN_2.6.2 promises_1.3.0
## [123] dbplyr_2.5.0 xtable_1.8-4
## [125] cluster_2.1.6 evaluate_0.24.0
## [127] zeallot_0.1.0 magick_2.8.4
## [129] cli_3.6.3 compiler_4.4.0
## [131] rlang_1.1.4 crayon_1.5.3
## [133] future.apply_1.11.2 labeling_0.4.3
## [135] plyr_1.8.9 forcats_1.0.0
## [137] fs_1.6.4 stringi_1.8.4
## [139] viridisLite_0.4.2 deldir_2.0-4
## [141] munsell_0.5.1 Biostrings_2.72.1
## [143] lazyeval_0.2.2 spatstat.geom_3.3-2
## [145] Matrix_1.7-0 ExperimentHub_2.6.0
## [147] bit64_4.0.5 future_1.34.0
## [149] Rhdf5lib_1.26.0 KEGGREST_1.44.1
## [151] shiny_1.9.1 highr_0.11
## [153] interactiveDisplayBase_1.42.0 AnnotationHub_3.6.0
## [155] ROCR_1.0-11 igraph_2.0.3
## [157] memoise_2.0.1 bslib_0.8.0
## [159] bit_4.0.5