Objectives

We are reaching out a challenging task of the analysis (and a very exciting one !).

What types of cells did we capture in the analysis ? Do we identify the expected cell types and can we distinguish different sub-population ? Do we identify “novel”, “surprising” cell types ?

The aim of this session is to understand the different methods that will help you to explore the biological cell types captured by your dataset.

Overview of the scRNAseq pipeline

At this step of the analysis, we have :

  • a gene expression matrix : for each cell, gene expression is available

  • a reduced space : gene expression matrix is summarized in N dimensions

  • a clustering : each cell belongs to a specific cluster

  • a 2D space : cells can be visualized on a 2D representation

On the cell visualization, we also searched for clusters of cell. The clustering resolution show multiple cell clusters that we can now associate to cell types.

For this you need :

  • your biological knowledge on your dataset

  • an internet connection :)

Different methods to annotate cell types

The annotation methods aim at defining marker genes that help to identify the cell types in each cluster.

But the logic across methods is similar :

You identify genes or set of genes that have a pattern of expression specific and that represents a large number of cells for the cluster.

Different methods exist :

For this practical we will try both approaches. We use the dataset previously filtered and pre-processed (the Seurat object contains the 3 dimension reductions previously performed - pca, umap and harmony).

## Loading the Seurat object into the variable "sobj"
sobj = base::readRDS(
  file = "/shared/projects/2325_ebaii/SingleCell/Annotation/data/TD3A.TDCT_Scal2K.IntH20.Clust0.8.RDS")

## A quick overview of the object
sobj
## An object of class Seurat 
## 12926 features across 7709 samples within 1 assay 
## Active assay: RNA (12926 features, 2000 variable features)
##  3 layers present: counts, data, scale.data
##  3 dimensional reductions calculated: pca, harmony, umap

1 - Manual annotation using differential expression

Differential expression between clusters

One way to annotate the clusters of cell is to look at the genes highly expressed in one cluster of cells compared to all the other cells: we can do a differential expression (DE) analysis.

DE analysis is performed on the normalized count matrix (“data”).

In our case, the dataset is already Normalised (cf previous practicals).

# DO NOT RUN THIS CODE
# sobj = NormalizeData(sobj)
Seurat::DimPlot(object = sobj, 
                reduction = "umap", 
                group.by = "RNA_snn_res.0.8", #color cells with their cluster number
                pt.size = 2,
                label = TRUE,
                repel = TRUE
) + ggplot2::theme(legend.position = "bottom")

To perform the manual annotation, we will use Seurat and the function FindAllMarkers.

This function compare each cluster against all the other clusters to identify genes differentially expressed that are potentially marker genes.

We can now run the function FindAllMarkers()

# find markers for every cluster compared to all remaining cells, report only genes with positive DE 
all_markers = FindAllMarkers(object = sobj, 
                          only.pos = TRUE, # genes more expressed in the cluster compared
                          min.pct = 0.25, # % of cell expressing the marker
                          logfc.threshold = 0.25) 

# This command can take up to 2 mins

Time warning : this command takes a while to run if the number of cells and cluster is high.

Once the markers per cluster have been identify, we can look at the number of markers identified by cluster.

# Number of markers identified by cluster
table(all_markers$cluster)
## 
##    0    1    2    3    4    5    6    7    8    9   10   11   12   13 
##  148  131  275  310   34 1019   32  114  914  118  535  275  508  499

Here we see that many markers (ie deferentially expressed genes) have been identified. We cannot look at all of them, but we can choose to look at the top 3 markers per cluster and use our biological knowledge to identify cell populations.

# Save in a table 3 genes the most differentially expressed in one cluster VS all the other clusters
top3_markers = as.data.frame(all_markers %>% 
                               group_by(cluster) %>% 
                               top_n(n = 3, wt = avg_log2FC))
# Create a dotplot the vidualise the expression of genes by cluster
Seurat::DotPlot(sobj, features = unique(top3_markers$gene)) +
  # this second part of the code is just for esthetics :
  ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 90, 
                                                     vjust = 1,
                                                     size = 8, 
                                                     hjust = 1)) +
  Seurat::NoLegend()

On this plot we can see that some markers display a very high and specific expression one cluster.

Biology in this plot :

Let’s focus on 2 genes :

FeaturePlot(sobj, 
            features = c("Cd5", "Rag1"), 
            reduction = "umap"
            )

