This vignette demonstrates the use of the sbivar package: Spatial BIVARiate association tests. It provides a suite of tests for bivariate spatial association across two spatial omics modalities that have been aligned, but do not necessarily share the same coordinate grid, e.g. due to differences in resolution between measurement technologies. Unlike many existing methods, sbivar accounts for spatial autocorrelation (SAC) in each of the modalities before testing for bivariate association, thus maintaining control of the type I error rate. sbivar is suited for a single section per modality, as well as replicated studies with multiple sections. Implemented methods are bivariate Moran’s I, generalised additive models (GAMs) and bivariate Gaussian processes (GPs); the modified t-test as implemented in the SpatialPack package is also wrapped for convenience. Basic plotting functions for checking alignment and visualizing results are included.
The package can be installed from Bioconductor as follows:
Alternatively, the latest version can be installed from github as:
Once installed, we can load the package:
The sbivar package can be computationally intensive, since the number of bivariate tests equals the product of the numbers of features of both modalities. For this reason we provide multithreading through the BiocParallel package.
All the user needs to do, is choose the number of cores:
and prepare the parallel backend. The code is different for windows or unix-based systems (linux and macOS), but is taken care of by the following code snippet:
param <- if (.Platform$OS.type == "unix") {
# On unix-based systems (linux and macOS), use MulticoreParam
MulticoreParam(nCores)
} else {
# On windows, build vignette without multithreading
SerialParam()
}
register(param)On windows, once the package has been built, for multithreading use
Wherever applicable, the registered backend will be used throughout the analysis. For serial calculations, for instance if memory is limiting, choose instead
Furthermore, it is highly recommended to install a matrix library such as “OpenBLAS”, “Intel MKL” or “Apple’s accelerate”, that employ threading for key matrix manipulations used throughout the package.
As example dataset, we use the one by Vicari et al. (2024), which includes replicated measurements of spatial transcriptomics and metabolomics coprofiled on mouse brain sections. A subset of the data is available in the sbivar package and can be loaded as:
## [1] "TranscriptCoords" "TranscriptOutcomes" "MetaboliteCoords"
## [4] "MetaboliteOutcomes"
This object consists of four lists of length six: TranscriptCoords and MetaboliteCoords for the coordinates, and TranscriptOutcomes and MetaboliteOutcomes for the feature measurements. Only the 5 most abundant features per modality are included in the package, for real datasets we also recommend to filter on the most abundant features, or apply the method to the entire dataset. The sbivar package assumes that the data have been pre-aligned, hence it is always a good idea to check the alignment visually:
The alignment seems successful, notice that some tissue areas are only covered by one modality though.
The Vicari data consist of six images which can be analysed jointly, but for didactical purposes we first analyse a single image here, the sample “V11T16-085_A1”.
singleSample <- "V11T16-085_A1"
singleStxCoords <- Vicari$TranscriptCoords[[singleSample]]
singleStx <- Vicari$TranscriptOutcomes[[singleSample]]
singleMetCoords <- Vicari$MetaboliteCoords[[singleSample]]
singleMet <- Vicari$MetaboliteOutcomes[[singleSample]]We analyse this single sample using bivariate Moran’s I. We choose to normalize both modalities to relative abundances (see ?normMat).
moransIRes <- sbivar(singleStx, singleMet, singleStxCoords, singleMetCoords,
method = "Moran's I", normX = "rel", normY = "rel"
)## Starting sbivar analysis of a single image on 2 computing cores
## Testing significance of bivariate Moran's I for 25 feature pairs
## Calculating bivariate Moran's I statistics ...
## Fitting variograms for first modality (5 features) ...
## Fitting variograms for second modality (5 features) ...
## Calculating variances of bivariate Moran's I statistics ...
Have a look at the results, which are sorted by increasing p-value:
## Modality_X Modality_Y Ixy_5e.06 Ixy_2e.04 Ixy_0.02 SE.Ixy._5e.06
## 1 Sparc Taurine -1.275865e-04 -8.789649e-05 -4.676381e-05 3.830270e-05
## 2 Sparc GABA 1.243888e-04 1.093865e-04 6.397515e-05 4.263167e-05
## 3 Fth1 Histidine -9.796108e-05 -7.611385e-05 -2.593648e-05 4.979809e-05
## 4 Sparc Dopamine 8.103384e-05 5.156486e-05 1.695850e-05 4.482058e-05
## 5 Gnas Taurine -3.533777e-05 -1.832929e-05 -6.049097e-06 2.143787e-05
## 6 mt.Atp6 Histidine 8.383458e-05 6.505115e-05 2.256473e-05 5.304026e-05
## SE.Ixy._2e.04 SE.Ixy._0.02 pVal pAdj
## 1 3.603835e-05 3.095988e-05 0.002437642 0.06094105
## 2 4.060163e-05 3.502142e-05 0.006819546 0.08524432
## 3 4.810448e-05 4.309704e-05 0.102890944 0.76609491
## 4 4.270522e-05 3.607202e-05 0.168602858 0.76609491
## 5 1.570091e-05 1.304224e-05 0.218341722 0.76609491
## 6 5.152161e-05 4.674568e-05 0.222927571 0.76609491
Plot the most significantly spatially associated gene-metabolite pair :
We see a clear negative relationship.
In addition, we employ generalized additive models (GAMs), with a negative binomial outcome distribution for the transcriptome data, and a gamma outcome distribution for the metabolome data. A log-link is used in both cases. For non-normal data, such as spatial transcriptomics and metabolomics data, this approach is usually preferable to the bivariate Moran’s I, as this latter one fails to account for heteroskedasticity,
FamiliesVicari <- list("X" = mgcv::nb(), "Y" = Gamma(lin = "log"))
gamRes <- sbivar(singleStx, singleMet, singleStxCoords, singleMetCoords,
method = "GAMs", families = FamiliesVicari
)## Starting sbivar analysis of a single image on 2 computing cores
## Fitting GAMs for first modality (5 features) ...
## Fitting GAMs for second modality (5 features) ...
## Performing 25 pairwise tests on fitted GAMs ...
Plot the most significant pair. Normalized data are shown, while the original analysis is on raw data, but we scale the size of the spots by the sample sums to reflect their higher weight in the analysis:
plotTopPair(gamRes,
X = singleStx, Y = singleMet, Cx = singleStxCoords, scaleBySampleSums = TRUE,
Ey = singleMetCoords, normX = "rel", normY = "rel"
)An other feature is found most significant by GAMs, now with a positive relationship. For GAMs, we can also plot the corresponding spline fit, with the contributions to the correlation 0.291:
plotGAMsTopResults(gamRes,
X = singleStx, Y = singleMet, Cx = singleStxCoords,
Ey = singleMetCoords
)Another available analysis for single images are bivariate Gaussian processes (GPs). Yet fitting GPs and calculating the score tests statistics can be computation and memory intensive! Hence the code is shown, but not run:
gpRes <- sbivar(singleStx, singleMet, singleStxCoords, singleMetCoords, method = "GPs", normX = "rel", normY = "rel")
head(gpRes$result)The analysis results can be written to an external spreadsheet using the following one-liner, e.g. for the GAM results.
Next, we analyse the six images jointly. Let’s look at their names:
## [1] "V11L12-109_A1" "V11L12-109_B1" "V11L12-109_C1" "V11T16-085_A1"
## [5] "V11T16-085_B1" "V11T16-085_C1"
We see that the first three and the last three are replicates from different mice (V11L12-109 and V11T16-085). We construct a variable identifying the mouse, consisting of the first 10 characters of the names:
For the multi-image case, we can also use bivariate Moran’s I as measure of spatial association, here with a nearest-neighbour (nn) weighting scheme for illustration (if the required RANN package is available). For computational reasons, we limit calculations to the first 500 observations:
VicariMultiTest <- lapply(Vicari, function(x) lapply(x, function(y) y[1:500, ]))
multiMoranRes <- sbivar(VicariMultiTest$TranscriptOutcomes, VicariMultiTest$MetaboliteOutcomes,
normX = "rel", normY = "rel",
VicariMultiTest$TranscriptCoords, VicariMultiTest$MetaboliteCoords,
method = "Moran", wo = if (require(RANN)) "nn" else "Gauss"
)## Loading required package: RANN
## Starting sbivar analysis (Moran's I) of 6 images on 2 computing cores
## Image 1 of 6
## Image 2 of 6
## Image 3 of 6
## Image 4 of 6
## Image 5 of 6
## Image 6 of 6
Note that for this analysis, we only calculate the bivariate Moran’s I statistics and their maxima, but not their variances, as we will quantify variability across replicates. Next we plug the calculated Moran’s I values into a linear model, with random effects for the individual mice, and adding a bogus fixed variable for illustrative purposes:
designDf <- data.frame("mouse" = mouse, "bogus" = factor(c(1, 2, 1, 2, 1, 2)))
multiMoranLmms <- fitLinModels(multiMoranRes, designDf, Formula = ~ bogus + (1 | mouse))## Fitting 25 mixed effects models on 2 cores
Extract the results and show the results for the intercept, i.e. the overall effect
multiMoranLmmsRes <- extractResultsMulti(multiMoranLmms, designDf)
head(multiMoranLmmsRes$result$Intercept)## Modality_X Modality_Y numNN_4 numNN_8 numNN_24 pVal
## 1 Gnas Tocopherol 0.008676723 0.010162118 0.013522596 0.01834492
## 2 mt.Atp6 Tocopherol 0.010649459 0.011038879 0.002456757 0.04915305
## 3 Fth1 Taurine 0.008847759 0.008113868 -0.007303785 0.06798428
## 4 mt.Atp6 Taurine -0.005607521 -0.003873033 0.011118747 0.14156282
## 5 Pcp4 Taurine -0.009708262 -0.011691945 -0.007060228 0.16938645
## 6 Fth1 Tocopherol -0.012294981 -0.013746067 -0.006134808 0.32288705
## pAdj
## 1 0.4586231
## 2 0.5665357
## 3 0.5665357
## 4 0.8469322
## 5 0.8469322
## 6 0.9880843
No features are significantly associated after multiplicity correction. This is in part caused by different experimental procedures used for the different sections, i.e. these are not real replicates yet, as technology is still being developed. For illustration, we plot the feature pair with the smallest p-values nevertheless:
plotTopPair(multiMoranLmmsRes,
Xl = Vicari$TranscriptOutcomes, Yl = Vicari$MetaboliteOutcomes,
Cxl = Vicari$TranscriptCoords, Eyl = Vicari$MetaboliteCoords, size = 0.4
)Again, the results of the multi-image analysis can be written to an external spreadsheet. Setting sigLevel to 1 means all feature pairs are written to the file:
Apart from matrices and lists, also other data objects from the Bioconductor universe can be analysed by sbivar.
The SpatialExperiment and MultiAssayExperiment classes are used in Bioconductor to store spatial (multi) omics experiments. The sbivar package provides functionality for doing analysis on these objects directly, for the general case of disjoint coordinate sets between the modalities.
For illustration, we first construct SpatialExperiment objects for the single-image case:
library(SpatialExperiment, quietly = TRUE)
StxSE <- SpatialExperiment(
assays = list("transcripts" = t(singleStx)),
spatialCoords = singleStxCoords
)
MetSE <- SpatialExperiment(
assays = list("metabolites" = t(singleMet)),
spatialCoords = singleMetCoords
)Look at the first object:
## class: SpatialExperiment
## dim: 5 2460
## metadata(0):
## assays(1): transcripts
## rownames(5): Fth1 mt.Atp6 Sparc Gnas Pcp4
## rowData names(0):
## colnames(2460): AAACAACGAATAGTTC-1 AAACAAGTATCTCCCA-1 ...
## TTGTTGTGTGTCAAGA-1 TTGTTTGTGTAAATTC-1
## colData names(1): sample_id
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):
## spatialCoords names(2) : x y
## imgData names(0):
Next we call the sbivar function with these as arguments, providing the names of the assays we want analysed. We set verbose to FALSE to prevent printing output:
resSpatExp <- sbivar(StxSE, MetSE,
assayX = "transcripts", assayY = "metabolites",
families = FamiliesVicari, method = "GAMs", verbose = FALSE
)Plot the second most significant result, again providing the SpatialExperiment objects
Now we construct a MultiAssayExperiment object
library(MultiAssayExperiment)
MAE <- MultiAssayExperiment(experiments = list(
"Stx" = StxSE,
"Msi" = MetSE
))
MAE## A MultiAssayExperiment object of 2 listed
## experiments with user-defined names and respective classes.
## Containing an ExperimentList class object of length 2:
## [1] Stx: SpatialExperiment with 5 rows and 2460 columns
## [2] Msi: SpatialExperiment with 5 rows and 3278 columns
## Functionality:
## experiments() - obtain the ExperimentList instance
## colData() - the primary/phenotype DataFrame
## sampleMap() - the sample coordination DataFrame
## `$`, `[`, `[[` - extract colData columns, subset, or experiment
## *Format() - convert into a long or wide DataFrame
## assays() - convert ExperimentList to a SimpleList of matrices
## exportClass() - save data to flat files
We run a the same analysis, now providing the experiment names on top of the assay names (since a MultiAssayExperiment can contain more than two modalities):
For the multi-image case, there are several options. One is to provide two lists of SpatialExperiment objects to the sbivar function. We construct such list here for illustrative purposes, and fit GAMs:
StxSElist <- lapply(selfName(names(Vicari$TranscriptOutcomes)), function(nam) {
SpatialExperiment(
assays = list("transcripts" = t(Vicari$TranscriptOutcomes[[nam]])),
spatialCoords = Vicari$TranscriptCoords[[nam]]
)
})
MetSElist <- lapply(selfName(names(Vicari$MetaboliteOutcomes)), function(nam) {
SpatialExperiment(
assays = list("metabolites" = t(Vicari$MetaboliteOutcomes[[nam]])),
spatialCoords = Vicari$MetaboliteCoords[[nam]]
)
})
multiMoranResSE <- sbivar(
X = StxSElist, Y = MetSElist, assayX = "transcripts",
assayY = "metabolites", method = "GAM", verbose = FALSE
)
multiMoranLmmsSE <- fitLinModels(multiMoranResSE, designDf, Formula = ~ (1 | mouse))## Fitting 25 mixed effects models on 2 cores
multiMoranLmmsResSE <- extractResultsMulti(multiMoranLmmsSE, designDf)
head(multiMoranLmmsResSE$result$Intercept)## Modality_X Modality_Y Estimate SE pVal pAdj
## 1 mt.Atp6 Tocopherol -0.3930271 0.2157481 0.1281296 0.960651
## 2 Fth1 Dopamine -0.3677403 0.2399068 0.1858886 0.960651
## 3 mt.Atp6 Histidine -0.4259019 0.2378129 0.3241990 0.960651
## 4 mt.Atp6 Taurine -0.4457374 0.2640538 0.3404712 0.960651
## 5 Sparc Tocopherol 0.4037679 0.2700480 0.3752822 0.960651
## 6 mt.Atp6 GABA -0.3386076 0.3152997 0.4773179 0.960651
Another option is to provide only two SpatialExperiment objects, but provide a sample_id argument that identifies the different images. For illustration, we construct such objects from the Vicari data.
SEsingleStx <- SpatialExperiment(
assays = list("transcripts" = t(Reduce(Vicari$TranscriptOutcomes, f = rbind))),
spatialCoords = Reduce(Vicari$TranscriptCoords, f = rbind),
colData = data.frame("sample_id" = rep(names(Vicari$TranscriptOutcomes),
times = vapply(Vicari$TranscriptOutcomes, FUN.VALUE = 0L, nrow)
))
)
SEsingleMet <- SpatialExperiment(
assays = list("metabolites" = t(Reduce(Vicari$MetaboliteOutcomes, f = rbind))),
spatialCoords = Reduce(Vicari$MetaboliteCoords, f = rbind),
colData = data.frame("sample_id" = rep(names(Vicari$MetaboliteOutcomes),
times = vapply(Vicari$MetaboliteOutcomes, FUN.VALUE = 0L, nrow)
))
)A quick look:
## class: SpatialExperiment
## dim: 5 16064
## metadata(0):
## assays(1): transcripts
## rownames(5): Fth1 mt.Atp6 Sparc Gnas Pcp4
## rowData names(0):
## colnames(16064): AAACAAGTATCTCCCA-1 AAACATTTCCCGGATT-1 ...
## TTGTTCTAGATACGCT-1 TTGTTGTGTGTCAAGA-1
## colData names(1): sample_id
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):
## spatialCoords names(2) : x y
## imgData names(0):
And run the same analysis:
sbivarMultiSingleSE <- sbivar(SEsingleStx, SEsingleMet,
sample_id_x = "sample_id",
assayX = "transcripts", assayY = "metabolites",
method = "GAMs", normX = "rel", normY = "rel"
)
multiMoranLmmsSingleSE <- fitLinModels(sbivarMultiSingleSE, designDf,
Formula = ~ (1 | mouse)
)
multiMoranLmmsResSingleSE <- extractResultsMulti(multiMoranLmmsSingleSE, designDf)AnnData is python data format often used to store spatial experiment results, which can also be read into R. An AnnData object is e.g. created by reading an ‘.h5ad’ with the functionality of the anndata R-package. Here we adapted one a file from the study by Godfrey et al. (2025), keeping its structure but subsetting it to only necessary components and the 10 most abundant features per modality. For illustration, this file is included in the sbivar package and can be read in (if the anndata and zellkonverter packages are installed) as:
if (reqadzk <- (require(anndata) && require(zellkonverter))) {
annDataObj <- read_h5ad(system.file("h5adData", "LC_170_subset.h5ad", package = "sbivar"))
}We suggest converting it to a SingleCellExperiment object from the eponymous R-package using the zellkonverter package:
if (reqadzk) {
sceStx <- AnnData2SCE(annDataObj, X_name = "X")
reducedDims(sceStx) <- annDataObj$obsm
}## For native R and reading and writing of H5AD files, an R <AnnData> object, and
## conversion to <SingleCellExperiment> or <Seurat> objects, check out the
## anndataR package:
## ℹ Install it from Bioconductor with `BiocManager::install("anndataR")`
## ℹ See more at <https://bioconductor.org/packages/anndataR/>
## This message is displayed once per session.
## Warning: The passed object is a 'AnnDataR6' object, conversion is likely to be less
## reliable
Note that a SingleCellExperiment object can only contain one modality at the time, here the transcriptomics. From there on, it is only a small step to a SpatialExperiment object as accepted by sbivar. The only tricky part are the spatial coordinates, which have no fixed slot in the AnnData object. Here, they have been stored in the “obsm” slot of the AnnData object, which means they have ended up in the “reducedDims” slot of the SingleCellExperiment object. In addition, we create a SpatialExperiment object for the metabolomics data, which has oddly been stored in the unstructured (“uns”) slot of the AnnData object. To keep build times of this vignette low, we again only look at a subset of 10 features
if (reqadzk) {
library(SpatialExperiment)
speStx <- SpatialExperiment(list("Stx" = assay(sceStx, "X")[1:10, ]),
colData = colData(sceStx),
spatialCoords = reducedDims(sceStx)$spatial
)
# Now for the metabolomics data too
speMet <- SpatialExperiment(list("msi" = t(annDataObj$uns$msi)[1:10, ]),
colData = colData(sceStx),
spatialCoords = reducedDims(sceStx)$spatial
)
rownames(speMet) <- annDataObj$uns[["mz_features"]][1:10]
# Need to set column names manually
}Note that in this example, the samples of the two modalities have been pre-matched (the “spatialCoords” slot is the same), which is in general not recommended. The above code chunks should not be applied thoughtlessly, as the AnnData structure is not very strict on the data types it includes. The analysis is then run and plotted as:
if (reqadzk) {
GodfreyRes <- sbivar(speStx, speMet,
assayX = "Stx", assayY = "msi",
normX = "rel", normY = "rel", verbose = FALSE
)
plotTopPair(GodfreyRes, speStx, speMet)
}An error like
Error in reducer$value.cache[[as.character(idx)]] <- values : wrong args for environment subassignment In addition: Warning message: In parallel::mccollect(wait = FALSE, timeout = 1) : 1 parallel job did not deliver a result
often indicates insufficient memory. Try reducing the number of cores requested with MultiCoreParam(), or switch to serial processing with register(SerialParam()).
## R version 4.6.0 (2026-04-24)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.4 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.26.so; LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
## [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: Etc/UTC
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats4 stats graphics grDevices utils datasets methods
## [8] base
##
## other attached packages:
## [1] zellkonverter_1.23.0 anndata_0.8.0
## [3] MultiAssayExperiment_1.39.0 SpatialExperiment_1.23.0
## [5] SingleCellExperiment_1.35.1 SummarizedExperiment_1.43.0
## [7] Biobase_2.73.1 GenomicRanges_1.65.0
## [9] Seqinfo_1.3.0 IRanges_2.47.2
## [11] S4Vectors_0.51.3 BiocGenerics_0.59.7
## [13] generics_0.1.4 MatrixGenerics_1.25.0
## [15] matrixStats_1.5.0 RANN_2.6.2
## [17] BiocParallel_1.47.0 sbivar_0.99.19
## [19] rmarkdown_2.31
##
## loaded via a namespace (and not attached):
## [1] RColorBrewer_1.1-3 sys_3.4.3 jsonlite_2.0.0
## [4] magrittr_2.0.5 spatstat.utils_3.2-3 magick_2.9.1
## [7] farver_2.1.2 nloptr_2.2.1 vctrs_0.7.3
## [10] minqa_1.2.8 spatstat.explore_3.8-1 SpatialPack_0.4-1
## [13] htmltools_0.5.9 S4Arrays_1.13.0 curl_7.1.0
## [16] SparseArray_1.13.2 sass_0.4.10 KernSmooth_2.23-26
## [19] bslib_0.11.0 basilisk_1.25.0 zoo_1.8-15
## [22] cachem_1.1.0 buildtools_1.0.0 mime_0.13
## [25] lifecycle_1.0.5 pkgconfig_2.0.3 Matrix_1.7-5
## [28] R6_2.6.1 fastmap_1.2.0 rbibutils_2.4.1
## [31] digest_0.6.39 numDeriv_2016.8-1.1 rprojroot_2.1.1
## [34] tensor_1.5.1 filelock_1.0.3 labeling_0.4.3
## [37] spatstat.sparse_3.2-0 polyclip_1.10-7 abind_1.4-8
## [40] mgcv_1.9-4 compiler_4.6.0 here_1.0.2
## [43] proxy_0.4-29 intervals_0.15.5 withr_3.0.2
## [46] S7_0.2.2 DBI_1.3.0 spatstat.model_3.7-1
## [49] MASS_7.3-65 concaveman_1.2.0 rappdirs_0.3.4
## [52] DelayedArray_0.39.3 rjson_0.2.23 classInt_0.4-11
## [55] tools_4.6.0 units_1.0-1 otel_0.2.0
## [58] zip_2.3.3 goftest_1.2-3 glue_1.8.1
## [61] nlme_3.1-169 grid_4.6.0 sf_1.1-1
## [64] smoppix_1.5.2 gtable_0.3.6 spatstat.data_3.1-9
## [67] class_7.3-23 sp_2.2-1 XVector_0.53.0
## [70] spatstat.geom_3.8-1 pillar_1.11.1 splines_4.6.0
## [73] dplyr_1.2.1 lattice_0.22-9 FNN_1.1.4.1
## [76] deldir_2.0-4 tidyselect_1.2.1 maketools_1.3.2
## [79] knitr_1.51 reformulas_0.4.4 V8_8.2.0
## [82] xfun_0.58 stringi_1.8.7 yaml_2.3.12
## [85] boot_1.3-32 evaluate_1.0.5 codetools_0.2-20
## [88] tibble_3.3.1 cli_3.6.6 RcppParallel_5.1.11-2
## [91] rpart_4.1.27 reticulate_1.46.0 Rdpack_2.6.6
## [94] jquerylib_0.1.4 spacetime_1.3-3 Rcpp_1.1.1-1.1
## [97] zigg_0.0.2 spatstat.random_3.5-0 dir.expiry_1.21.0
## [100] png_0.1-9 spatstat.univar_3.2-0 parallel_4.6.0
## [103] Rfast_2.1.5.2 ggplot2_4.0.3 assertthat_0.2.1
## [106] fastmatrix_0.6-6 lme4_2.0-1 viridisLite_0.4.3
## [109] lmerTest_3.2-1 scales_1.4.0 xts_0.14.2
## [112] e1071_1.7-17 gstat_2.1-6 openxlsx_4.2.8.1
## [115] rlang_1.2.0