Annotates single-cell and spatial-transcriptomic (ST) data using context-matching marker datasets. It creates a unified marker list (`Markers_list`) from multiple sources: built-in curated databases ('Cellmarker2', 'PanglaoDB', 'ScType', 'CellTypist', 'scBaseCount', 'scIBD', 'TCellSI', 'PCTIT', 'PCTAM'), Seurat objects with cell labels, or user-provided Excel tables. SlimR first uses adaptive machine learning for parameter optimization, and then offers two automated annotation approaches: 'cluster-based' and 'per-cell'. Cluster-based annotation assigns one label per cluster, expression-based probability calculation, and AUC validation. Per-cell annotation assigns labels to individual cells using three scoring methods with adaptive thresholds and ratio-based confidence filtering, plus optional UMAP spatial smoothing, making it ideal for heterogeneous clusters and rare cell types. The package also supports semi-automated workflows with heatmaps, feature plots, and combined visualizations for manual annotation. For more information, see the package documentation at < https://github.com/zhaoqing-wang/SlimR>.
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
CellMarker 2.0 is a manually curated repository of experimentally supported markers across human and mouse, encompassing 26,915 markers, 2,578 cell types, and 656 tissues (83,361 tissue–cell type–marker entries). It also includes marker information from 48 sequencing technology sources (e.g., 10X Chromium, Smart‑Seq2, Drop‑seq) and 29 types of cell markers (protein‑coding genes, lncRNAs, processed pseudogenes, etc.). SlimR integrates the full dataset and provides flexible filtering to generate custom marker lists.
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 is a public database of 1,368 single‑cell experiments (covering most major platforms) with >5 million cells from human and mouse tissues. It includes a community‑curated marker compendium of >8,000 gene–cell‑type associations. SlimR integrates this marker compendium, allowing filtering by species and organ.
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 provides a comprehensive marker database organised by tissue type (e.g., Immune system, Brain) and cell name, enabling data‑driven annotation using positive and negative markers. SlimR includes the full ScType marker collection for automated cell‑type identification.
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)
Reference:
Xu et al. (2023) doi:10.1016/j.cell.2023.11.026
Domínguez Conde et al. (2022) doi:10.1126/science.abl5197
SlimR provides a pre‑computed marker list derived from the CellTypist organ atlas. It covers 12 human organs (Blood, Bone_marrow, Heart, Hippocampus, Intestine, Kidney, Liver, Lung, Lymph_node, Pancreas, Skeletal_muscle, Spleen) and 399 cell types, with markers obtained via the Scanpy workflow (Section 2.6: log1p‑normalised data, Wilcoxon test, adjusted p‑value < 0.01, log2 fold‑change > 0, then ranked by log fold‑change; top 100 genes per cell type). The data have been imported using Read_excel_markers and are directly usable.
# Load the built-in list
CellTypist <- SlimR::CellTypist
# Access markers for one organ (e.g., Intestine)
Markers_list_CellTypist <- CellTypist$Intestine
# Each organ contains a named list of data frames (one per cell type)
names(Markers_list_CellTypist)
# The data frames are pre‑sorted by log fold‑change (descending).
# To restrict to the top 20 markers for every cell type in this organ:
Markers_list_CellTypist_top20 <- lapply(Markers_list_CellTypist, function(df) head(df, 20))
Key points:
$organ_name to extract an organ; the organ names are exactly as shown above (case‑sensitive).logfoldchanges (descending) – simply use head(df, n) to obtain the top n markers.Markers_list object.Reference: Youngblut et al. (2026) doi:10.1016/j.cell.2026.08.025
scBaseCount provides cross-species marker gene sets derived from over 500 million cells. SlimR includes four species-specific lists—human, mouse, zebrafish, and Drosophila—where each list contains cell type–marker gene sets ready for annotation.
scBaseCount <- SlimR::scBaseCount
Markers_list_scBaseCount_human <- scBaseCount$human_gene_sets
Markers_list_scBaseCount_mouse <- scBaseCount$mouse_gene_sets
Markers_list_scBaseCount_fly <- scBaseCount$fly_gene_sets
Markers_list_scBaseCount_zebrafish <- scBaseCount$zebrafish_gene_sets
Important: Select the species-specific list matching your data.
names(SlimR::scBaseCount)
# [1] "human_gene_sets" "mouse_gene_sets"
# [3] "fly_gene_sets" "zebrafish_gene_sets"
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.
Important: To avoid long running time, for data with more than 100,000 cells, it is recommended to use scanpy for DEGs calculation (Section 2.6).
Differential expression results from a Scanpy AnnData object can be exported to an Excel file and then loaded directly into SlimR’s standard format using Read_excel_markers.
import scanpy as sc
import pandas as pd
import numpy as np
from openpyxl import Workbook
from openpyxl.utils.dataframe import dataframe_to_rows
import re
# Load data
adata = sc.read_h5ad("adata.h5ad")
# ------------------------------------------------------------
# Ensure expression data is log1p‑normalised.
# If adata.X contains raw counts, normalise and log1p now:
# sc.pp.normalize_total(adata, target_sum=1e4)
# sc.pp.log1p(adata)
#
# If raw counts are in a layer (e.g., 'counts'), move them to .X first:
# adata.X = adata.layers['counts'].copy()
# sc.pp.normalize_total(adata, target_sum=1e4)
# sc.pp.log1p(adata)
#
# If .X already contains log1p data, you can skip the step above.
# ------------------------------------------------------------
# Cluster column (adjust to your metadata column name)
cluster_key = "Curated_annotation"
adata.obs[cluster_key] = adata.obs[cluster_key].astype("category")
clusters = adata.obs[cluster_key].cat.categories
# Wilcoxon test (one‑vs‑rest)
sc.tl.rank_genes_groups(adata, groupby=cluster_key,
method="wilcoxon", n_jobs=-1)
# Collect filtered results per cluster
de_dict = {}
for clust in clusters:
df = sc.get.rank_genes_groups_df(adata, group=clust)
df = df[(df["pvals_adj"] < 0.01) & (df["logfoldchanges"] > 0)]
df = df.sort_values("logfoldchanges", ascending=False).head(100)
df = df.rename(columns={"names": "gene"})
# Round numeric columns for cleaner output
for col in df.select_dtypes(include=[np.number]).columns:
df[col] = df[col].round(4)
de_dict[clust] = df
# Write to Excel (one sheet per cluster)
def sanitize_sheet_name(name):
return re.sub(r'[\[\]:*?/\\]', '_', str(name))[:31]
wb = Workbook()
wb.remove(wb.active)
for clust in clusters:
ws = wb.create_sheet(title=sanitize_sheet_name(clust))
for row in dataframe_to_rows(de_dict[clust], index=False, header=True):
ws.append(row)
wb.save("DEGs.xlsx")
Important:
.X still holds raw counts, normalise (e.g., normalize_total + log1p) before calling rank_genes_groups.groupby to your actual annotation column (e.g., "Cell_type", "leiden").pvals_adj), fold‑change direction, and number of genes (head(100)) to suit your analysis.After saving the DEGs.xlsx file, use the Read_excel_markers function from Section 2.7 to import it into R.
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_scIBD <- SlimR::Markers_list_scIBD
# The data frames are pre‑sorted by log fold‑change (descending).
# To restrict to the top 20 markers for every cell type in this organ:
Markers_list_scIBD_top20 <- lapply(Markers_list_scIBD, function(df) head(df, 20))
Important: 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"
)
seurat_obj: Seurat object containing annotation columns (e.g., seurat_cluster) in meta.data.gene_list: A named list of markers, where each element is a data frame with marker genes in the first column. Can be generated by Markers_filter_Cellmarker2(), Markers_filter_PanglaoDB(), read_excel_markers(), or read_seurat_markers().species: "Human" or "Mouse" – used for standardising gene symbols in the marker list.cluster_col: Column name in meta.data that defines clusters (default: "seurat_clusters").assay: Assay to use (default: "RNA").min_expression: Threshold for considering a gene “expressed” in a cell; low‑expression cells are filtered to reduce noise (default: 0.1).specificity_weight: Controls how much expression variability (standard deviation) within a cluster contributes to the specificity score; higher values amplify variability (default: 3).threshold: Normalised similarity threshold between the alternative and predicted cell types; used for filtering uncertain assignments (default: 0.6).compute_AUC: If TRUE, calculates AUC values for each predicted cell type to measure marker discriminative power (default: TRUE).plot_AUC: If TRUE, generates an ROC curve plot for the predicted cell types (default: TRUE).AUC_correction: If TRUE, uses the highest‑AUC cell type among candidates (probability > threshold) as the final prediction, and records its AUC in the AUC column (default: FALSE).colour_low: Colour for the lowest probability in the heatmap (default: "navy").colour_high: Colour for the highest probability in the heatmap (default: "firebrick3").# 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.
If you ran Parameter_Calculate(), use: min_expression = SlimR_params$min_expression, specificity_weight = SlimR_params$specificity_weight, threshold = SlimR_params$threshold.
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.
Please note: When performing cell-by-cell annotation, the annotation results based on cell resolution are subject to instability.
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 group
Quickly 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.Assess how well a single gene identifies a user-defined cell group when the positive class is rare. PRC-AUC focuses on precision and recall, and is reported as Average Precision together with its no-skill baseline.
result <- Compute_Gene_PRC(
seurat_obj = sce,
gene = "DCLK1",
group_col = "Cell Types",
group_label = "Tuft cells",
assay = "RNA",
method = "rank",
plot = TRUE,
line_color = "darkmagenta",
line_size = 1
)
# Access results
result$PR_AUC # numeric PR-AUC (average precision)
result$Baseline # no-skill baseline = positive class prevalence
head(result$pr_data) # data.frame with recall and precision
result$pr_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 changes both the evaluation population and the baseline, and should be compared with the default all-cell result.plot, plot_title, line_color, line_size: control the PR plot appearance.Why PRC-AUC? ROC-AUC is insensitive to class balance, but rare cell types are exactly where precision matters most. PRC-AUC answers “when I call a cell positive, how often am I right?”, making it more stringent under dropout and background contamination. Always interpret PR_AUC against its Baseline: the same value is strong at baseline 0.02 and weak at baseline 0.50.
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.
# Full three-level hierarchy with proportion heatmap (default: row‑wise proportions)
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"
)
# When plotting sub‑types of a larger population (e.g., immune subsets)
# where total group sizes differ, use adjust_by_group = TRUE
res <- Plot_Hierarchy_Proportion(
seurat_obj = sce,
Main_cell_types = "Immune_Main_type",
Cell_types = "Immune_Cell_type",
Sub_cell_types = "Immune_Sub_type",
proportion = TRUE,
Groups = "condition",
adjust_by_group = TRUE
)
# 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 [email protected].
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‑navy colour gradient (customisable via low_col and high_col). Group labels are shown in bold on the y‑axis, and the number of cells in each group is appended (e.g. “Control (1254)”).
Displaying cell values (show_value_proportion)
Set show_value_proportion = TRUE to overlay formatted numeric proportion values inside the heatmap cells. Text color dynamically switches between black and white based on fill intensity to maximize readability.
Adjustment for unequal group sizes (adjust_by_group)
When analysing sub‑types derived from a larger population (e.g., immune subsets) and group sizes differ, set adjust_by_group = TRUE. This scales proportions by group size relative to the mean group size, highlighting both within-group composition and overall abundance differences. When combined with show_value_proportion = TRUE, the displayed values and heatmap colors reflect these adjusted proportions.
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 object
Data & hierarchy
Main_cell_types and Cell_types are column names in [email protected] 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.
Generate a mean Z-score expression heatmap across specified cell groups from a Seurat object using pheatmap. Optionally computes an integrated marker/pathway score per cell using AUCell and appends its group-level mean Z-score as a weighted top row. Colors are styled with a publication-ready blue-white-red gradient for heatmap values, while annotation bars seamlessly integrate with SlimR's internal discrete palettes (derived from ArchR).
# Basic group-level Z-score heatmap without AUCell integrated row
p <- Plot_Group_Gene_Heatmap(
seurat_obj = sce,
features = c("CD3D", "CD3E", "CD4", "CD8A"),
group_by = "celltype",
add_aucell_row = FALSE
)
# Heatmap with an integrated pathway AUCell score on the top row
p <- Plot_Group_Gene_Heatmap(
seurat_obj = sce,
features = c("TNF", "IL6", "NFKB1", "RELA"),
group_by = "orig.ident",
add_aucell_row = TRUE,
aucell_row_name = "NFkB_Pathway_AUC"
)
seurat_obj accepts both Seurat v4 and v5 objects.
features is a character vector of gene names to display. Missing features in the dataset are automatically omitted with a warning.
group_by specifies a metadata column in [email protected] (e.g., "celltype", "orig.ident") to define group aggregations.assay, slot_or_layer)
assay specifies which assay to pull expression values from (defaults to Seurat::DefaultAssay()).
slot_or_layer defines the data layer (default "data").add_aucell_row, aucell_row_name)add_aucell_row = TRUE (default) calculates cell-level enrichment scores across all specified features using AUCell. Group means of these AUC scores are Z-score normalized and displayed as the top row.aucell_row_name specifies the row label for this top row (default "Integrated_Score").add_aucell_row = FALSE to render only individual gene Z-score rows.cluster_rows, cluster_cols)
Both cluster_rows and cluster_cols default to FALSE to strictly preserve the input gene list order and the original group order from [email protected]. Set to TRUE if hierarchical clustering dendrograms are desired.palette_set, scale_range)
palette_set controls discrete annotation bar colors for cell groups via the internal paletteDiscrete() function (default "stallion").
Heatmap body values use a 11-color RdBu palette smoothly interpolated across custom breaks.
scale_range defines the numeric bounds for Z-scores (default c(-1.25, 1.25)). Values exceeding these bounds are safely clamped to avoid blank cells.Since ArchR is not available on CRAN, SlimR incorporates its colour palettes directly (via the internal function paletteDiscrete()) so that users can enjoy the same publication‑quality colours without any additional installation. The palettes, including the default stallion, are hard‑coded in the package and require no external dependencies.
You can call the palette generator directly:
# Display "orig.ident" using the built-in palette
col.clr <- SlimR::paletteDiscrete(values = c(names(table(sce$orig.ident))))
DimPlot(sce,
reduction = "umap",
group.by = "orig.ident",
cols = col.clr,label = TRUE) + NoAxes()
# Display "cell_type" using the built-in palette
col.clr <- SlimR::paletteDiscrete(levels(sce$cell_type))
DimPlot(sce,
reduction = "umap",
group.by = "cell_type",
cols = col.clr,label = TRUE) + NoAxes()
The function returns a named vector of hex colours, arranged horizontally according to the input vector. 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: [email protected] | Issues: SlimR Issues