… at this moment using your biological knowledge on your dataset is critical, you can also test manually any marker of your choice !

Conclusion - Manual annotation :

  • Perform differential expression for each cluster VS all the others with a normalized matrix

  • Look at the gene expression of the markers identified in the 2D representation to validate specificity and representativness

  • Find the cell population corresponding to these markers and annotate this cluster

Advantages Limits
  • Easy to implement

  • Sometimes the only solution (ex : novel tissue)

  • Everything is possible

  • Clustering : resolution, merged clusters, “bio-informatic” cluster

  • Change clustering ? Change annotation…

  • Knowledge : time-consuming

2 - Automatic annotation using reference markers

For some tissues, the different cell types have already been largely described and databases exist with referenced marker genes. Another way to annotate your dataset will be to find a database with relevant annotation for your dataset and use tools of automatic annotation to annotate your clusters.

Let’s see how it works in practice !

We will use a database focused on immunological cell types called ImmGen, thanks to the celldex R package that “provides a collection of reference expression datasets with curated cell type labels, for use in procedures like automated annotation of single-cell data or deconvolution of bulk RNA-seq”

Note : In the following chunk code, you will load the annotation file from the IFB server where we downloaded it. In real life and with a version of dbdypr inf or equal to 2.3, you can also use this command :

annotation = ImmGenData(ensembl = FALSE) 
# ensembl set to TRUE if we want ENSEMBL ID gene names, FALSE will get the annotation with Gene Symbols
# Loading the ImmGen database
annotation = readRDS("/shared/projects/2325_ebaii/SingleCell/Annotation/data/ImmGenData.RDS")

## A quick description of the db
annotation
## class: SummarizedExperiment 
## dim: 22134 830 
## metadata(0):
## assays(1): logcounts
## rownames(22134): Zglp1 Vmn2r65 ... Tiparp Kdm1a
## rowData names(0):
## colnames(830):
##   GSM1136119_EA07068_260297_MOGENE-1_0-ST-V1_MF.11C-11B+.LU_1.CEL
##   GSM1136120_EA07068_260298_MOGENE-1_0-ST-V1_MF.11C-11B+.LU_2.CEL ...
##   GSM920654_EA07068_201214_MOGENE-1_0-ST-V1_TGD.VG4+24ALO.E17.TH_1.CEL
##   GSM920655_EA07068_201215_MOGENE-1_0-ST-V1_TGD.VG4+24ALO.E17.TH_2.CEL
## colData names(3): label.main label.fine label.ont

This database contains 3 levels of granularity :

As we are in a context of sorted cells of the same lineage, we’re going to use the fine label.

Let’s see how many cell types are described in this ImmGen database :

length(unique(annotation$label.fine))
## [1] 253

The tool we will use to perform the automatic cell type annotation, SingleR works better with the normalized data. Thus, we will extract the normalized matrix from our Seurat object :

# Extraction of the normanised data 
norm_exp_mat = Seurat::GetAssayData(
  object = sobj,
  assay = "RNA",
  slot = "data" #normalised count matrix
)
# We can check the caracteristics of this new object with dim() 
# dim() outputs the number of columns (cells) and rows (Cells)
dim(norm_exp_mat)
## [1] 12926  7709

We are ready to start the annotation.

The following command of SingleR performs the prediction of celltypes for each cell of the dataset.

# Run in ~ 1min
# This command uses performs the prediction of celltypes for each cell of the dataset
ann_predictions = SingleR::SingleR(
    test = norm_exp_mat, # use the normalised matrix
    ref = annotation, # use the annotation previously downloaded 
    labels = annotation$label.fine, # specify which annotation we use in annotation
    de.method="classic", # use marker dectection scheme 
    assay.type.test = "logcounts",
    assay.type.ref = "logcounts",
    BPPARAM = BiocParallel::SerialParam()
  )

The resulting object is a special kind of data.frame . Each row contains the ID of a cell and the prediction score associated by SingleR. Cell labels associated to each cell are stored in the column `$labels`

How many different kind of labels were identified ?

# Lenght of the list of labels => n of different cell types in our dataset
length(unique(ann_predictions$labels))
## [1] 45

Besides scoring, SingleR assesses the score quality, and prunes bad results.

How many cells got a poor quality annotation ?

# Print the number of cells with bad prediction scores (not labelled)
summary(is.na(ann_predictions$pruned.labels))
##    Mode   FALSE    TRUE 
## logical    7659      50

