细胞分群质量评估

Learning Objectives:
  • Evaluate whether clustering artifacts are present
  • Determine the quality of clustering with PCA and UMAP plots, and decide when to re-cluster
  • Assess known cell type markers to hypothesize cell type identities of clusters

After separating cells into clusters, it is crtical to evaluate whether they are biologically meaningful or not. At this point we can also decide if we need to re-cluster and/or potentialy go back to a previous QC step.
In this lesson you will:

1 Exploration of quality control metrics

To determine whether our clusters might be due to artifacts such as cell cycle phase or mitochondrial expression, it can be useful to explore these metrics visually to see if any clusters exhibit enrichment or are different from the other clusters. However, if enrichment or differences are observed for particular clusters it may not be worrisome if it can be explained by the cell type.

To explore and visualize the various quality metrics, we will use the versatile DimPlot() and FeaturePlot() functions from Seurat.

2 数据读取

载入上一节中完成细胞分群的数据seurat_clustered

library(Seurat)
seurat_clustered <- readRDS("output/scRNA-seq_online/seurat_clustered.rds")
seurat_clustered
An object of class Seurat 
31130 features across 29629 samples within 3 assays 
Active assay: integrated (3000 features, 3000 variable features)
 2 layers present: data, scale.data
 2 other assays present: RNA, SCT
 2 dimensional reductions calculated: pca, umap
head(seurat_clustered, 5)
                      orig.ident nCount_RNA nFeature_RNA
ctrl_AAACATACAATGCC-1       ctrl       2344          874
ctrl_AAACATACATTTCC-1       ctrl       3124          895
ctrl_AAACATACCAGAAA-1       ctrl       2578          725
ctrl_AAACATACCAGCTA-1       ctrl       3260          978
ctrl_AAACATACCATGCA-1       ctrl        746          362
                                      seq_folder nUMI nGene log10GenesPerUMI
ctrl_AAACATACAATGCC-1 ctrl_raw_feature_bc_matrix 2344   874        0.8728630
ctrl_AAACATACATTTCC-1 ctrl_raw_feature_bc_matrix 3125   896        0.8447596
ctrl_AAACATACCAGAAA-1 ctrl_raw_feature_bc_matrix 2578   725        0.8384933
ctrl_AAACATACCAGCTA-1 ctrl_raw_feature_bc_matrix 3261   979        0.8512622
ctrl_AAACATACCATGCA-1 ctrl_raw_feature_bc_matrix  746   362        0.8906861
                       mitoRatio                 cells sample     S.Score
ctrl_AAACATACAATGCC-1 0.01962457 ctrl_AAACATACAATGCC-1   ctrl  0.04330502
ctrl_AAACATACATTTCC-1 0.01792000 ctrl_AAACATACATTTCC-1   ctrl  0.02661900
ctrl_AAACATACCAGAAA-1 0.01551590 ctrl_AAACATACCAGAAA-1   ctrl -0.04670650
ctrl_AAACATACCAGCTA-1 0.01379945 ctrl_AAACATACCAGCTA-1   ctrl -0.05832833
ctrl_AAACATACCATGCA-1 0.02144772 ctrl_AAACATACCATGCA-1   ctrl  0.03929605
                        G2M.Score Phase      mitoFr nCount_SCT nFeature_SCT
ctrl_AAACATACAATGCC-1  0.05422631   G2M      Medium       1572          829
ctrl_AAACATACATTTCC-1  0.05159679   G2M      Medium       1572          718
ctrl_AAACATACCAGAAA-1 -0.04841661    G1      Medium       1553          648
ctrl_AAACATACCAGCTA-1  0.05045960   G2M         Low       1576          756
ctrl_AAACATACCATGCA-1 -0.02995512     S Medium high       1075          363
                      integrated_snn_res.0.4 integrated_snn_res.0.6
ctrl_AAACATACAATGCC-1                      2                      1
ctrl_AAACATACATTTCC-1                      0                      2
ctrl_AAACATACCAGAAA-1                      0                      3
ctrl_AAACATACCAGCTA-1                      0                      3
ctrl_AAACATACCATGCA-1                      5                      6
                      integrated_snn_res.0.8 integrated_snn_res.1
ctrl_AAACATACAATGCC-1                      2                    2
ctrl_AAACATACATTTCC-1                      1                    0
ctrl_AAACATACCAGAAA-1                      3                   15
ctrl_AAACATACCAGCTA-1                      3                    3
ctrl_AAACATACCATGCA-1                      4                   12
                      integrated_snn_res.1.4 seurat_clusters
