wSIR 0.99.3
library(wSIR) # package itself
library(magrittr) # for %>%
library(ggplot2) # for ggplot
library(Rfast) # for distance correlation
library(doBy) # for which.maxn
library(vctrs) # for vec_rep_each
library(umap) # for umap
library(class) # for example wSIR application
Weighted Sliced Inverse Regression (wSIR) is a supervised dimension reduction technique for spatial transcriptomics data. This method uses each cell’s gene expression values as covariates and spatial position as the response. This allows us to create a low-dimensional representation of the gene expression data that retains the information about spatial patterns that is present in the gene expression data. The resulting mapping from gene expression data to a spatially aware low-dimensional embedding can be used to project new single-cell gene expression data into a low-dimensional space which preserves the ability to predict each cell’s spatial location from its low-dimensional embedding.
wSIR is an extension of the supervised dimension reduction technique of Sliced Inverse Regression (SIR).
SIR is an existing supervised dimension reduction method which works by grouping together the observations with similar values for the response. For spatial transcriptomics data, this means grouping all the cells into a certain number of tiles based on their spatial position. For example, if we use 4 tiles, then the cells in the top right quadrant of the image/tissue go to one group, those in the top left to another, and so on. Each of those groups is then summarised by averaging the expression level of all cells in each group for each of the genes. From there, eigendecomposition is performed on the resulting matrix of tile-gene means, then returning the SIR directions and SIR scores.
The motivation behind wSIR is that SIR only uses each cell’s spatial position when we are separating the cells into the given number of groups/tiles. Once those groups are created, we lose the fact that some groups may be more spatially related (if they come from adjacent tiles) than other groups (if they come from opposite sides of the tissue). wSIR uses a weight matrix to incorporate the spatial correlation between all pairs of cells in the SIR algorithm. This matrix has dimension H*H, where H is the number of tiles, and the (i,j)th entry represents the distance between tiles i and j. This matrix is incorporated into the eigendeomposition step. The wSIR output has the same structure as the SIR output.
In this vignette, we will demonstrate how to use WSIR to obtain a low-dimensional embedding of gene expression data. We will then explore this embedding using the package’s built-in functions. However, this low-dimensional matrix is more importantly used for your own downstream tasks that would benefit from a lower-dimensional representation of gene expression data that preserves information about each cell’s spatial location. We perform some basic downstream analysis to demonstrate the practicality of wSIR.
We use data from Lohoff et al, 2021. The code below would allow you to download the mouse data yourself using the MouseGastrulationData and scran R packages. We randomly sample 20% of the cells from each of the three biological replicate samples.
# Packages needed to download data
#library(scran) # for logNormCounts
#library(MouseGastrulationData) # to download the data for this vignette
set.seed(2024)
seqfish_data_sample1 <- LohoffSeqFISHData(samples = c(1,2))
seqfish_data_sample1 = logNormCounts(seqfish_data_sample1) # log transform variance stabilising
rownames(seqfish_data_sample1) <- rowData(seqfish_data_sample1)[,"SYMBOL"] # change rownames to gene symbols that are consistent
sample1_exprs = t(assay(seqfish_data_sample1, "logcounts")) # extract matrix of gene expressions
sample1_coords = spatialCoords(seqfish_data_sample1)[,1:2] %>% as.data.frame()
colnames(sample1_coords) = c("x", "y")
seqfish_data_sample2 <- LohoffSeqFISHData(samples = c(3,4))
seqfish_data_sample2 = logNormCounts(seqfish_data_sample2)
rownames(seqfish_data_sample2) <- rowData(seqfish_data_sample2)[,"SYMBOL"]
sample2_exprs = t(assay(seqfish_data_sample2, "logcounts"))
sample2_coords = spatialCoords(seqfish_data_sample2)[,1:2] %>% as.data.frame()
colnames(sample2_coords) = c("x", "y")
seqfish_data_sample3 <- LohoffSeqFISHData(samples = c(5,6))
seqfish_data_sample3 = logNormCounts(seqfish_data_sample3)
rownames(seqfish_data_sample3) <- rowData(seqfish_data_sample3)[,"SYMBOL"]
sample3_exprs = t(assay(seqfish_data_sample3, "logcounts"))
sample3_coords = spatialCoords(seqfish_data_sample3)[,1:2] %>% as.data.frame()
colnames(sample3_coords) = c("x", "y")
keep1 = sample(c(TRUE, FALSE), nrow(sample1_exprs), replace = TRUE, prob = c(0.2, 0.8))
keep2 = sample(c(TRUE, FALSE), nrow(sample2_exprs), replace = TRUE, prob = c(0.2, 0.8))
keep3 = sample(c(TRUE, FALSE), nrow(sample3_exprs), replace = TRUE, prob = c(0.2, 0.8))
sample1_exprs = sample1_exprs[keep1,]
sample1_coords = sample1_coords[keep1,]
sample2_exprs = sample2_exprs[keep2,]
sample2_coords = sample2_coords[keep2,]
sample3_exprs = sample3_exprs[keep3,]
sample3_coords = sample3_coords[keep3,]
sample1_cell_types = seqfish_data_sample1$celltype[keep1]
sample2_cell_types = seqfish_data_sample2$celltype[keep2]
sample3_cell_types = seqfish_data_sample3$celltype[keep3]
save(sample1_exprs, sample1_coords, sample1_cell_types,
sample2_exprs, sample2_coords, sample2_cell_types,
sample3_exprs, sample3_coords, sample3_cell_types,
file = "../data/MouseData.rda", compress = "xz")
For this vignette and the examples for each function in wSIR, we simply load
this data that has already been saved at data/MouseData.rda
.
data(MouseData)
wSIR contains two parameters, alpha
and slices
. Parameter slices
is the
number of groups along each spatial axis into which we split the observations
in the wSIR algorithm. More slices means we could pick up more spatial
information in the gene expression data, but we risk overfitting on the
training set. Parameter alpha
modifies the strength of the weight matrix.
alpha = 0
is equivalent to no spatial weighting, meaning the weight matrix
becomes the identity matrix. This is equivalent to SIR. Larger alpha
values
means there is more weight given to spatial correlation rather than gene
expression differences alone in the computation of the wSIR directions.
The function exploreWSIRParams
performs wSIR over many choices of alpha
and
slices
to identify the most appropriate parameters moving forward. Here, we
will use sample 1 only.
These parameters should both be tuned over some reasonable values. The function
exploreWSIRParams
computes and visualises the performance of wSIR for all
given combinations of slices
and alpha
. The performance is computed
from the following procedure:
1) For each combination of slices
and alpha
, split the data into 50%
train and 50% test (where train and test halves both include gene expression
data and cell coordinates).
2) Perform wSIR on the training set using the current combination of slices
and alpha.
3) Project the gene expression data of the testing set into low-dimensional
space using the wSIR results from step 2.
4) Evaluate wSIR’s performance by computing either the distance correlation
(“DC”, default), or the correlation of distances (“CD”) between the projected gene
expression data of the test set and the test coordinates, according to parameter
metric
.
5) Repeat steps 2-4 until it has been done nrep
times (nrep
is a parameter
whose default is 5). Calculate the average metric value over each of the nrep
iterations for this combination of slices and alpha.
6) Repeat steps 1-5 with all other combinations of slices
and alpha
to
obtain an average metric value for each combination.
7) Return the combination of slices
and alpha
with the highest average
metric value and display a plot showing the performance for every combination
of parameters.
Note: a key advantage of wSIR over SIR is parameter robustness. Here, we can
see that SIR’sperformance deteriorates as you use larger values for slices
.
However, wSIR’s performance is relatively stable as you vary both slices
and
alpha
across reasonable values (e.g. among the default values we optimise
over). In the following plot, the metric value becomes smaller as we increase
the number of slices for \(\alpha = 0\) (which corresponds to SIR). Performance is
stable for all non-zero alpha and slice combinations (which correspond to wSIR).
a <- Sys.time()
optim_obj = exploreWSIRParams(X = sample1_exprs,
coords = sample1_coords,
# optim_alpha = c(0,.5, 1,2,4,8),
# optim_slices = c(5,10,15),
optim_alpha = c(0, 4),
optim_slices = c(10, 15),
nrep = 5,
metric = "DC")
## set up nrep random splits of the data into training and test sets
## completed runs of wSIR and metric calculation
## Optimal (alpha, slices) pair: (0, 10)
Sys.time()-a
## Time difference of 18.96961 secs
optim_obj$plot
We next perform wSIR using the optimal parameter combination that we found in
the previous section. We use the gene expression matrix and spatial coordinates
from sample 1 here. This returns a list of results with 5 (named) slots, whose
details can be found at ?wSIR::wSIR
.
wsir_obj = wSIR(X = sample1_exprs,
coords = sample1_coords,
slices = optim_obj$best_slices,
alpha = optim_obj$best_alpha,
optim_params = FALSE)
names(wsir_obj)
## [1] "scores" "directions" "estd" "W" "evalues"
In this section, we will demonstrate how to use the built-in analysis functions to better understand how wSIR creates a spatially-informed low-dimensional embedding. These functions all use a wSIR result as an input. Here, we use the output from the previous section, meaning we are studying the result of performing wSIR on sample 1 only.
The findTopGenes
function finds and plots the genes with highest loading in
the specified wSIR directions (default is direction 1). If a gene has high
loading (in terms of magnitude), it is more important to the wSIR direction.
Since the wSIR directions are designed to retain information about each cell’s
spatial position, the genes with high loading should be spatially-related genes.
In the plot below, we can see which genes have the highest loading in wSIR direction 1. This is useful as it gives us an intuition about how wSIR creates the low-dimensional embedding. We can see that some of the genes are known spatial genes (e.g. Cdx2, Hox-), which is what we would expect to see.
We can simultaneously plot top genes for multiple directions, and utilise the
top_genes_obj = findTopGenes(WSIR = wsir_obj, highest = 8) # create top genes object
top_genes_plot = top_genes_obj$plot # select plot
top_genes_plot # print plot
top_genes_obj = findTopGenes(WSIR = wsir_obj, highest = 8, dirs = 2:4)
top_genes_plot = top_genes_obj$plot
top_genes_plot
The visualiseWSIRDirections
function plots each cell at its spatial position,
coloured by its value for each of the specified wSIR columns. This gives us an
understanding of what each column of the low-dimensional embedding represents.
Below, we visualise the cells at their spatial positions, coloured by each of the 5 wSIR directions The top left plot illustrates how, for this example, wSIR direction 1 captures information about the “y” spatial axis, since cells with higher “y” coordinate have low wSIR1 value, while cells with lower “y” coordinate have higher wSIR1 value. wSIR2 is shown in the next plot over (the one titled “2”), and we can see that wSIR column two appears to capture information about the “x” spatial coordinate. The remaining three wSIR columns all contain information about cell types, which we can tell by the regions of high and low wSIR column values spread across the tissue.
vis_obj = visualiseWSIRDirections(coords = sample1_coords, WSIR = wsir_obj, dirs = 8) # create visualisations
vis_obj
The two functions generateUmapFromWSIR
and plotUmapFromWSIR
create and
display UMAP dimension reduction calculated on the wSIR low-dimensional
embedding. We can colour the UMAP plot (where each point represents a cell) by
its value for various genes of interest. This visualises the structure of the
wSIR dimension reduction space, which is useful to gain more intuition about
what the space represents. Specifically, we can see if the wSIR space contains
neighbourhoods of high expression for specific genes, thus better understanding
how this space is made.
To specify which genes we would like to include, we can use the output from
the findTopGenes
function from above, which finds spatially-related genes by
ranking those with the highest loading in relevant wSIR directions. This output
is then the value for the highest_genes
parameter. Otherwise, we could also
specify our own genes of interest if there are some specific genes we would
like to visualise. For example, if we wanted to visualise the expression
distribution for Cdx2 and Hoxb4, we could use genes = c("Cdx2", "Hoxb4")
as
an argument in plotUmapFromWSIR
(and leave highest_genes
blank).
Below, we use the UMAP function to visualise the wSIR space computed on the
gene expression data from sample 1. We colour each cell by their values for
the 6 genes with highest value in wSIR direction 1 (as found by the
findTopGenes
function previously). We can see that for some of these genes,
there are specific regions of high expression in the UMAP plots, suggesting
that the wSIR space separates cells based on their expression for those genes.
umap_coords = generateUmapFromWSIR(WSIR = wsir_obj)
umap_plots = plotUmapFromWSIR(X = sample1_exprs,
umap_coords = umap_coords,
highest_genes = top_genes_obj,
n_genes = 6)
umap_plots
A key functionality of the wSIR package is the ability to project new single-cell data into the wSIR low-dimensional space. This will allow for a low-dimensional representation of gene expression data that contains information about each cell’s spatial position even though we do not have access to the spatial coordinates for this new data. This low-dimensional wSIR embedding would be especially useful for downstream applications, like spatial alignment or spatial clustering (where we don’t have spatial coordinates).
Here, we will demonstrate the steps for that, as well as a specific application.
For each projection example, we will perform wSIR on a spatial transcriptomics dataset which includes gene expression data and spatial coordinates. We will then project a “single-cell” dataset, which only contains the gene expression matrix, into wSIR low-dimensional space.
Here, we demonstrate the steps to project a new sample single-cell dataset into wSIR low-dimensional space having already performed wSIR on the spatial transcriptomics dataset from the first sample.
We have already performed wSIR on sample 1, so here we project sample 2’s gene expression matrix into the wSIR low-dimensional space, which will therefore have an ability to predict sample 2’s (unknown at this stage) spatial locations.
sample2_low_dim_exprs = projectWSIR(wsir = wsir_obj, newdata = sample2_exprs)
Check the dimension of sample 2’s low-dimensional gene expression data:
dim(sample2_low_dim_exprs)
## [1] 2986 50
Observe some of sample 2’s low-dimensional gene expression data:
head(sample2_low_dim_exprs)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,] 0.4033853 -1.1406906 0.9342274 -0.6690855 1.183150 -0.4204610 -1.6947454
## [2,] -0.3976906 -1.1332231 0.2099434 -0.9262752 1.452108 -0.3434242 0.2826430
## [3,] 2.8521104 0.5786873 1.7263464 -0.4939740 1.545942 1.9442965 -0.9077402
## [4,] 3.0851403 0.8251517 0.6092021 -0.5964077 1.349482 1.1061599 -0.8913565
## [5,] 1.7075150 -1.5915042 -0.4335929 -0.6712088 1.829439 1.3707372 0.8978932
## [6,] 1.5921375 -1.3481260 -0.4065247 0.1631131 1.854096 0.2094885 0.5237807
## [,8] [,9] [,10] [,11] [,12] [,13]
## [1,] -1.2416277 1.59455858 0.87866970 0.1545180 -0.1226031 0.007213118
## [2,] -0.9156203 -0.01792227 0.17127514 -0.6272048 0.3600095 0.041998794
## [3,] -1.1414361 0.88014085 0.10466509 -1.1003643 0.2268346 0.104254143
## [4,] -1.5925948 0.98843793 0.55220381 -0.9919387 1.0468458 0.535745625
## [5,] -1.5563948 -0.37715216 -0.29244180 -0.4787738 0.4219472 -0.599094022
## [6,] -1.1472571 -0.85171920 0.06985137 -0.5388220 -0.4363146 -1.735954576
## [,14] [,15] [,16] [,17] [,18] [,19]
## [1,] -0.26403842 -0.1667892 -0.1674317 -0.84025812 -1.2032348 -1.923318769
## [2,] 0.02027922 -0.1912650 0.4971098 -0.03229449 -0.6919699 -0.005947897
## [3,] -1.07366605 -0.6264570 1.6476511 -1.85407880 -1.2730726 -0.277065604
## [4,] -0.26912731 0.1633992 1.3475923 -1.08817836 -0.8927717 0.104622662
## [5,] -0.11342803 -0.7663365 0.3608360 1.22403405 -0.8265268 1.261045070
## [6,] 0.66379966 -1.2086104 -0.1218102 0.83435792 -1.8961773 1.151805215
## [,20] [,21] [,22] [,23] [,24] [,25]
## [1,] -1.3525301 -0.90228595 0.21986234 1.7140137 1.7309975 0.74602409
## [2,] -0.8091922 -2.27363291 0.20854077 -0.1540283 -1.1164174 -0.05310395
## [3,] 0.5378237 -0.03316571 -0.27216629 -0.5039993 -0.1865994 -0.79026591
## [4,] -0.3044058 0.39915731 -0.54615606 -1.0883485 -0.6943658 -1.00291231
## [5,] -0.1299859 -1.53565884 0.03956295 -0.5873782 0.1000467 -1.63964609
## [6,] -0.6253794 -0.99818155 0.14399058 -0.4114348 -0.3822816 -0.54459743
## [,26] [,27] [,28] [,29] [,30] [,31]
## [1,] 0.35040014 -1.9244114 1.0994142 -0.8017454 0.06630328 0.018409306
## [2,] -0.04033414 -2.4342194 0.1775621 0.4003911 1.99938051 -0.001305528
## [3,] -0.16474872 -1.2637777 0.1026267 0.2428714 0.58283064 0.195284812
## [4,] -0.32528226 -0.6078707 -0.1877018 0.3551147 0.25573785 -0.906437879
## [5,] -1.00529104 -1.7031747 1.2513900 0.4557731 0.18030373 0.863123205
## [6,] -1.13653850 -1.8444441 -0.1379572 0.2130001 0.62098951 0.555737550
## [,32] [,33] [,34] [,35] [,36] [,37]
## [1,] 0.3581564 -0.29453308 -1.22243261 -0.83359997 0.5626265 0.27147656
## [2,] -0.2014190 -0.32778650 -0.54913966 -1.38506568 -0.2047991 -0.55698357
## [3,] -0.3263791 -0.32772422 0.19305454 -0.01615896 0.1681945 -0.03517469
## [4,] -0.5392833 -0.06349666 -0.32993882 -1.26199626 0.3987478 0.47164230
## [5,] -0.2326273 -0.49177219 -0.22691262 -1.14278654 1.1506724 0.50078317
## [6,] 0.5669336 -0.12087072 0.00246478 -0.45564116 0.2931448 0.29778589
## [,38] [,39] [,40] [,41] [,42] [,43]
## [1,] -0.7485256 0.41777984 0.4383434 -2.50295425 0.3573508 -1.6484713
## [2,] 0.7616677 0.77111513 -1.1546844 -0.50097650 0.6704736 0.9528671
## [3,] 0.2185019 0.16336572 -0.3048052 -0.92621527 0.7283678 0.2140502
## [4,] 0.1381785 -0.05387757 -0.4122033 -0.09306071 0.7372195 -0.0273528
## [5,] 0.3879110 0.19807621 -0.5889438 -0.69818005 0.6589139 0.4508320
## [6,] 0.6482173 0.20978183 -1.0426766 -1.42117800 0.4702585 0.2349036
## [,44] [,45] [,46] [,47] [,48] [,49]
## [1,] -0.4895815 -0.59446975 0.71408399 -1.23068370 0.3799625 -0.3894140
## [2,] -0.2195819 0.62827717 -0.52972392 1.08694513 0.5879184 -2.0141168
## [3,] 0.2567104 -0.48469833 0.12967940 0.37968571 0.4806475 -0.5887303
## [4,] 0.1112703 0.02530738 -0.21172745 0.99822491 0.5224671 -0.6332211
## [5,] 0.2628886 0.19487445 -0.07063846 -0.59261012 -0.2320150 -0.7073504
## [6,] 0.9833049 -0.10346168 0.52593553 0.01375025 0.1666974 -0.5304861
## [,50]
## [1,] -0.39796516
## [2,] -0.02853424
## [3,] -0.06295446
## [4,] 0.44533316
## [5,] -0.25872334
## [6,] -0.23373365
This low-dimensional gene expression data can then be used for any later tasks which would benefit from a low-dimensional embedding of the gene expression data for all the samples, rather than just the gene expression data.
Here, we perform wSIR on samples 1 and 2 together. This requires the gene expression matrices from both samples joined together into one matrix, and the coords dataframes joined into one dataframe. We do this concatenation using rbind. We then specify the sample IDs for each row in the joined expression matrix and coordinates dataframe using the samples argument. This is a vector with a “1” for each row in sample 1 and a “2” for each row in sample 2.
We use the resulting wSIR output to project the gene expression data from sample 3 into low-dimensional space. We check the dimension of the resulting matrix.
wsir_obj_samples12 <- wSIR(X = rbind(sample1_exprs, sample2_exprs),
coords = rbind(sample1_coords, sample2_coords),
samples = c(rep(1, nrow(sample1_coords)), rep(2, nrow(sample2_coords))),
slices = optim_obj$best_slices,
alpha = optim_obj$best_alpha,
optim_params = FALSE)
sample3_low_dim_exprs <- projectWSIR(wsir = wsir_obj_samples12, newdata = sample3_exprs)
dim(sample3_low_dim_exprs)
## [1] 4607 50
This low-dimensional matrix can then be used for downstream tasks which would benefit from a low-dimensional embedding of sample 3’s gene expression matrix that contains information about each cell’s location. Examples for downstream use include spatial alignment of single-cell and spatial gene expression data via Tangram, using the wSIR scores as the input rather than the (unreduced) gene expression matrix.
An example of a very simple application is using the wSIR scores as an input to a KNN cell type classification algorithm. This is demonstrated below, using the ‘knn’ function from ‘class’ package.
samples12_cell_types = append(sample1_cell_types, sample2_cell_types)
knn_classification_object = knn(train = wsir_obj_samples12$scores,
test = sample3_low_dim_exprs,
cl = samples12_cell_types,
k = 10)
tail(knn_classification_object)
## [1] Presomitic mesoderm Presomitic mesoderm Presomitic mesoderm
## [4] Presomitic mesoderm Presomitic mesoderm Presomitic mesoderm
## 24 Levels: Allantois Anterior somitic tissues ... Surface ectoderm
In the above code, we use the wSIR scores as input for a simple KNN-based cell type classification tool. We print the tail of the prediction vector, demonstrating how we can use the wSIR-based low-dimensional gene expression data from a new sample as a step in a realistic analysis pipeline.
Session Info
sessionInfo()
## R version 4.4.1 (2024-06-14)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.1 LTS
##
## Matrix products: default
## BLAS: /media/volume/teran2_disk/biocbuild/bbs-3.20-bioc/R/lib/libRblas.so
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_GB LC_COLLATE=C
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: America/New_York
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] class_7.3-22 umap_0.2.10.0 vctrs_0.6.5 doBy_4.6.24
## [5] Rfast_2.1.0 RcppParallel_5.1.9 RcppZiggurat_0.1.6 Rcpp_1.0.13
## [9] ggplot2_3.5.1 magrittr_2.0.3 wSIR_0.99.3 BiocStyle_2.33.1
##
## loaded via a namespace (and not attached):
## [1] tidyselect_1.2.1 farver_2.1.2
## [3] dplyr_1.1.4 fastmap_1.2.0
## [5] SingleCellExperiment_1.27.2 digest_0.6.37
## [7] lifecycle_1.0.4 Deriv_4.1.6
## [9] compiler_4.4.1 rlang_1.1.4
## [11] sass_0.4.9 tools_4.4.1
## [13] utf8_1.2.4 yaml_2.3.10
## [15] knitr_1.48 labeling_0.4.3
## [17] askpass_1.2.1 S4Arrays_1.5.11
## [19] reticulate_1.39.0 DelayedArray_0.31.14
## [21] abind_1.4-8 BiocParallel_1.39.0
## [23] withr_3.0.1 purrr_1.0.2
## [25] BiocGenerics_0.51.3 grid_4.4.1
## [27] stats4_4.4.1 fansi_1.0.6
## [29] colorspace_2.1-1 scales_1.3.0
## [31] MASS_7.3-61 tinytex_0.53
## [33] SummarizedExperiment_1.35.4 cli_3.6.3
## [35] rmarkdown_2.28 crayon_1.5.3
## [37] generics_0.1.3 RSpectra_0.16-2
## [39] httr_1.4.7 modelr_0.1.11
## [41] rjson_0.2.23 cachem_1.1.0
## [43] stringr_1.5.1 zlibbioc_1.51.1
## [45] parallel_4.4.1 BiocManager_1.30.25
## [47] XVector_0.45.0 matrixStats_1.4.1
## [49] boot_1.3-31 Matrix_1.7-0
## [51] jsonlite_1.8.9 bookdown_0.41
## [53] IRanges_2.39.2 distances_0.1.11
## [55] S4Vectors_0.43.2 magick_2.8.5
## [57] jquerylib_0.1.4 tidyr_1.3.1
## [59] glue_1.8.0 codetools_0.2-20
## [61] cowplot_1.1.3 stringi_1.8.4
## [63] gtable_0.3.5 GenomeInfoDb_1.41.2
## [65] GenomicRanges_1.57.2 UCSC.utils_1.1.0
## [67] munsell_0.5.1 tibble_3.2.1
## [69] pillar_1.9.0 htmltools_0.5.8.1
## [71] openssl_2.2.2 GenomeInfoDbData_1.2.13
## [73] R6_2.5.1 microbenchmark_1.5.0
## [75] evaluate_1.0.1 lattice_0.22-6
## [77] Biobase_2.65.1 highr_0.11
## [79] png_0.1-8 backports_1.5.0
## [81] SpatialExperiment_1.15.1 broom_1.0.7
## [83] bslib_0.8.0 SparseArray_1.5.45
## [85] xfun_0.48 MatrixGenerics_1.17.0
## [87] pkgconfig_2.0.3