Annotation diagnostic

SingleR allows to visualize some control plots :

SingleR::plotScoreHeatmap(ann_predictions)
## Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE
## or useNames = TRUE.

## Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE
## or useNames = TRUE.

## Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE
## or useNames = TRUE.

How do you interpret this heatmap ?

Saving the annotation in your Seurat object

We add a column with the annotation for each cell to our Seurat object.

# Add the columns $labels of the prediction to the metadata of the single cell object
sobj$singler_cells_labels = ann_predictions$labels

Visualization of our annotation on UMAP

We can visualize cells annotation the the UMAP.

# The 4 lines under are just esthetics (set color palette to use)
seeable_palette = setNames(
  c(RColorBrewer::brewer.pal(name = "Dark2", n = 8),
    c(1:(length(unique(ann_predictions$labels)) - 8))),
  nm = names(sort(table(ann_predictions$labels), decreasing = TRUE)))

# UMAP with the predicted annotation by cell
ann_plot = Seurat::DimPlot(
  object = sobj, 
  reduction = "umap", 
  group.by = "singler_cells_labels", #we want to color cells by their annotation 
  pt.size = 2,
  cols = seeable_palette
) + ggplot2::theme(legend.position = "bottom")

# UMAP with the cluster numbers (before annotation)
clust_plot = Seurat::DimPlot(
  object = sobj, 
  reduction = "umap", 
  group.by = "RNA_snn_res.0.8", #color cells with their cluster number
  pt.size = 2,
  label = TRUE,
  repel = TRUE
)

print(ann_plot + clust_plot)

Maybe the annotation is not perfectly suited for our dataset. Some cell populations in the annotation are closely related, and this leads to annotation competition for our cells.

It is possible to run the annotation at the cluster level : it will be cleaner than the single cell level annotation. But, be sure that the clustering is not merging several cell populations.

We can check the number of cell attributed to labels from each cluster :

# Create a contingency table with in rows the cell labels and in columns the cluster numbers
table(sobj$singler_cells_labels,
      sobj$RNA_snn_res.0.8)