ctrl_AAACATACAATGCC-1                      5               5
ctrl_AAACATACATTTCC-1                      0               0
ctrl_AAACATACCAGAAA-1                     19              19
ctrl_AAACATACCAGCTA-1                      3               3
ctrl_AAACATACCATGCA-1                     13              13

3 分析样本类型是否影响细胞分群

首先通过UMAP图,直观查看不同样本类型的细胞分群情况:

# 先简单查看一下分群情况及不同cluster的细胞数
table(seurat_clustered@active.ident)

   0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15 
4220 3718 3649 3004 2164 1959 1810 1646 1504 1375 1208 1174  858  468  459  289 
  16 
 124 
# UMAP of cells in each cluster by sample
DimPlot(seurat_clustered, 
        label = TRUE, 
        split.by = "sample") + 
  NoLegend()

从UMAP图上可以直观的发现不同样本(ctrl vs. stim)的细胞分群非常一致,这是符合预期的。

接下来通过提取不同样本类型中各cluster的细胞数来以数据的形式验证这种一致性。下面是实现方法:

  1. 通过Seurat包的FetchData()函数可以从Seurat对象中提取指定的变量并形成行为细胞列为变量的数据框。这里通过关键词“ident”提取“active.ident”(即每个细胞所在的cluster的编号);并提取”orig.ident”变量,即每个细胞对应的样本类型(ctrl vs. stim)(也可以提取“sample”)

  2. 然后通过dplyr包的count()函数统计每个样本类型内每个cluster的细胞数量

  3. 最后,通过tidyr包的pivot_wider()函数将长数据转换成宽数据。其中的names_from参数用于指定原数据中要拆分的那一列的名字(会在转换后的数据中变成列名);values_from参数用于指定新数据集中单元格的值由旧数据的哪个(或哪些)变量的值填充

library(dplyr)
library(tidyr)
n_cells <- FetchData(seurat_clustered, 
                     vars = c("ident", "orig.ident")) |>
        count(ident, orig.ident) |>
        pivot_wider(names_from = ident,
                    values_from = n)
n_cells
# A tibble: 2 × 18
  orig.ident   `0`   `1`   `2`   `3`   `4`   `5`   `6`   `7`   `8`   `9`  `10`
  <chr>      <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
1 ctrl        2017  2398  1840  1076  1112   976   952   830   775   661   600
2 stim        2203  1320  1809  1928  1052   983   858   816   729   714   608
# ℹ 6 more variables: `11` <int>, `12` <int>, `13` <int>, `14` <int>,
#   `15` <int>, `16` <int>

从该表中可以看出,不同样本类型下的各细胞群的细胞数量基本一致。These clusters look pretty similar between conditions, which is good since we expected similar cell types to be present in both control and stimulated conditions.

Caution

Generally, we expect to see the majority of the cell type clusters to be present in all conditions; however, depending on the experiment we might expect to see some condition-specific cell types present.

4 分析细胞周期是否影响细胞分群

Next, we can explore whether the cells cluster influenced by the different cell cycle phases. We did not regress out variation due to cell cycle phase when we performed the SCTransform normalization (见Normalization and regressing out unwanted variation). If our cell clusters showed large differences in cell cycle expression, this would be an indication we would want to re-run the SCTransform and add the S.Score and G2M.Score to our variables to regress, then re-run the rest of the steps.

# Explore whether clusters segregate by cell cycle phase
DimPlot(seurat_clustered,
        label = TRUE, 
        split.by = "Phase") + 
  NoLegend()

We do not see much clustering by cell cycle score, so we can proceed with the QC.

5 分析其他非期望变异来源是否会影响细胞分群

Next we will explore additional metrics, such as the number of UMIs and genes per cell, S-phase and G2M-phase markers, and mitochondrial gene expression by UMAP. Looking at the individual S and G2M scores can give us additional information to checking the phase as we did previously.

Tip

The order argument will plot the positive cells above the negative cells, while the min.cutoff argument will determine the threshold for shading. A min.cutoff of q10 translates to the 10% of cells with the lowest expression of the gene will not exhibit any purple shading (completely gray) (min.cutoff定义着色阈值。这里指定值最低的10%的细胞不着色).

# Determine metrics to plot present in seurat_clustered@meta.data
metrics <-  c("nUMI", "nGene", "S.Score", "G2M.Score", "mitoRatio")

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = metrics,
            pt.size = 0.4, 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

