
SlimR is an R package for cell-type annotation in single-cell and spatial transcriptomics. Existing marker-based annotation methods typically rely on manually tuned thresholds and operate at a single analytical granularity, limiting their adaptability across diverse datasets. SlimR addresses these challenges through three methodological contributions: (1) a context-matching framework that standardizes heterogeneous marker sources via multi-level biological filtering; (2) a dataset-adaptive parameterization strategy that infers optimal annotation hyperparameters from intrinsic data characteristics, eliminating manual calibration; and (3) a dual-granularity scoring architecture that provides both cluster-level probabilistic assignment and per-cell resolution with manifold-aware spatial smoothing for continuous cell states. A unified Feature Significance Score ensures biologically interpretable marker ranking throughout the workflow.
install.packages("SlimR")devtools::install_github("zhaoqing-wang/SlimR")Required: R (≥ 3.5), cowplot, dplyr, ggplot2, patchwork, pheatmap, readxl, scales, Seurat, tidyr, tools
install.packages(c("cowplot", "dplyr", "ggplot2", "patchwork",
"pheatmap", "readxl", "scales", "Seurat",
"tidyr", "tools"))Optional: RANN (10–100× faster UMAP spatial smoothing in per-cell annotation)
install.packages("RANN")library(SlimR)
# For Seurat objects with multiple layers, join layers first
sce@assays$RNA <- SeuratObject::JoinLayers(sce@assays$RNA)Important: Ensure your Seurat object has completed standard preprocessing (normalization, scaling, clustering) and batch effect correction.
SlimR uses a standardized list format: list names = cell types, first column = marker genes, additional columns = metrics (optional).
Reference: Hu et al. (2023) doi:10.1093/nar/gkac947
Cellmarker2 <- SlimR::Cellmarker2
Markers_list_Cellmarker2 <- Markers_filter_Cellmarker2(
Cellmarker2,
species = "Human",
tissue_class = "Intestine",
tissue_type = NULL,
cancer_type = NULL,
cell_type = NULL
)Important: Specify at least species and
tissue_class for accurate annotations.
Cellmarker2_table <- SlimR::Cellmarker2_table
View(Cellmarker2_table)Reference: Franzén et al. (2019) doi:10.1093/database/baz046
PanglaoDB <- SlimR::PanglaoDB
Markers_list_panglaoDB <- Markers_filter_PanglaoDB(
PanglaoDB,
species_input = 'Human',
organ_input = 'GI tract'
)PanglaoDB_table <- SlimR::PanglaoDB_table
View(PanglaoDB_table)Reference: Ianevski et al. (2022) doi:10.1038/s41467-022-28803-w
ScType <- SlimR::ScType
Markers_list_ScType <- Markers_filter_ScType(
ScType,
tissue_type = "Intestine",
cell_name = NULL
)Important: Specify tissue_type for accurate
annotations.
ScType_table <- SlimR::ScType_table
View(ScType_table)seurat_markers <- Seurat::FindAllMarkers(
object = sce,
group.by = "Cell_type",
only.pos = TRUE)
Markers_list_Seurat <- Read_seurat_markers(seurat_markers,
sources = "Seurat",
sort_by = "FSS",
gene_filter = 20
)Tip: sort_by = "FSS" ranks by Feature Significance
Score (log2FC × Expression ratio). Use
sort_by = "avg_log2FC" for fold-change ranking.
seurat_markers <- dplyr::filter(
presto::wilcoxauc(
X = sce,
group_by = "Cell_type",
seurat_assay = "RNA"
),
padj < 0.05, logFC > 0.5
)
Markers_list_Seurat <- Read_seurat_markers(seurat_markers,
sources = "presto",
sort_by = "FSS",
gene_filter = 20
)Install presto:
devtools::install_github('immunogenomics/presto')
Format: Each sheet name = cell type, first row = headers, first column = markers, subsequent columns = metrics (optional).
Markers_list_Excel <- Read_excel_markers("D:/Laboratory/Marker_load.xlsx")If your Excel file lacks column headers, set
has_colnames = FALSE.
SlimR includes curated marker lists for specific annotation tasks:
| List | Scope | Reference |
|---|---|---|
Markers_list_scIBD |
Human intestinal cells (IBD) | Nie et al. (2023) doi:10.1038/s43588-023-00464-9 |
Markers_list_TCellSI |
T cell subtypes | Yang et al. (2024) doi:10.1002/imt2.231 |
Markers_list_PCTIT |
Pan-cancer T cell subtypes | L. Zheng et al. (2021) doi:10.1126/science.abe6474 |
Markers_list_PCTAM |
Pan-cancer macrophage subtypes | Ruo-Yu Ma et al. (2022) doi:10.1016/j.it.2022.04.008 |
# Example: Load built-in markers
Markers_list <- SlimR::Markers_list_scIBDImportant: Ensure your input Seurat object matches the tissue/cell type scope of the selected marker list.
SlimR provides two automated approaches:
Cluster-Based (one label per cluster, fast) and
Per-Cell (individual cell labels, finer resolution).
Both share the same parameter calculation step and
Markers_list format.
| Feature | Cluster-Based | Per-Cell |
|---|---|---|
| Unit | Cluster | Individual cell |
| Speed | ~10–30s (50k cells) | ~2–3min (50k cells) |
| Resolution | Coarse | Fine |
| Best For | Homogeneous clusters | Mixed clusters, rare cell types |
| Spatial Context | Not used | Optional (UMAP smoothing) |
SlimR uses adaptive machine learning to determine optimal
min_expression, specificity_weight, and
threshold parameters. This step is optional — skip
to Section 3.2 to use defaults.
SlimR_params <- Parameter_Calculate(
seurat_obj = sce,
features = c("CD3E", "CD4", "CD8A"),
assay = "RNA",
cluster_col = "seurat_clusters",
verbose = TRUE
)SlimR_params <- Parameter_Calculate(
seurat_obj = sce,
features = unique(Markers_list_Cellmarker2$`B cell`$marker),
assay = "RNA",
cluster_col = "seurat_clusters",
verbose = TRUE
)Three steps: Calculate → Annotate → Verify.
Step 1: Calculate Cell Types
SlimR_anno_result <- Celltype_Calculate(seurat_obj = sce,
gene_list = Markers_list,
species = "Human",
cluster_col = "seurat_clusters",
assay = "RNA",
min_expression = 0.1,
specificity_weight = 3,
threshold = 0.6,
compute_AUC = TRUE,
plot_AUC = TRUE,
AUC_correction = TRUE,
colour_low = "navy",
colour_high = "firebrick3"
)If you ran Parameter_Calculate(), use:
min_expression = SlimR_params$min_expression,
specificity_weight = SlimR_params$specificity_weight,
threshold = SlimR_params$threshold.
# View heatmap, predictions, and ROC curves
print(SlimR_anno_result$Heatmap_plot)
View(SlimR_anno_result$Prediction_results)
print(SlimR_anno_result$AUC_plot) # Requires plot_AUC = TRUE
# Manually correct predictions
SlimR_anno_result$Prediction_results$Predicted_cell_type[
SlimR_anno_result$Prediction_results$cluster_col == 15
] <- "Intestinal stem cell"
# Label low-confidence predictions as Unknown
SlimR_anno_result$Prediction_results$Predicted_cell_type[
SlimR_anno_result$Prediction_results$AUC <= 0.5
] <- "Unknown"When correcting, preferably use cell types from the
Alternative_cell_types column.
Step 2: Annotate Cell Types
sce <- Celltype_Annotation(seurat_obj = sce,
cluster_col = "seurat_clusters",
SlimR_anno_result = SlimR_anno_result,
plot_UMAP = TRUE,
annotation_col = "Cell_type_SlimR"
)Step 3: Verify Cell Types
Celltype_Verification(seurat_obj = sce,
SlimR_anno_result = SlimR_anno_result,
gene_number = 5,
assay = "RNA",
colour_low = "white",
colour_high = "navy",
annotation_col = "Cell_type_SlimR"
)Important: Use matching cluster_col and
annotation_col values across all three
functions.
Three steps: Calculate → Annotate → Verify. Ideal for heterogeneous clusters, rare cell types, and continuous differentiation states.
Step 1: Calculate Per-Cell Types
SlimR_percell_result <- Celltype_Calculate_PerCell(
seurat_obj = sce,
gene_list = Markers_list,
species = "Human",
assay = "RNA",
method = "weighted",
min_expression = 0.1,
use_umap_smoothing = FALSE,
min_score = "auto",
min_confidence = 1.2,
verbose = TRUE
)Three scoring methods: "weighted" (default,
recommended), "mean" (fast baseline), "AUCell"
(rank-based, robust to batch effects).
# Enable UMAP smoothing for noise reduction
SlimR_percell_result <- Celltype_Calculate_PerCell(
seurat_obj = sce,
gene_list = Markers_list,
species = "Human",
method = "weighted",
use_umap_smoothing = TRUE,
k_neighbors = 20,
smoothing_weight = 0.3
)Install RANN for 10–100× faster k-NN:
install.packages("RANN")
| Scenario | min_score |
min_confidence |
|---|---|---|
| Few cell types (<15) | "auto" |
1.2 (default) |
| Many cell types (>30) | "auto" |
1.1–1.15 |
| Strict annotation | "auto" |
1.3–1.5 |
| Liberal annotation | "auto" |
1.0 (disable) |
Step 2: Annotate Per-Cell Types
sce <- Celltype_Annotation_PerCell(
seurat_obj = sce,
SlimR_percell_result = SlimR_percell_result,
plot_UMAP = TRUE,
annotation_col = "Cell_type_PerCell_SlimR",
plot_confidence = TRUE
)Step 3: Verify Per-Cell Types
Celltype_Verification_PerCell(
seurat_obj = sce,
SlimR_percell_result = SlimR_percell_result,
gene_number = 5,
assay = "RNA",
colour_low = "white",
colour_high = "navy",
annotation_col = "Cell_type_PerCell_SlimR",
min_cells = 10
)Important: Use matching annotation_col values in
Celltype_Annotation_PerCell() and
Celltype_Verification_PerCell().
For expert-guided manual annotation using visualizations:
Celltype_Annotation_Heatmap(
seurat_obj = sce,
gene_list = Markers_list,
species = "Human",
cluster_col = "seurat_cluster",
min_expression = 0.1,
specificity_weight = 3,
colour_low = "navy",
colour_high = "firebrick3"
)Note: This function is now incorporated into
Celltype_Calculate(). Use Celltype_Calculate()
instead for automated workflows.
Generates per-cell-type expression dot plot with metric heat map:
Celltype_Annotation_Features(
seurat_obj = sce,
cluster_col = "seurat_clusters",
gene_list = Markers_list,
gene_list_type = "Cellmarker2",
species = "Human",
save_path = "./SlimR/Celltype_Annotation_Features/",
colour_low = "white",
colour_high = "navy",
colour_low_mertic = "white",
colour_high_mertic = "navy"
)Set gene_list_type to "Cellmarker2",
"PanglaoDB", "Seurat", or "Excel"
to match your marker source.
Generates per-cell-type box plots of marker expression levels:
Celltype_Annotation_Combined(
seurat_obj = sce,
gene_list = Markers_list,
species = "Human",
cluster_col = "seurat_cluster",
assay = "RNA",
save_path = "./SlimR/Celltype_Annotation_Combined/",
colour_low = "white",
colour_high = "navy"
)Cross‑tabulate cell type labels from one Seurat object with a grouping column from another Seurat object. The function automatically aligns cell barcodes using multiple normalization strategies and returns count tables, column‑wise proportion tables, a dominant mapping, and a heatmap.
result <- Celltype_Compare(
sce_label = seurat_obj1,
sce = seurat_obj2,
label_col = "cell_type",
group_col = "cluster"
)
# Access results
head(result$prop_table) # column-wise proportions
print(result$plot) # heatmap of proportions
result$main_to_sub # dominant cell type per groupQuickly assess the discriminative power of a single gene for a user‑defined cell group. The function returns the AUC, ROC data for custom plotting, and an optional ggplot2 curve.
result <- Compute_Gene_AUC_ROC(
seurat_obj = sce,
gene = "CD3D",
group_col = "Cell Types",
group_label = "T cells",
assay = "RNA",
method = "rank",
plot = TRUE,
line_color = "navy",
line_size = 1
)
# Access results
result$AUC # numeric AUC value
head(result$roc_data) # data.frame with fpr and tpr
result$roc_plot # ggplot object (when plot = TRUE)method: "raw" (raw expression, optionally
truncated by min_expression) or "rank"
(dropout‑robust rank‑based scores).min_expression: when method = "raw",
values below this are set to zero.keep_expression_above: optional threshold – keep only
cells with expression above it. Warning: this shifts
the AUC interpretation to “discrimination among expressing cells” and
should be compared with the default all‑cell result.plot, plot_title, line_color,
line_size: control the ROC plot appearance.以下是优化后的 README 5.3、5.4 节以及新增的 5.5 节。主要改动:
paletteDiscrete,详细介绍内置调色板,注明文献引用、官网、GitHub、MIT
许可证,并给出简单示例。### 5.3 Hierarchical Proportion Plot
Create a publication‑ready composite figure that visualises the hierarchical classification of single‑cell data from broad cell types down to fine sub‑types.
The **upper panel** draws a layered tree diagram (bubble size ∝ cell count, parent‑child links shown as three‑segment step lines). The **lower panel** (optional) displays per‑group cell‑type proportions as a heatmap perfectly aligned with the terminal leaves.
```r
# Full three-level hierarchy with proportion heatmap
res <- Plot_Hierarchy_Proportion(
seurat_obj = sce,
Main_cell_types = "Main_type",
Cell_types = "Cell_type",
Sub_cell_types = "Sub_type",
proportion = TRUE,
Groups = "orig.ident",
low_col = "white",
high_col = "navy"
)
# Access individual plot components
res$tree_plot # ggplot object – tree including labels & short sticks
res$prop_plot # ggplot object – proportion heatmap
res$combined_plot # combined plot (requires patchwork)Hierarchy levels
Main_cell_types, Cell_types,
Sub_cell_types are character strings naming columns in
seurat_obj@meta.data.
Use NULL to omit a level. If Sub_cell_types is
given, Cell_types must also be provided.
Category names (e.g. “T cell”) must be unique within each
level (they can repeat across levels).
Partial sub‑clustering
It is common that only a subset of cells receives a finer annotation
(e.g., only T cells are split into subtypes). The function automatically
handles this: a cell without a valid sub‑label becomes a leaf at the
deepest level where it has a label. The proportion heatmap is then built
from the union of all terminal leaf labels – so no
population is lost.
Label placement & adaptive height
Leaf labels are drawn directly below the terminal nodes inside the tree
panel, rotated 90°, with short black sticks connecting nodes to labels.
The tree panel’s lower limit automatically expands to accommodate the
longest cell‑type name – no label is ever clipped, and the heatmap sits
immediately beneath the labels.
Colour control
col_Main_cell_types, col_Cell_types,
col_Sub_cell_types accept named or unnamed colour vectors.
When missing, the function generates a palette using the internal
paletteDiscrete() function, which replicates the
stallion palette from the ArchR package. No
external ArchR installation is required.
Proportion heatmap
proportion = TRUE (default) adds a lower panel showing the
fraction of each terminal cell type per group (column
Groups).
Groups is required only when
proportion = TRUE. The heatmap uses the same leaf order as
the tree, has a tight black border, and uses a white‑to‑red colour
gradient (customisable via low_col and
high_col). Group labels are shown in bold
on the y‑axis.
Non‑leaf annotations
show_labels = TRUE (default) places italic text next to
non‑leaf Main and Cell level nodes, helping identify broad categories at
a glance.
Output
The function returns a list with tree_plot,
prop_plot (NULL if proportion = FALSE), and
combined_plot (NULL unless patchwork is
installed). All are ggplot2 objects that can be further
customised. The combined plot is automatically printed to the active
graphics device.
Generate a weighted Voronoi treemap that visualizes the hierarchical composition of single‑cell data. Polygons are grouped by the main cell type, and the area of each sub‑type polygon is proportional to its cell count. Colours follow the same palette logic as other SlimR functions, derived from ArchR but fully built into the package.
The plot is drawn using a custom ggplot2‑based renderer
to ensure exact colour matching with
Plot_Hierarchy_Proportion and DimPlot,
bypassing the limited colour handling of the upstream
WeightedTreemaps package.
# Basic treemap with rounded rectangles, displaying both count and percentage
res <- Plot_Voronoi_diagram(
seurat_obj = sce,
Main_cell_types = "Main_type",
Cell_types = "Cell_type",
label_type = "both",
shape = "rounded_rect",
seed = 1
)
# Access the underlying treemap object or the final ggplot
res$voronoi_treemap # the treemap object from WeightedTreemaps
res$plot # the ggplot objectData & hierarchy
Main_cell_types and Cell_types are column
names in seurat_obj@meta.data defining the two‑level
hierarchy.
Only cells with valid (non‑missing, non‑empty) labels in both columns
are used.
The voronoi diagram groups cells by main type (level 1) and further
splits each main type into sub‑type polygons (level 2).
Polygon labels (label_type)
Controls the text displayed inside each sub‑type polygon:
"both" (default) – shows the sub‑type name, cell count,
and percentage of total cells (each on a new line)."count" – shows sub‑type name and cell count."percentage" – shows sub‑type name and percentage of
total cells."none" – shows only the sub‑type name.Polygon shape (shape)
"rounded_rect" (default) produces rounded rectangles;
"circle" yields circular polygons.
The layout is non‑deterministic but can be made reproducible via the
seed parameter.
Reproducibility (seed)
A single integer passed to the Voronoi layout algorithm. The same seed
yields the same polygon arrangement across runs.
Colour control
(col_Cell_types)
Accepts a named or unnamed character vector of colours for the
Cell_types categories. If NULL, colours are
automatically generated via the internal paletteDiscrete()
function (replicates the ArchR stallion palette). No external
ArchR installation is needed.
Label appearance
label_size controls the text size inside polygons (default
3).
label_color sets the text colour (default
"black").
label_fontface controls the font face
("plain", "italic", "bold";
default "bold").
Borders and frames
The function draws three types of borders:
subtype_border_lwd,
default 0.15) – thin lines between individual sub‑type
polygons.main_border_lwd, default
0.35) – thicker lines between main cell type regions, drawn
on top of sub‑type borders for clear separation.outer_border_lwd, default
0.4) – a convex hull tightly surrounding the entire plot,
following the natural outline of the treemap. All borders share the same
border_color (default "grey90", a very light
grey). This parameter can be customised to any valid R colour.Legend
legend = TRUE (default) shows a colour legend;
legend_position controls its placement (default
"right", also accepts "left",
"bottom", "top", or
"none").
Output
The function invisibly returns a list with two components:
voronoi_treemap: the raw voronoiTreemap
object from WeightedTreemaps, containing polygon
coordinates and metadata.plot: the final ggplot object, produced by
a custom drawing routine that extracts polygon vertices and applies
colours via scale_fill_manual(). The plot is automatically
printed to the active graphics device.Dependencies
Requires the WeightedTreemaps package, available from
GitHub. If not installed, an error is thrown with installation
instructions.
The function only uses WeightedTreemaps::voronoiTreemap()
to compute polygon layouts; all rendering is done with
ggplot2.
SlimR provides an internal function paletteDiscrete()
that reproduces the colour palettes from the ArchR
package.
These palettes, including the default stallion, are hard‑coded
in the package and do not require an external ArchR
installation.
Usage
You can call the palette generator directly:
# Generate colours for a set of categories
cols <- paletteDiscrete(c("B cells", "T cells", "NK cells"))
print(cols)
# Custom set (e.g., "kelly")
cols <- paletteDiscrete(c("B cells", "T cells", "NK cells"), set = "kelly")The function returns a named vector of hex colours, sorted naturally (e.g., “NK cells” before “T cells”). When the number of categories exceeds the palette size, colours are interpolated smoothly.
All SlimR plotting functions that accept col_...
parameters automatically use this palette when no custom colours are
supplied, ensuring a consistent and publication‑ready colour scheme
across different types of plots.
The palettes are derived from ArchR, a scalable software package for integrative single‑cell chromatin accessibility analysis:
License
ArchR is distributed under the MIT License. SlimR
respects the original license by including the palette data directly and
documenting its provenance.
Wang Z (2026). SlimR: Adaptive Machine Learning-Powered, Context-Matching Tool for Single-Cell and Spatial Transcriptomics Annotation.
https://github.com/zhaoqing-wang/SlimR
Author: Zhaoqing Wang (ORCID) | Email: zhaoqingwang@mail.sdu.edu.cn | Issues: SlimR Issues