##                                         
##                                             0    1    2    3    4    5    6
##   DC (DC.8-4-11B-)                          0    0    0    0    0    0    0
##   DC (DC.PDC.8+)                            0    0    0    0    0    0    0
##   Macrophages (MF.103-11B+.SALM3)           0    0    0    0    0    0    0
##   Macrophages (MF.11CLOSER.SALM3)           0    0    0    0    0    0    0
##   NKT (NKT.44+NK1.1-)                       0    0    0    0    0    0    0
##   T cells (T.4.Pa)                          0    0    0    1    0    0    0
##   T cells (T.4.PLN)                         0    0    0    0    0    0    0
##   T cells (T.4FP3+25+)                      0    0    0    0    0    0    0
##   T cells (T.4Nve)                          0    0    0    0    0    0    0
##   T cells (T.4SP24-)                        0    0    0    0    0    0    0
##   T cells (T.4SP24int)                      0    0    0   25    0    0    0
##   T cells (T.8EFF.OT1.48HR.LISOVA)          0    0    0    0    0    0    0
##   T cells (T.8MEM.OT1.D45.LISOVA)           0    0    0    0    0    0    0
##   T cells (T.8Mem)                          0    0    0    0    0    0    0
##   T cells (T.8MEM)                          0    0    0    0    0    0    0
##   T cells (T.8MEMKLRG1-CD127+.D8.LISOVA)    0    0    0    0    0    0    0
##   T cells (T.8NVE.OT1)                      0    0    0    0    0    0    0
##   T cells (T.8Nve)                          1    0    0    1    0    0    0
##   T cells (T.8SP24-)                        0    0    0    0    0    0    0
##   T cells (T.8SP24int)                      0    0    0    2    0    1    0
##   T cells (T.8SP69+)                        0    0    0    3    0    0    0
##   T cells (T.CD4.5H)                        0    0    0   11    0    0    0
##   T cells (T.CD4TESTCJ)                     0    0    0    3    0    0    0
##   T cells (T.CD8.5H)                        0    0    0    1    0    0    0
##   T cells (T.CD8.CTR)                       0    0    0    0    0    0    0
##   T cells (T.DN2-3)                         0    0    2    0    0    0    0
##   T cells (T.DN2B)                          0    0    3    0    0    0    0
##   T cells (T.DN3-4)                         0    0    1    0    0    0    0
##   T cells (T.DN3A)                          0    2   87    0    0    0    0
##   T cells (T.DN3B)                          0    0    2    0    0    2    0
##   T cells (T.DN4)                           0    0    0    2    0    0    0
##   T cells (T.DP.69-)                        0    0    0    0    0    1    0
##   T cells (T.DP)                            0    0    0    0    0    1    0
##   T cells (T.DP69+)                         1    1    0  375    4    0    0
##   T cells (T.DPbl)                          0    0    0    0    0  124    0
##   T cells (T.DPsm)                       1929 1748  900  255  628    1  266
##   T cells (T.ISP)                           0    7    3    1    1  325    2
##   T cells (T.Tregs)                         0    0    0    0    0    0    0
##   Tgd (Tgd.imm.VG1+VD6+)                    0    0    0    3    0    0    0
##   Tgd (Tgd.imm.vg2)                         0    0    0    1    0    0    0
##   Tgd (Tgd.imm.vg2+)                        0    0    1    1    0    0    0
##   Tgd (Tgd.mat.VG1+VD6+)                    0    0    0    0    0    0    0
##   Tgd (Tgd.VG2+)                            0    0    0    0    0    0    0
##   Tgd (Tgd.VG5+24AHI)                       0    0    0    2    0    0    0
##   Tgd (Tgd)                                 0    0    1    0    0    0    0
##                                         
##                                             7    8    9   10   11   12   13
##   DC (DC.8-4-11B-)                          0    0    1    0    0    0    0
##   DC (DC.PDC.8+)                            0    0    1    0    0    0    0
##   Macrophages (MF.103-11B+.SALM3)           0    0    1    0    0    0    0
##   Macrophages (MF.11CLOSER.SALM3)           0    0    1    0    0    0    0
##   NKT (NKT.44+NK1.1-)                       0    0    0    1    0    0    0
##   T cells (T.4.Pa)                          0    0    0    0    0    0    0
##   T cells (T.4.PLN)                         0    0    0    1    0    0    0
##   T cells (T.4FP3+25+)                      0    0    0    2    0    0    0
##   T cells (T.4Nve)                          0    0    0    3    0    0    0
##   T cells (T.4SP24-)                        0    0    0    1    0    0    0
##   T cells (T.4SP24int)                      2    0    0    3    0    0    0
##   T cells (T.8EFF.OT1.48HR.LISOVA)          0    0    0    3    0    1    0
##   T cells (T.8MEM.OT1.D45.LISOVA)           0    0    0    1    0    0    0
##   T cells (T.8Mem)                          0    0    0    3    0    0    0
##   T cells (T.8MEM)                          0    0    0    2    0    0    0
##   T cells (T.8MEMKLRG1-CD127+.D8.LISOVA)    0    0    0    1    0    0    0
##   T cells (T.8NVE.OT1)                      0    0    0    5    0    0    0
##   T cells (T.8Nve)                          0    0    0   57    0    0    0
##   T cells (T.8SP24-)                        0    0    0   11    0    0    0
##   T cells (T.8SP24int)                      0    0    0    3    0    0    0
##   T cells (T.8SP69+)                        0    0    0   10    0    0    0
##   T cells (T.CD4.5H)                        0    0    0    0    0    0    0
##   T cells (T.CD4TESTCJ)                     0    0    0    4    0    0    0
##   T cells (T.CD8.5H)                        0    1    0    0    0    0    0
##   T cells (T.CD8.CTR)                       0    0    0    3    0    0    0
##   T cells (T.DN2-3)                         0    0    0    0    0    0    0
##   T cells (T.DN2B)                          0    0    0    0    0    0    0
##   T cells (T.DN3-4)                         0    0    0    0    0    0    0
##   T cells (T.DN3A)                          0    0    0    0    0    0    9
##   T cells (T.DN3B)                          0    4    0    0    0    1    5
##   T cells (T.DN4)                           0    1    0    0    0    0    0
##   T cells (T.DP.69-)                        0    0    0    0    0    0    0
##   T cells (T.DP)                            0    0    1    0    0    0    0
##   T cells (T.DP69+)                        10    0    2    0    0    0    0
##   T cells (T.DPbl)                          0    0    0    0    0   42    0
##   T cells (T.DPsm)                        247   30  133    8   76   38   53
##   T cells (T.ISP)                           1  138    0    0   25   16    5
##   T cells (T.Tregs)                         0    0    0    1    0    0    0
##   Tgd (Tgd.imm.VG1+VD6+)                    0    0    0    0    0    0    0
##   Tgd (Tgd.imm.vg2)                         0    0    0    0    0    0    0
##   Tgd (Tgd.imm.vg2+)                        0    0    0    0    0    0    0
##   Tgd (Tgd.mat.VG1+VD6+)                    0    0    0    1    0    0    0
##   Tgd (Tgd.VG2+)                            0    0    0    6    0    0    0
##   Tgd (Tgd.VG5+24AHI)                       0    0    0    0    0    0    0
##   Tgd (Tgd)                                 0    0    0    2    0    0    0