The metrics seem to be relatively even across the clusters, with the exception of nGene exhibiting slightly higher values in clusters to the left of the plot. We can keep an eye on these clusters to see whether the cell types may explain the increase.

If we see differences corresponding to any of these metrics at this point in time, then we will often note them and then decide after identifying the cell type identities whether to take any further action.

6 分析主成分(PCs)对细胞分群的影响

We can also explore how well our clusters separate by the different PCs; we hope that the defined PCs separate the cell types well. To visualize this information, we need to extract the UMAP coordinate information for the cells along with their corresponding scores for each of the PCs to view by UMAP.

First, we identify the information we would like to extract from the Seurat object, then, we can use the FetchData() function to extract it.

# Defining the information in the seurat object of interest
columns <- c("ident", paste0("PC_", 1:16), "UMAP_1", "UMAP_2")

# Extracting this data from the seurat object
pc_data <- FetchData(seurat_clustered, 
                     vars = columns)
head(pc_data, 3)
                      ident      PC_1      PC_2      PC_3      PC_4       PC_5
ctrl_AAACATACAATGCC-1     2 -14.97782 -2.879193 -5.059351 -1.602766  0.8728779
ctrl_AAACATACATTTCC-1     1  22.39233 -5.296913  4.951958  3.112632  0.3379874
ctrl_AAACATACCAGAAA-1     3  28.98473  1.203408 -5.947993 -1.042701 -7.5690434
                           PC_6        PC_7       PC_8       PC_9     PC_10
ctrl_AAACATACAATGCC-1 -1.501420   0.5327841 -0.5855545  0.8866479 0.8223524
ctrl_AAACATACATTTCC-1 -7.873002   2.2740054 -5.8362430 -0.9666741 0.2170141
ctrl_AAACATACCAGAAA-1  5.477813 -10.7953185 19.5052392 -1.8312647 2.1803084
                          PC_11      PC_12      PC_13       PC_14     PC_15
ctrl_AAACATACAATGCC-1 -1.722880 -0.1832132  0.2985759 -0.04539058  1.260942
ctrl_AAACATACATTTCC-1  3.105132 -0.7964707  2.8982516  0.04362601 -3.189937
ctrl_AAACATACCAGAAA-1 -7.796582 -1.3324607 -2.3117140  3.06677862  1.663382
                           PC_16     UMAP_1    UMAP_2
ctrl_AAACATACAATGCC-1  0.1993319   7.270473 0.9072988
ctrl_AAACATACATTTCC-1  5.3805322  -8.742020 1.5622634
ctrl_AAACATACCAGAAA-1 -3.0593032 -10.032904 4.7139827
Tip

How did we know in the FetchData() function to include UMAP_1 to obtain the UMAP coordinates? Seurat常用函数清单 describes the function as being able to pull any data from the expression matrices, cell embeddings, or metadata.

For instance, if you explore the seurat_clustered@reductions list object, the first component is for PCA, and includes a slot for cell.embeddings (坐标数据). We can use the column names (PC_1, PC_2, PC_3, etc.) to pull out the coordinates or PC scores corresponding to each cell for each of the PCs (提取每个细胞在指定主成分上的坐标).

We could do the same thing for UMAP:

# 提取前5个细胞在前两个UMAP主成分上的坐标
seurat_clustered@reductions[["umap"]]@cell.embeddings[1:5, 1:2]
                          UMAP_1     UMAP_2
ctrl_AAACATACAATGCC-1   7.270473  0.9072988
ctrl_AAACATACATTTCC-1  -8.742020  1.5622634
ctrl_AAACATACCAGAAA-1 -10.032904  4.7139827
ctrl_AAACATACCAGCTA-1  -8.363044  5.0377137
ctrl_AAACATACCATGCA-1   6.875784 -4.6442526

等价于:

FetchData(seurat_clustered, vars = c("UMAP_1", "UMAP_2")) |> head(5)

The FetchData() function just allows us to extract the data more easily.

Caution

The pre-existing seurat_clustered loaded in previously was created using an older version of Seurat. As such the columns we Fetch() are in upper case (i.e UMAP_1). If you are using your own seurat object using a newer version of Seurat you will need to change the column names as shown below. Alternatively, explore your Seurat object to see how they have been stored.

 # Defining the information in the seurat object of interest
 columns <- c("ident", paste0("PC_", 1:16), "umap_1", "umap_2")

In the UMAP plots below, the cells are colored by their PC score for each respective principal component.

Let’s take a quick look at the top 16 PCs:

# Adding cluster label to center of cluster on UMAP
umap_label <- FetchData(seurat_clustered, 
                        vars = c("ident", "UMAP_1", "UMAP_2")) |>
  group_by(ident) |> # 指定分组计算依据
  summarise(UMAP1_mean = mean(UMAP_1), UMAP2_mean = mean(UMAP_2)) # 根据指定的分组依据进行分组计算
head(umap_label)
# A tibble: 6 × 3
  ident UMAP1_mean UMAP2_mean
  <fct>      <dbl>      <dbl>
1 0          8.42       1.99 
2 1         -9.18       1.84 
3 2          5.51       1.68 
4 3         -8.49       3.87 
5 4          6.67      -2.58 
6 5          0.359      0.115
# Plotting a UMAP plot for each of the PCs
library(purrr)
library(ggplot2)
library(cowplot)
library(dplyr)
map(paste0("PC_", 1:16), 
    function(pc) {
      ggplot(pc_data, 
             aes(UMAP_1, UMAP_2)) +
        geom_point(aes_string(color = pc), 
                   alpha = 0.7) +
        scale_color_gradient(low = "grey90", 
                             high = "blue") +
        geom_text(data = umap_label, 
                  aes(label = ident, UMAP1_mean, UMAP2_mean)) +
        ggtitle(pc)
      }) %>% 
  plot_grid(plotlist = .)

We can see how the clusters are represented by the different PCs. For instance, the genes driving PC_2 exhibit higher expression in clusters 8 and 12. We could look back at our genes driving this PC to get an idea of what the cell types might be:

# 提取PCA信息中的第二主成分,并展示对该主成分影响最大的前5个基因名
print(seurat_clustered[["pca"]], dims = 2, nfeatures = 5)
PC_ 2 
Positive:  GNLY, CCL5, NKG7, GZMB, FGFBP2 
Negative:  CD74, IGHM, IGKC, HLA-DRA, CD79A 

With the GNLY and NKG7 genes as positive markers of PC_2, we can hypothesize that clusters 8 and 12 correspond to NK cells ( Table 1 ). This just hints at what the clusters identity could be, with the identities of the clusters being determined through a combination of the PCs.

To truly determine the identity of the clusters and whether the resolution is appropriate, it is helpful to explore a handful of known gene markers for the cell types expected.

7 探索已知的cell type markers的表达

With the cells clustered, we can explore the cell type identities by looking for known markers. 下面给出了本案例的cell type markers及其对应的细胞类型:

Table 1: 细胞类型marker基因
Cell Type Marker
CD14+ monocytes CD14, LYZ
FCGR3A+ monocytes FCGR3A, MS4A7
Conventional dendritic cells FCER1A, CST3
Plasmacytoid dendritic cells IL3RA, GZMB, SERPINF1, ITM2C
Macrophages MARCO, ITGAM, ADGRE1
B cells CD79A, MS4A1
T cells CD3D
CD4+ T cells CD3D, IL7R, CCR7
CD8+ T cells CD3D, CD8A
NK cells GNLY, NKG7
Megakaryocytes PPBP
Erythrocytes HBB, HBA2
  • SingleR是一个用于单细胞RNA测序数据细胞类型注释的工具,使用已知的细胞类型基因表达模式来预测未知细胞类型。

  • CellMarker 2.0是人类和小鼠细胞类型标记物数据库,收集了已知细胞表面分子和转录因子的信息,并提供了细胞类型注释的参考。

  • Human Protein Atlas是一个用于人类蛋白组学的数据库,其中包含各种组织和细胞类型的蛋白质表达信息,可以用于细胞类型的注释。

这些marker数据库的注释可以通过基因名称、蛋白名称或细胞类型进行查询,以获取特定细胞类型的标记物。

The FeaturePlot() function from Seurat makes it easy to visualize a handful of genes using the gene IDs stored in the Seurat object. We can easily explore the expression of known gene markers on top of our UMAP visualizations. Let’s go through and determine the identities of the clusters.

Caution

The SCTransform normalization was performed only on the 3000 most variable genes, so many of our genes of interest may not be present in this data (见Seurat-运行SCTransform).

Warning

原教程中,由于采用了Seurat V5之前的工作流(如此前章节所述),所以为了准确可视化marker基因的表达情况,将默认的assay改回了“RNA”,然后运行NormalizeData

DefaultAssay(seurat_clustered) 
[1] "integrated"
# Select the RNA counts slot to be the default assay
DefaultAssay(seurat_clustered) <- "RNA"

