pacman::p_load(
Seurat, tidyverse, qs2, cowplot, tictoc, reticulate, ggpubr
)
knitr::opts_knit$set(root.dir = "/home/han/Desktop/guoqiang/stroke_bm/stroke_bm_Rproj")
setwd("/home/han/Desktop/guoqiang/stroke_bm/stroke_bm_Rproj")
source("codes/plot_colors.R")
source("codes/activity_helpers.R")
summarise <- dplyr::summarise
mutate <- dplyr::mutate
filter <- dplyr::filter
Sys.setenv(RETICULATE_PYTHON = "/home/han/anaconda3/envs/cytosig/bin/python")CytoSig cytokine activity
CytoSig:转录组看起来像被哪些细胞因子作用过,不是 ELISA。Lollipop 是样本级 ACI 减去 CTRL。
全细胞 CytoSig ridge,再对中性粒谱系(GMP + Pre-Neut + Neut,与 08 一致)做亚型分析。conda cytosig。均值热图:每个细胞因子跨细胞 z-score 再取均值。组间 Wilcoxon:细胞级 BH,样本级原始 p。Lollipop 样式同 arhgap35 analysis.R 的 ggdotchart。group 以 CTRL 为对照。nrand=0。
res_path <- "results/cytosig"
obj_path <- "data/rdata/activity"
if (dir.exists(res_path)) {
old_res <- list.files(res_path, full.names = TRUE)
if (length(old_res) > 0) unlink(old_res, recursive = TRUE)
} else {
dir.create(res_path, recursive = TRUE)
}
if (!dir.exists(obj_path)) dir.create(obj_path, recursive = TRUE)
nrand <- 0
alpha_ridge <- 1e4
traj_levels <- c(
"GMP",
"Promyelocyte", "MMP8 Pre-Neut", "MMP9 Pre-Neut",
"S100A12 Neut", "SLC8A1 Neut", "ISG15 Neut"
)seurat_object <- qs_read("data/rdata/seurat_object_final.qs2", nthreads = 10)
stopifnot(all(c("sample", "group", "annot_main", "annot_sub") %in%
colnames(seurat_object[[]])))
seurat_object$group <- factor(seurat_object$group, levels = c("CTRL", "ACI"))
seurat_object$annot_main <- factor(
as.character(seurat_object$annot_main),
levels = names(annot_main_col)
)
if (length(Layers(seurat_object, search = "counts")) > 1) {
seurat_object <- JoinLayers(seurat_object)
}
if (!"data" %in% Layers(seurat_object, search = "data")) {
seurat_object <- NormalizeData(seurat_object, verbose = TRUE)
}
cell_meta <- FetchData(
seurat_object,
vars = c("sample", "group", "annot_main", "annot_sub")
) |>
rownames_to_column("barcode")
print(table(cell_meta$annot_main, cell_meta$group))
CTRL ACI
HSPC 1390 1976
B 3641 664
Plasma 445 109
T 6894 3560
NK 954 793
Mono/DC 2060 1850
pDC 363 103
Pre-Neut 1216 12291
Neut 885 16783
Ery 4890 323
1. CytoSig ridge(全细胞)
给每个细胞打一套细胞因子响应分数。推断「像被什么刺激过」,不是测到的浓度。
用 CytoSig 签名对 log 表达做 ridge,得到每个细胞的细胞因子响应分数。
cs_qs2 <- file.path(obj_path, "cytosig_all.qs2")
if (cache_ok(cs_qs2, colnames(seurat_object))) {
cs_wide <- qs_read(cs_qs2, nthreads = 10)
} else {
use_python("/home/han/anaconda3/envs/cytosig/bin/python", required = TRUE)
pd <- import("pandas", convert = FALSE)
cs <- import("CytoSig.Util", convert = FALSE)
sig <- pd$read_csv(py_to_r(cs$find_signature_path()), sep = "\t", index_col = 0L)
sig_genes <- as.character(py_to_r(sig$index$tolist()))
expr_genes <- intersect(rownames(seurat_object), sig_genes)
stopifnot(length(expr_genes) >= 10)
mat <- as.matrix(
GetAssayData(seurat_object, assay = "RNA", layer = "data")[expr_genes, ]
)
py$expr <- r_to_py(mat)
py$gene_names <- r_to_py(as.list(rownames(mat)))
py$cell_names <- r_to_py(as.list(colnames(mat)))
py$alpha_ridge <- alpha_ridge
py$nrand <- as.integer(nrand)
tic("CytoSig ridge_significance_test")
py_run_string("
import pandas as pd
from CytoSig.Util import ridge_significance_test, find_signature_path
Y = pd.DataFrame(expr, index=list(gene_names), columns=list(cell_names))
sig = pd.read_csv(find_signature_path(), sep='\\t', index_col=0)
res = ridge_significance_test(
sig, Y,
alpha=alpha_ridge,
alternative='two-sided',
nrand=int(nrand),
cnt_thres=10,
flag_normalize=True,
flag_const=False,
verbose=True
)
zscore = res[2]
")
toc()
z <- py_to_r(py$zscore)
cs_wide <- as.data.frame(t(as.matrix(z))) |>
rownames_to_column("barcode")
qs_save(cs_wide, cs_qs2, nthreads = 10)
}
ck <- features_from_wide(cs_wide)
dat <- bind_meta_acts(cell_meta, cs_wide)
stopifnot(nrow(dat) == nrow(cell_meta))
length(ck)[1] 43
print(ck) [1] "Activin A" "BDNF" "BMP2" "BMP4" "BMP6" "CD40L"
[7] "CXCL12" "EGF" "FGF2" "GCSF" "GDF11" "GMCSF"
[13] "HGF" "IFN1" "IFNG" "IFNL" "IL10" "IL12"
[19] "IL13" "IL15" "IL17A" "IL1A" "IL1B" "IL2"
[25] "IL21" "IL22" "IL27" "IL3" "IL36" "IL4"
[31] "IL6" "LIF" "LTA" "MCSF" "NO" "OSM"
[37] "TGFB1" "TGFB3" "TNFA" "TRAIL" "TWEAK" "VEGFA"
[43] "WNT3A"
2. 细胞大类:活性热图
哪些大类看起来对哪些细胞因子更敏感。颜色是相对高低。
热图:每个细胞因子先在细胞间 z-score,再按大类取均值。
mean_main <- mean_by_scaled(dat, ck, "annot_main")
p_hm_main <- plot_heatmap_mean(mean_main, ck, row_col = "annot_main") +
scale_x_discrete(limits = names(annot_main_col))heatmap fill
Min. 1st Qu. Median Mean 3rd Qu. Max.
-1.67646 -0.58416 -0.13992 -0.09939 0.33246 2.15273
|x| q80 / q90 / q95: 0.82 / 1.04 / 1.23
ggsave(file.path(res_path, "01_heatmap_annot_main.pdf"), p_hm_main, width = 8, height = 10, dpi = 600)
p_hm_mainmean_main_g <- mean_by_scaled(dat, ck, c("annot_main", "group"))
long_mg <- tidyr::pivot_longer(
mean_main_g, dplyr::all_of(ck), names_to = "feature", values_to = "mean"
) |>
dplyr::mutate(
annot_main = factor(annot_main, levels = names(annot_main_col)),
group = factor(group, levels = c("CTRL", "ACI"))
)
p_hm_main_g <- ggplot(long_mg, aes(x = annot_main, y = feature, fill = mean)) +
geom_tile(color = "white", linewidth = 0.4) +
facet_wrap(~group, ncol = 2) +
scale_fill_activity(long_mg$mean) +
theme_classic() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 9)) +
xlab(NULL) +
ylab(NULL)heatmap fill
Min. 1st Qu. Median Mean 3rd Qu. Max.
-1.9526 -0.5836 -0.1353 -0.1150 0.3159 2.2688
|x| q80 / q90 / q95: 0.888 / 1.11 / 1.29
ggsave(file.path(res_path, "01_heatmap_annot_main_group.pdf"), p_hm_main_g, width = 12, height = 10, dpi = 600)
p_hm_main_g3. 细胞大类:CTRL vs ACI
各大类上 ACI 减 CTRL。红 = ACI 更高。
ck_cell_main <- add_fdr(cell_group_tests(dat, ck, strata_col = "annot_main")) |>
dplyr::mutate(annot_main = factor(.data$stratum, levels = names(annot_main_col)))
ck_med_main <- sample_medians(dat, ck, extra_group = "annot_main")
ck_sample_main <- add_stars(sample_group_tests(ck_med_main, ck, strata_col = "annot_main")) |>
dplyr::mutate(annot_main = factor(.data$stratum, levels = names(annot_main_col)))
write_csv(ck_cell_main, file.path(res_path, "02_wilcox_cell_annot_main.csv"))
write_csv(ck_sample_main, file.path(res_path, "02_wilcox_sample_annot_main.csv"))
print(dplyr::filter(ck_sample_main, .data$p < 0.05))# A tibble: 194 × 10
stratum feature n_sample_ctrl n_sample_aci median_ctrl median_aci
<chr> <chr> <int> <int> <dbl> <dbl>
1 HSPC BDNF 6 5 -4.05 -2.76
2 HSPC BMP2 6 5 -1.96 -1.15
3 HSPC BMP4 6 5 -1.27 -0.900
4 HSPC BMP6 6 5 0.728 0.303
5 HSPC CD40L 6 5 -0.693 0.625
6 HSPC CXCL12 6 5 1.10 1.35
7 HSPC EGF 6 5 -1.01 1.05
8 HSPC GCSF 6 5 -1.98 0.142
9 HSPC GDF11 6 5 -1.23 -0.788
10 HSPC HGF 6 5 -2.55 -1.49
# ℹ 184 more rows
# ℹ 4 more variables: delta_aci_minus_ctrl <dbl>, p <dbl>, star <chr>,
# annot_main <fct>
p_d_s <- ggplot(
dplyr::mutate(ck_sample_main, feature = factor(feature, levels = ck)),
aes(x = annot_main, y = feature, fill = delta_aci_minus_ctrl)
) +
geom_tile(color = "white", linewidth = 0.4) +
geom_text(aes(label = star), size = 2.2) +
scale_fill_activity(ck_sample_main$delta_aci_minus_ctrl) +
theme_classic() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
xlab(NULL) +
ylab(NULL) +
ggtitle("Sample-level ACI − CTRL (Wilcoxon p)")heatmap fill
Min. 1st Qu. Median Mean 3rd Qu. Max.
-3.4506 -0.3221 0.1258 0.1778 0.6917 3.5940
|x| q80 / q90 / q95: 1.07 / 1.52 / 1.96
ggsave(file.path(res_path, "02_heatmap_sample_annot_main.pdf"), p_d_s, width = 8, height = 10, dpi = 600)
p_d_sp_d_c <- ggplot(
dplyr::mutate(ck_cell_main, feature = factor(feature, levels = ck)),
aes(x = annot_main, y = feature, fill = delta_aci_minus_ctrl)
) +
geom_tile(color = "white", linewidth = 0.4) +
geom_text(aes(label = star), size = 2.2) +
scale_fill_activity(ck_cell_main$delta_aci_minus_ctrl) +
theme_classic() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
xlab(NULL) +
ylab(NULL) +
ggtitle("Cell-level ACI − CTRL (BH)")heatmap fill
Min. 1st Qu. Median Mean 3rd Qu. Max.
-2.5838 -0.3561 0.1159 0.1710 0.6928 3.3629
|x| q80 / q90 / q95: 1.04 / 1.48 / 1.92
ggsave(file.path(res_path, "02_heatmap_cell_annot_main.pdf"), p_d_c, width = 8, height = 10, dpi = 600)
p_d_c4. 中性粒谱系:亚型活性热图
同一套细胞因子在 GMP / Pre-Neut / 成熟粒上的相对高低。
同一套分数,只看 GMP 到成熟粒。
dat_neut <- dat |>
dplyr::filter(as.character(.data$annot_sub) %in% traj_levels) |>
dplyr::mutate(
annot_sub = factor(as.character(.data$annot_sub), levels = traj_levels)
)
stopifnot(nrow(dat_neut) > 0)
print(table(dat_neut$annot_sub, dat_neut$group))
CTRL ACI
GMP 204 1320
Promyelocyte 154 1774
MMP8 Pre-Neut 294 5696
MMP9 Pre-Neut 768 4821
S100A12 Neut 486 7570
SLC8A1 Neut 280 8465
ISG15 Neut 119 748
mean_sub <- mean_by_scaled(dat_neut, ck, "annot_sub")
p_hm_sub <- plot_heatmap_mean(mean_sub, ck, row_col = "annot_sub") +
scale_x_discrete(limits = traj_levels)heatmap fill
Min. 1st Qu. Median Mean 3rd Qu. Max.
-2.17251 -0.45296 -0.03157 -0.08672 0.34780 2.81312
|x| q80 / q90 / q95: 0.793 / 1.04 / 1.52
ggsave(file.path(res_path, "03_neut_heatmap_subtype.pdf"), p_hm_sub, width = 8, height = 10, dpi = 600)
p_hm_submean_sub_g <- mean_by_scaled(dat_neut, ck, c("annot_sub", "group"))
long_sg <- tidyr::pivot_longer(
mean_sub_g, dplyr::all_of(ck), names_to = "feature", values_to = "mean"
) |>
dplyr::mutate(
annot_sub = factor(annot_sub, levels = traj_levels),
group = factor(group, levels = c("CTRL", "ACI"))
)
p_hm_sub_g <- ggplot(long_sg, aes(x = annot_sub, y = feature, fill = mean)) +
geom_tile(color = "white", linewidth = 0.4) +
facet_wrap(~group, ncol = 2) +
scale_fill_activity(long_sg$mean) +
theme_classic() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 9)) +
xlab(NULL) +
ylab(NULL)heatmap fill
Min. 1st Qu. Median Mean 3rd Qu. Max.
-2.9779 -0.6425 -0.1342 -0.1675 0.3171 3.9001
|x| q80 / q90 / q95: 0.963 / 1.3 / 1.64
ggsave(file.path(res_path, "03_neut_heatmap_subtype_group.pdf"), p_hm_sub_g, width = 12, height = 10, dpi = 600)
p_hm_sub_g5. 中性粒谱系总体:lollipop
中性粒谱系总体:每种细胞因子一个点,高度是样本级 ACI−CTRL。红显著升高,蓝显著降低,灰不显著。
每个点一种细胞因子,高度是样本级 ACI 减 CTRL。先看 IFN 和集落刺激因子落在哪一侧,再对照亚型图看信号停在哪一段。
ck_cell_lineage <- add_fdr(cell_group_tests(dat_neut, ck))
ck_med_lineage <- sample_medians(dat_neut, ck)
ck_sample_lineage <- add_stars(sample_group_tests(ck_med_lineage, ck))
write_csv(ck_cell_lineage, file.path(res_path, "04_neut_wilcox_cell_lineage.csv"))
write_csv(ck_sample_lineage, file.path(res_path, "04_neut_wilcox_sample_lineage.csv"))
print(dplyr::filter(ck_sample_lineage, .data$p < 0.05) |>
dplyr::arrange(dplyr::desc(delta_aci_minus_ctrl)))# A tibble: 29 × 8
feature n_sample_ctrl n_sample_aci median_ctrl median_aci
<chr> <int> <int> <dbl> <dbl>
1 IL10 6 5 0.408 4.06
2 GCSF 6 5 2.09 5.58
3 EGF 6 5 0.246 3.49
4 NO 6 5 2.28 5.23
5 IL1B 6 5 -0.0511 2.69
6 TGFB3 6 5 0.175 2.30
7 IL17A 6 5 1.83 3.38
8 LIF 6 5 -0.935 0.551
9 TRAIL 6 5 1.76 3.14
10 VEGFA 6 5 0.335 1.62
# ℹ 19 more rows
# ℹ 3 more variables: delta_aci_minus_ctrl <dbl>, p <dbl>, star <chr>
p_lolli_s <- plot_lollipop_delta(
ck_sample_lineage,
title = "Neut lineage (GMP + Pre-Neut + Neut), sample-level",
p_col = "p"
)
ggsave(file.path(res_path, "04_neut_lollipop_sample.pdf"), p_lolli_s, width = 12, height = 4.2, dpi = 600)
p_lolli_sp_lolli_c <- plot_lollipop_delta(
ck_cell_lineage,
title = "Neut lineage, cell-level (BH)",
p_col = "padj"
)
ggsave(file.path(res_path, "04_neut_lollipop_cell.pdf"), p_lolli_c, width = 12, height = 4.2, dpi = 600)
p_lolli_c6. 中性粒亚型:CTRL vs ACI
拆到亚型看信号停在哪一段。同样看样本级。
拆到亚型,看信号在前体还是成熟粒。组间仍看每例一个点。
ck_cell_sub <- add_fdr(cell_group_tests(dat_neut, ck, strata_col = "annot_sub")) |>
dplyr::mutate(annot_sub = factor(.data$stratum, levels = traj_levels))
ck_med_sub <- sample_medians(dat_neut, ck, extra_group = "annot_sub")
ck_sample_sub <- add_stars(sample_group_tests(ck_med_sub, ck, strata_col = "annot_sub")) |>
dplyr::mutate(annot_sub = factor(.data$stratum, levels = traj_levels))
write_csv(ck_cell_sub, file.path(res_path, "05_neut_wilcox_cell_subtype.csv"))
write_csv(ck_sample_sub, file.path(res_path, "05_neut_wilcox_sample_subtype.csv"))
print(dplyr::filter(ck_sample_sub, .data$p < 0.05))# A tibble: 137 × 10
stratum feature n_sample_ctrl n_sample_aci median_ctrl median_aci
<chr> <chr> <int> <int> <dbl> <dbl>
1 GMP BMP2 6 5 -1.69 -0.907
2 GMP EGF 6 5 -1.90 0.661
3 GMP HGF 6 5 -2.15 -1.42
4 GMP IFNL 6 5 1.37 0.268
5 GMP IL1B 6 5 -0.860 0.0343
6 GMP IL36 6 5 1.55 1.91
7 GMP IL6 6 5 1.58 2.35
8 GMP NO 6 5 -0.270 0.224
9 GMP TRAIL 6 5 2.34 3.18
10 GMP VEGFA 6 5 0.845 1.84
# ℹ 127 more rows
# ℹ 4 more variables: delta_aci_minus_ctrl <dbl>, p <dbl>, star <chr>,
# annot_sub <fct>
p_sub_s <- ggplot(
dplyr::mutate(ck_sample_sub, feature = factor(feature, levels = ck)),
aes(x = annot_sub, y = feature, fill = delta_aci_minus_ctrl)
) +
geom_tile(color = "white", linewidth = 0.4) +
geom_text(aes(label = star), size = 2.2) +
scale_fill_activity(ck_sample_sub$delta_aci_minus_ctrl) +
theme_classic() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
xlab(NULL) +
ylab(NULL) +
ggtitle("Subtype sample-level ACI − CTRL (Wilcoxon p)")heatmap fill
Min. 1st Qu. Median Mean 3rd Qu. Max.
-2.0184 -0.1951 0.3366 0.3400 0.7837 2.9955
|x| q80 / q90 / q95: 1.07 / 1.52 / 1.96
ggsave(file.path(res_path, "05_neut_heatmap_sample_subtype.pdf"), p_sub_s, width = 8, height = 10, dpi = 600)
p_sub_sp_sub_c <- ggplot(
dplyr::mutate(ck_cell_sub, feature = factor(feature, levels = ck)),
aes(x = annot_sub, y = feature, fill = delta_aci_minus_ctrl)
) +
geom_tile(color = "white", linewidth = 0.4) +
geom_text(aes(label = star), size = 2.2) +
scale_fill_activity(ck_cell_sub$delta_aci_minus_ctrl) +
theme_classic() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
xlab(NULL) +
ylab(NULL) +
ggtitle("Subtype cell-level ACI − CTRL (BH)")heatmap fill
Min. 1st Qu. Median Mean 3rd Qu. Max.
-1.9633 -0.2165 0.2766 0.3486 0.7943 3.1434
|x| q80 / q90 / q95: 1.09 / 1.56 / 2.1
ggsave(file.path(res_path, "05_neut_heatmap_cell_subtype.pdf"), p_sub_c, width = 8, height = 10, dpi = 600)
p_sub_csessionInfo()R version 4.4.3 (2025-02-28)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 24.04.3 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.12.0
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_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: Asia/Shanghai
tzcode source: system (glibc)
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] ggpubr_0.6.0 reticulate_1.42.0 tictoc_1.2.1 cowplot_1.1.3
[5] qs2_0.1.7 lubridate_1.9.3 forcats_1.0.0 stringr_1.5.1
[9] dplyr_1.1.4 purrr_1.0.2 readr_2.1.5 tidyr_1.3.1
[13] tibble_3.2.1 ggplot2_3.5.1 tidyverse_2.0.0 Seurat_5.2.1
[17] SeuratObject_5.0.2 sp_2.1-4
loaded via a namespace (and not attached):
[1] RColorBrewer_1.1-3 jsonlite_1.8.9 magrittr_2.0.3
[4] spatstat.utils_3.1-1 farver_2.1.2 rmarkdown_2.29
[7] ragg_1.3.3 vctrs_0.6.5 ROCR_1.0-11
[10] spatstat.explore_3.3-3 rstatix_0.7.2 htmltools_0.5.8.1
[13] broom_1.0.7 Formula_1.2-5 sctransform_0.4.1
[16] parallelly_1.39.0 KernSmooth_2.23-26 htmlwidgets_1.6.4
[19] ica_1.0-3 plyr_1.8.9 plotly_4.10.4
[22] zoo_1.8-12 igraph_2.1.2 mime_0.12
[25] lifecycle_1.0.4 pkgconfig_2.0.3 Matrix_1.7-3
[28] R6_2.5.1 fastmap_1.2.0 fitdistrplus_1.2-1
[31] future_1.34.0 shiny_1.9.1 digest_0.6.37
[34] colorspace_2.1-1 patchwork_1.3.0 tensor_1.5
[37] RSpectra_0.16-2 irlba_2.3.5.1 textshaping_0.4.0
[40] labeling_0.4.3 progressr_0.15.1 fansi_1.0.6
[43] spatstat.sparse_3.1-0 timechange_0.3.0 httr_1.4.7
[46] polyclip_1.10-7 abind_1.4-8 compiler_4.4.3
[49] bit64_4.5.2 withr_3.0.2 backports_1.5.0
[52] carData_3.0-5 fastDummies_1.7.4 ggsignif_0.6.4
[55] MASS_7.3-65 tools_4.4.3 lmtest_0.9-40
[58] httpuv_1.6.15 future.apply_1.11.3 goftest_1.2-3
[61] glue_1.8.0 nlme_3.1-166 promises_1.3.2
[64] grid_4.4.3 Rtsne_0.17 cluster_2.1.8.1
[67] reshape2_1.4.4 generics_0.1.3 gtable_0.3.6
[70] spatstat.data_3.1-4 tzdb_0.4.0 data.table_1.16.2
[73] hms_1.1.3 car_3.1-3 stringfish_0.18.0
[76] utf8_1.2.4 spatstat.geom_3.3-4 RcppAnnoy_0.0.22
[79] ggrepel_0.9.6 RANN_2.6.2 pillar_1.9.0
[82] vroom_1.6.5 spam_2.11-0 RcppHNSW_0.6.0
[85] later_1.4.1 splines_4.4.3 lattice_0.22-6
[88] bit_4.5.0 survival_3.8-3 deldir_2.0-4
[91] tidyselect_1.2.1 miniUI_0.1.1.1 pbapply_1.7-2
[94] knitr_1.49 gridExtra_2.3 scattermore_1.2
[97] xfun_0.49 matrixStats_1.4.1 stringi_1.8.4
[100] lazyeval_0.2.2 yaml_2.3.10 pacman_0.5.1
[103] evaluate_1.0.1 codetools_0.2-20 cli_3.6.3
[106] uwot_0.2.2 RcppParallel_5.1.9 systemfonts_1.1.0
[109] xtable_1.8-4 munsell_0.5.1 Rcpp_1.0.13-1
[112] globals_0.16.3 spatstat.random_3.3-2 png_0.1-8
[115] spatstat.univar_3.1-1 parallel_4.4.3 dotCall64_1.2
[118] listenv_0.9.1 viridisLite_0.4.2 scales_1.3.0
[121] ggridges_0.5.6 crayon_1.5.3 rlang_1.1.4