We can eventually check if some clusters contain multiple cell types. We compute the proportion of each cell type in each cluster. If a cluster is composed of two cell types (or more), maybe this resolution for the clustering is too low ?

# Compute the proportion of cell types per cluster
pop_by_cluster = prop.table(table(sobj$singler_cells_labels,
                                  sobj$RNA_snn_res.0.8),
                            margin = 2)
# Print number of cell types per cluster with >=30% from this cluster
colSums(pop_by_cluster > 0.3)
##  0  1  2  3  4  5  6  7  8  9 10 11 12 13 
##  1  1  1  2  1  1  1  1  1  1  1  1  2  1

Be aware of :

Cluster level annotation

We will now run the annotation at the cluster level (SingleR will summarize the expression profiles of all cells from the same cluster, and then assess the resulting aggregation) :

Note : we run the same command as before (SingleR), we only add the parameter “cluster” to SingleR function to annotate by cluster and not by cell.

# Rerun a prediction using clustering information 
clust_ann_predictions  =
    SingleR::SingleR(
    test = norm_exp_mat,
    clusters = sobj$RNA_snn_res.0.8,
    ref = annotation,
    labels = annotation$label.fine,
    assay.type.test = "logcounts",
    assay.type.ref = "logcounts",
    BPPARAM = BiocParallel::SerialParam()
  )

How many clusters have been labelled for each annotation label ?

head(sort(table(clust_ann_predictions$labels), decreasing = TRUE))
## 
##   T cells (T.DPsm)    T cells (T.ISP) T cells (T.8SP24-)     T cells (T.DP) 
##                  7                  3                  1                  1 
##  T cells (T.DP69+)   T cells (T.DPbl) 
##                  1                  1

For how many clusters was the annotation of poor quality ?

summary(is.na(clust_ann_predictions$pruned.labels))
##    Mode   FALSE    TRUE 
## logical      13       1

Annotation diagnostic

We can visualize the scores for each cell type, to each cell, as a heatmap :

# Heatmap using the annotation prediction by cluster
SingleR::plotScoreHeatmap(clust_ann_predictions)
## Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE
## or useNames = TRUE.

## Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE
## or useNames = TRUE.

## Warning: useNames = NA is deprecated. Instead, specify either useNames = TRUE
## or useNames = TRUE.

What do you observe here ? What is the difference with the annotation by cell ?

Add annotation to metadata

We add the annotation to our Seurat object.

# Save the name of future annotation
clust_labels_col = "singler_clust_labels"
# Create a column with this name in the metadata and fill it with the cluster levels of each cell
sobj@meta.data[[clust_labels_col]] = sobj@meta.data$RNA_snn_res.0.8
# Fill associate each cluster with its annotation 
levels(sobj@meta.data[[clust_labels_col]]) = clust_ann_predictions$labels

Visualization

We can visualize cells annotation the the 2D projection :

ann_cluster_plot = Seurat::DimPlot(
  object = sobj, 
  reduction = "umap", 
  group.by = clust_labels_col,
  pt.size = 2,
  label = FALSE, 
  cols = seeable_palette
) + ggplot2::theme(legend.position = "bottom")

ann_cell_plot = Seurat::DimPlot(
  object = sobj, 
  reduction = "umap", 
  group.by = "singler_cells_labels",
  pt.size = 2,
  label = FALSE,
  repel = TRUE, 
  cols = seeable_palette
) + ggplot2::theme(legend.position = "bottom")

ann_cluster_plot + ann_cell_plot

Save your Seurat object annotated

We save the annotated Seurat object :

# path <- "/shared/projects/<your_project>/<etc>/"
# base::saveRDS(
#   object = sobj,
#   file = paste0(path, "/Scaled_Normalized_Harmony_Clustering_Annotated_Seurat_Object.RDS")
# )