# Normalize RNA data for visualization purposes
seurat_clustered <- NormalizeData(seurat_clustered, verbose = FALSE)

Assay is a slot defined in the Seurat object, it has multiple slots within it. In a given assay, the counts slot stores non-normalized raw counts, and the data slot stores normalized expression data. Therefore, when we run the NormalizeData() function in the above code, the normalized data will be stored in the data slot of the RNA assay while the counts slot will remain unaltered.

而在Seurat V5的官方教程中,经过了SCTransform之后绘制marker基因的表达情况时,并没有执行这一步,默认的assay仍然是“SCT”。这里为了和原教程的图像一致,所以也进行这一步。而对于以后的Seurat V5工作流考虑按照官方教程的做法。

Depending on our markers of interest, they could be positive or negative markers for a particular cell type. The combined expression of our chosen handful of markers should give us an idea on whether a cluster corresponds to that particular cell type.

For the markers used here, we are looking for positive markers and consistency of expression of the markers across the clusters. For example, if there are two markers for a cell type and only one of them is expressed in a cluster - then we cannot reliably assign that cluster to the cell type.

7.1 CD14+ monocyte markers

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("CD14", "LYZ"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

CD14+ monocytes appear to correspond to clusters 1, and 3. We wouldn’t include clusters 14 and 10 because they do not highly express both of these markers.

7.2 FCGR3A+ monocyte markers

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("FCGR3A", "MS4A7"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

FCGR3A+ monocytes markers distinctly highlight cluster 10, although we do see some decent expression in clusters 1 and 3. We would like to see additional markers for FCGR3A+ cells show up when we perform the marker identification.

7.3 Conventional dendritic cell markers

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("FCER1A", "CST3"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

The markers corresponding to conventional dendritic cells identify cluster 14 (both markers consistently show expression).

7.4 Plasmacytoid dendritic cell markers

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("IL3RA", "GZMB", "SERPINF1", "ITM2C"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

Plasmacytoid dendritic cells represent cluster 16. While there are a lot of differences in the expression of these markers, we see cluster 16 (though small) is consistently strongly expressed.

7.5 Macrophages

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("MARCO", "ITGAM", "ADGRE1"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

We don’t see much overlap of our markers, so no clusters appear to correspond to macrophages; perhaps cell culture conditions negatively selected for macrophages (more highly adherent).

7.6 B cells

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("CD79A", "MS4A1"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

可以看出,cluster 11, 7, 13属于B细胞。

7.7 T cells

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("CD3D"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

T细胞的标志物在大量的cluster中均表达,包括cluster 0, 2, 6, 4, 5, 9。

7.8 CD4+ T cells

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("CD3D", "IL7R", "CCR7"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

大致看出cluster 4, 0, 6, 2属于CD4+ T 细胞。

7.9 CD8+ T cells

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("CD3D", "CD8A"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

cluster 5和 cluster 9属于CD8+ T细胞。

7.10 NK cells

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("GNLY", "NKG7"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

cluster 8, 12属于NK细胞。这和我们在前面的 Section 6 中的结论(第二主成分的top基因GNLY和NKG7在cluster 8和cluster 12中高表达)一致。

7.11 Megakaryocytes(巨核细胞)

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("PPBP"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

cluster 15属于巨核细胞。

7.12 Erythrocytes(红细胞)

FeaturePlot(seurat_clustered, 
            reduction = "umap", 
            features = c("HBB", "HBA2"), 
            order = TRUE,
            min.cutoff = 'q10', 
            label = TRUE)

可以看到,红细胞的marker gene基本没有明显的表达。


8 细胞类型初步鉴定结果

根据上面的marker表达情况,我们大致可以确定如下细胞类型鉴定结果:

Cell Type Clusters
CD14+ monocytes 1, 3
FCGR3A+ monocytes 10
Conventional dendritic cells 14
Plasmacytoid dendritic cells 16
Marcrophages -
B cells 11, 7, 13
T cells 0, 2, 6, 4, 5, 9
CD4+ T cells 4, 0, 6, 2
CD8+ T cells 5, 9
NK cells 8, 12
Megakaryocytes 15
Erythrocytes -
Unknown -

Important

If any cluster appears to contain two separate cell types, it’s helpful to increase our clustering resolution to properly subset the clusters. Alternatively, if we still can’t separate out the clusters using increased resolution, then it’s possible that we had used too few principal components such that we are just not separating out these cell types of interest. To inform our choice of PCs, we could look at our PC gene expression overlapping the UMAP plots and determine whether our cell populations are separating by the PCs included.

Now we have a decent idea as to the cell types corresponding to the majority of the clusters, but some questions remain:

  1. T cell markers appear to be highly expressed in many clusters. How can we differentiate and subset the larger group into smaller subset of cells?
  2. Do the clusters corresponding to the same cell types have biologically meaningful differences? Are there subpopulations of these cell types?
  3. Can we acquire higher confidence in these cell type identities by identifying other marker genes for these clusters?

Marker identification analysis can help us address all of these questions!!

The next step will be to perform marker identification analysis, which will output the genes that significantly differ in expression between clusters. Using these genes we can determine or improve confidence in the identities of the clusters/subclusters.

9 保存数据

saveRDS(seurat_clustered, file = "output/scRNA-seq_online/seurat_clustered_qc.rds")

R version 4.3.2 (2023-10-31)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Sonoma 14.3

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.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: Asia/Shanghai
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] cowplot_1.1.2      ggplot2_3.4.4      purrr_1.0.2        tidyr_1.3.0       
[5] dplyr_1.1.4        Seurat_5.0.1       SeuratObject_5.0.1 sp_2.1-2          

loaded via a namespace (and not attached):
  [1] deldir_2.0-2           pbapply_1.7-2          gridExtra_2.3         
  [4] rlang_1.1.3            magrittr_2.0.3         RcppAnnoy_0.0.21      
  [7] spatstat.geom_3.2-7    matrixStats_1.2.0      ggridges_0.5.5        
 [10] compiler_4.3.2         png_0.1-8              vctrs_0.6.5           
 [13] reshape2_1.4.4         stringr_1.5.1          pkgconfig_2.0.3       
 [16] fastmap_1.1.1          ellipsis_0.3.2         labeling_0.4.3        
 [19] utf8_1.2.4             promises_1.2.1         rmarkdown_2.25        
 [22] xfun_0.41              jsonlite_1.8.8         goftest_1.2-3         
 [25] later_1.3.2            spatstat.utils_3.0-4   irlba_2.3.5.1         
 [28] parallel_4.3.2         cluster_2.1.6          R6_2.5.1              
 [31] ica_1.0-3              stringi_1.8.3          RColorBrewer_1.1-3    
 [34] spatstat.data_3.0-4    reticulate_1.34.0      parallelly_1.36.0     
 [37] lmtest_0.9-40          scattermore_1.2        Rcpp_1.0.12           
 [40] knitr_1.45             tensor_1.5             future.apply_1.11.1   
 [43] zoo_1.8-12             sctransform_0.4.1      httpuv_1.6.13         
 [46] Matrix_1.6-5           splines_4.3.2          igraph_1.6.0          
 [49] tidyselect_1.2.0       abind_1.4-5            rstudioapi_0.15.0     
 [52] yaml_2.3.8             spatstat.random_3.2-2  codetools_0.2-19      
 [55] miniUI_0.1.1.1         spatstat.explore_3.2-5 listenv_0.9.0         
 [58] lattice_0.22-5         tibble_3.2.1           plyr_1.8.9            
 [61] withr_3.0.0            shiny_1.8.0            ROCR_1.0-11           
 [64] evaluate_0.23          Rtsne_0.17             future_1.33.1         
 [67] fastDummies_1.7.3      survival_3.5-7         polyclip_1.10-6       
 [70] fitdistrplus_1.1-11    pillar_1.9.0           KernSmooth_2.23-22    
 [73] plotly_4.10.4          generics_0.1.3         RcppHNSW_0.5.0        
 [76] munsell_0.5.0          scales_1.3.0           globals_0.16.2        
 [79] xtable_1.8-4           glue_1.7.0             lazyeval_0.2.2        
 [82] tools_4.3.2            data.table_1.14.10     RSpectra_0.16-1       
 [85] RANN_2.6.1             leiden_0.4.3.1         dotCall64_1.1-1       
 [88] grid_4.3.2             colorspace_2.1-0       nlme_3.1-164          
 [91] patchwork_1.2.0        cli_3.6.2              spatstat.sparse_3.0-3 
 [94] spam_2.10-0            fansi_1.0.6            viridisLite_0.4.2     
 [97] uwot_0.1.16            gtable_0.3.4           digest_0.6.34         
[100] progressr_0.14.0       ggrepel_0.9.5          farver_2.1.1          
[103] htmlwidgets_1.6.4      htmltools_0.5.7        lifecycle_1.0.4       
[106] httr_1.4.7             mime_0.12              MASS_7.3-60.0.1