Conclusion - Automatic annotation using reference markers

  1. Find a good marker gene reference (PanglaoDB, CellMarker, CancerSEA…)

  2. Select a tool / model : classifier, scoring function … 

  3. Annotate your dataset

Advantages Limitations
  • Annotation for every single cell is possible

  • Design your own reference

  • Find the good reference markers

  • Cell types arborescence

  • Limited number of cell types : all cells are annotated, or “unknown” is possible ?

3 - Automatic annotation using a reference scRNAseq

Another possibility is to use a published single-cell dataset as a reference for the cluster annotation. Multiple tools exist to transfer the annotations on your own dataset.

We are not going to use this method today but you might want to use it for your practicals.

Here are the main command from Single R.

# # Load the reference packages from REF paper
# REF_SNRNASEQ = readRDS("reference_scRNAseq.RDS")

# # removing unlabelled libraries
# REF_SNRNASEQ = REF_SNRNASEQ[,!is.na(REF_SNRNASEQ$Cell.type)]

# #log normalise the library 
# REF_SNRNASEQ <- logNormCounts(REF_SNRNASEQ)

# # Create SingleCellExperiment object for your dataset 
# sx_sce = as.SingleCellExperiment(sx)

# # RUN SINGLE R 
# pred.grun = SingleR(test=sx_sce, 
#                     ref=REF_SNRNASEQ, # ref single cell data in "ref="
#                     labels=REF_SNRNASEQ$Cell.type.labels, 
#                     de.method="wilcox") # default method, you can choose others

Conclusion - Automatic annotation using a reference scRNAseq

  1. Find a good reference dataset : several bulk RNA-seq, one scRNA-seq…

  2. Select a tool to transfer annotation (SingleR, …)

  3. Annotate your dataset

Advantages Limitations
  • Single cell level

  • Design your own reference

  • Find the good reference dataset

  • Limited number of cell types (you can only find cell types present in the reference dataset)

Conclusion

Method Advantages Limitations
Manual cluster annotation using differential expression
  • Easy to implement

  • May be the only solution

  • Everything is possible

  • Clustering : resolution, merged clusters, “bio-informatic” cluster

  • Change clustering ? Change annotation…

  • Knowledge : time-consuming

Automatic annotation using reference markers
  • Single cell level is possible

  • Design your own reference

  • Find the good reference markers

  • Cell types arborescence

  • Limited number of cell types : all cells are annotated, or “unknown” ?

Automatic annotation using reference dataset
  • Single cell level

  • Design your own reference

  • Find the good reference dataset

  • Limited number of cell types : all cells are annotated, or “unknown” ?

A few advices :)

Note about automatic annotation :

If you are working with non model species or with multiple species : it is not trivial to transfert an annotation from one species to another. Genes markers are not always conserved across the evolution. In this case, manual annotation is a very important sanity check of any automatic annotation !!

References

Good practices for single cell analysis : https://www.sc-best-practices.org/preamble.html

Sanger Single cell course : https://www.singlecellcourse.org/index.html

SingleR : https://bioconductor.org/books/3.12/SingleRBook/

Ressources

For human :

GeneCard : https://www.genecards.org

Human Protein Atlas : https://www.proteinatlas.org/search/H2-K1

Session

sessionInfo()
## R version 4.2.3 (2023-03-15)
## Platform: x86_64-conda-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.6 LTS
## 
## Matrix products: default
## BLAS/LAPACK: /shared/ifbstor1/software/miniconda/envs/r-4.2.3/lib/libopenblasp-r0.3.21.so
## 
## 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       
## 
## attached base packages:
## [1] stats4    stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
##  [1] dplyr_1.1.3                 SeuratObject_5.0.0         
##  [3] Seurat_4.4.0                SingleR_2.0.0              
##  [5] SummarizedExperiment_1.28.0 Biobase_2.58.0             
##  [7] GenomicRanges_1.50.2        GenomeInfoDb_1.34.9        
##  [9] IRanges_2.32.0              S4Vectors_0.36.2           
## [11] BiocGenerics_0.44.0         MatrixGenerics_1.10.0      
## [13] matrixStats_1.0.0           ggplot2_3.4.4              
## 
## loaded via a namespace (and not attached):
##   [1] spam_2.10-0               plyr_1.8.9               
##   [3] igraph_1.5.1              lazyeval_0.2.2           
##   [5] sp_2.1-1                  splines_4.2.3            
##   [7] BiocParallel_1.32.6       listenv_0.9.0            
##   [9] scattermore_1.2           digest_0.6.33            
##  [11] htmltools_0.5.7           viridis_0.6.4            
##  [13] fansi_1.0.5               magrittr_2.0.3           
##  [15] ScaledMatrix_1.6.0        tensor_1.5               
##  [17] cluster_2.1.4             ROCR_1.0-11              
##  [19] limma_3.54.2              globals_0.16.2           
##  [21] spatstat.sparse_3.0-3     colorspace_2.1-0         
##  [23] ggrepel_0.9.4             xfun_0.41                
##  [25] RCurl_1.98-1.13           jsonlite_1.8.7           
##  [27] progressr_0.14.0          spatstat.data_3.0-3      
##  [29] survival_3.5-7            zoo_1.8-12               
##  [31] glue_1.6.2                polyclip_1.10-6          
##  [33] gtable_0.3.4              zlibbioc_1.44.0          
##  [35] XVector_0.38.0            leiden_0.4.3             
##  [37] DelayedArray_0.24.0       BiocSingular_1.14.0      
##  [39] future.apply_1.11.0       abind_1.4-5              
##  [41] scales_1.2.1              pheatmap_1.0.12          
##  [43] spatstat.random_3.2-1     miniUI_0.1.1.1           
##  [45] Rcpp_1.0.11               viridisLite_0.4.2        
##  [47] xtable_1.8-4              reticulate_1.34.0        
##  [49] rsvd_1.0.5                dotCall64_1.1-0          
##  [51] htmlwidgets_1.6.2         httr_1.4.7               
##  [53] RColorBrewer_1.1-3        ellipsis_0.3.2           
##  [55] ica_1.0-3                 farver_2.1.1             
##  [57] pkgconfig_2.0.3           uwot_0.1.16              
##  [59] sass_0.4.7                deldir_1.0-9             
##  [61] utf8_1.2.4                labeling_0.4.3           
##  [63] tidyselect_1.2.0          rlang_1.1.2              
##  [65] reshape2_1.4.4            later_1.3.1              
##  [67] munsell_0.5.0             tools_4.2.3              
##  [69] cachem_1.0.8              cli_3.6.1                
##  [71] generics_0.1.3            ggridges_0.5.4           
##  [73] evaluate_0.23             stringr_1.5.0            
##  [75] fastmap_1.1.1             goftest_1.2-3            
##  [77] yaml_2.3.7                knitr_1.45               
##  [79] fitdistrplus_1.1-11       purrr_1.0.2              
##  [81] RANN_2.6.1                nlme_3.1-163             
##  [83] pbapply_1.7-2             future_1.33.0            
##  [85] sparseMatrixStats_1.10.0  mime_0.12                
##  [87] compiler_4.2.3            rstudioapi_0.15.0        
##  [89] plotly_4.10.3             png_0.1-8                
##  [91] spatstat.utils_3.0-4      tibble_3.2.1             
##  [93] bslib_0.5.1               stringi_1.7.12           
##  [95] highr_0.10                lattice_0.22-5           
##  [97] Matrix_1.6-1.1            vctrs_0.6.4              
##  [99] pillar_1.9.0              lifecycle_1.0.3          
## [101] spatstat.geom_3.2-7       lmtest_0.9-40            
## [103] jquerylib_0.1.4           RcppAnnoy_0.0.21         
## [105] data.table_1.14.8         cowplot_1.1.1            
## [107] bitops_1.0-7              irlba_2.3.5.1            
## [109] httpuv_1.6.12             patchwork_1.1.3          
## [111] R6_2.5.1                  promises_1.2.1           
## [113] KernSmooth_2.23-22        gridExtra_2.3            
## [115] parallelly_1.36.0         codetools_0.2-19         
## [117] MASS_7.3-60               withr_2.5.2              
## [119] sctransform_0.4.1         GenomeInfoDbData_1.2.9   
## [121] parallel_4.2.3            grid_4.2.3               
## [123] beachmat_2.14.2           tidyr_1.3.0              
## [125] rmarkdown_2.25            DelayedMatrixStats_1.20.0
## [127] Rtsne_0.16                spatstat.explore_3.2-5   
## [129] shiny_1.7.5.1