The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
The SingleCellComplexHeatMap
package provides a powerful
and flexible way to visualize single-cell RNA-seq data using complex
heatmaps that simultaneously display both gene expression levels (as
color intensity) and expression percentages (as circle sizes). This
dual-information approach allows for comprehensive visualization of
expression patterns across different cell types and conditions.
library(SingleCellComplexHeatMap)
library(Seurat)
library(dplyr)
# Load optional color packages for testing
if (requireNamespace("ggsci", quietly = TRUE)) {
library(ggsci)
}
if (requireNamespace("viridis", quietly = TRUE)) {
library(viridis)
}
# For this vignette, we'll use the built-in pbmc_small dataset
data("pbmc_small", package = "SeuratObject")
seurat_obj <- pbmc_small
# Add example metadata for demonstration
set.seed(123)
seurat_obj$timepoint <- sample(c("Mock", "6hpi", "24hpi"), ncol(seurat_obj), replace = TRUE)
seurat_obj$celltype <- sample(c("T_cell", "B_cell", "Monocyte"), ncol(seurat_obj), replace = TRUE)
seurat_obj$group <- paste(seurat_obj$timepoint, seurat_obj$celltype, sep = "_")
# Check the structure
head(seurat_obj@meta.data)
#> orig.ident nCount_RNA nFeature_RNA RNA_snn_res.0.8
#> ATGCCAGAACGACT SeuratProject 70 47 0
#> CATGGCCTGTGCAT SeuratProject 85 52 0
#> GAACCTGATGAACC SeuratProject 87 50 1
#> TGACTGGATTCTCA SeuratProject 127 56 0
#> AGTCAGACTGCACA SeuratProject 173 53 0
#> TCTGATACACGTGT SeuratProject 70 48 0
#> letter.idents groups RNA_snn_res.1 timepoint celltype
#> ATGCCAGAACGACT A g2 0 24hpi B_cell
#> CATGGCCTGTGCAT A g1 0 24hpi Monocyte
#> GAACCTGATGAACC B g2 0 24hpi Monocyte
#> TGACTGGATTCTCA A g2 0 6hpi T_cell
#> AGTCAGACTGCACA A g2 0 24hpi B_cell
#> TCTGATACACGTGT A g1 0 6hpi T_cell
#> group
#> ATGCCAGAACGACT 24hpi_B_cell
#> CATGGCCTGTGCAT 24hpi_Monocyte
#> GAACCTGATGAACC 24hpi_Monocyte
#> TGACTGGATTCTCA 6hpi_T_cell
#> AGTCAGACTGCACA 24hpi_B_cell
#> TCTGATACACGTGT 6hpi_T_cell
The simplest way to create a complex heatmap is to provide a Seurat object and a list of features:
# Define genes to visualize
features <- c("CD3D", "CD3E", "CD8A", "IL32", "CD79A")
# Create basic heatmap
heatmap_basic <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
group_by = "group"
)
For more complex analyses, you can group genes by functional categories:
# Define gene groups
gene_groups <- list(
"T_cell_markers" = c("CD3D", "CD3E", "CD8A", "IL32"),
"B_cell_markers" = c("CD79A", "CD79B", "MS4A1"),
"Activation_markers" = c("GZMK", "CCL5")
)
# Get all genes from groups
all_genes <- c("CD3D", "CD3E", "CD8A", "IL32","CD79A", "CD79B", "MS4A1","GZMK", "CCL5")
# Create advanced heatmap with gene grouping
heatmap_advanced <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = all_genes,
gene_classification = gene_groups,
group_by = "group",
time_points_order = c("Mock", "6hpi", "24hpi"),
cell_types_order = c("T_cell", "B_cell", "Monocyte"),
color_range = c(-2, 0, 2),
color_palette = c("navy", "white", "firebrick"),
max_circle_size = 3,
split_by = "time"
)
The complex heatmap displays two types of information simultaneously:
This dual approach allows you to distinguish between genes that are: - Highly expressed in few cells (small intense circles) - Moderately expressed in many cells (large moderate circles) - Highly expressed in many cells (large intense circles)
For optimal functionality, your group identifiers should follow the
format "timepoint_celltype"
:
# Example of proper data preparation
seurat_obj@meta.data <- seurat_obj@meta.data %>%
mutate(
# Create combined group for time course + cell type analysis
time_celltype = paste(timepoint, celltype, sep = "_"),
# Or create other combinations as needed
cluster_time = paste(RNA_snn_res.0.8, timepoint, sep = "_")
)
head(seurat_obj@meta.data[, c("timepoint", "celltype", "time_celltype","cluster_time")])
#> timepoint celltype time_celltype cluster_time
#> ATGCCAGAACGACT 24hpi B_cell 24hpi_B_cell 0_24hpi
#> CATGGCCTGTGCAT 24hpi Monocyte 24hpi_Monocyte 0_24hpi
#> GAACCTGATGAACC 24hpi Monocyte 24hpi_Monocyte 1_24hpi
#> TGACTGGATTCTCA 6hpi T_cell 6hpi_T_cell 0_6hpi
#> AGTCAGACTGCACA 24hpi B_cell 24hpi_B_cell 0_24hpi
#> TCTGATACACGTGT 6hpi T_cell 6hpi_T_cell 0_6hpi
Here, we test the ability to change the default titles for the annotation tracks.
heatmap <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
gene_classification = gene_groups,
group_by = "group",
time_points_order = c("Mock", "6hpi", "24hpi"),
# NEW: Custom annotation titles
gene_group_title = "Gene Function",
time_point_title = "Time Point",
cell_type_title = "Cell Type",
split_by = "time"
)
You can customize colors for different components:
# Custom color schemes
heatmap_colors <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
gene_classification = gene_groups,
group_by = "group",
color_range = c(-1.5, 0, 1.5,3), # 4-point gradient
color_palette = c("darkblue", "blue", "white", "red"), # 4 colors
gene_color_palette = "Spectral",
time_color_palette = "Set2",
celltype_color_palette = "Pastel1"
)
ggsci
Palettesif (requireNamespace("ggsci", quietly = TRUE)) {
heatmap_colors <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
gene_classification = gene_groups,
group_by = "group",
time_points_order = c("Mock", "6hpi", "24hpi"),
# NEW: Using ggsci color vectors
gene_color_palette = pal_npg()(3),
time_color_palette = pal_lancet()(3),
celltype_color_palette = pal_jama()(4),
# Custom expression heatmap colors
color_range = c(-2, 0, 2),
color_palette = c("#2166AC", "#F7F7F7", "#B2182B")
)
}
viridis
and Custom Colorsif (requireNamespace("ggsci", quietly = TRUE)) {
heatmap_colors <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
gene_classification = gene_groups,
group_by = "group",
time_points_order = c("Mock", "6hpi", "24hpi"),
# NEW: Using ggsci color vectors
gene_color_palette = pal_npg()(3),
time_color_palette = pal_lancet()(3),
celltype_color_palette = pal_jama()(4),
# Custom expression heatmap colors
color_range = c(-2, 0, 2),
color_palette = c("#2166AC", "#F7F7F7", "#B2182B")
)
}
# Publication-ready styling
heatmap_publication <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = all_genes,
gene_classification = gene_groups,
group_by = "group",
max_circle_size = 2.5,
row_fontsize = 12,
col_fontsize = 12,
row_title_fontsize = 14,
col_title_fontsize = 12,
percentage_legend_title = "Fraction of cells",
percentage_legend_labels = c("0", "20", "40", "60", "80"),
legend_side = "right"
)
This test demonstrates how to remove cell borders and column annotations for a cleaner look.
heatmap_con <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
gene_classification = gene_groups,
group_by = "group",
# NEW: Visual control parameters
show_cell_borders = FALSE,
show_column_annotation = FALSE,
# Other parameters for a clean plot
split_by = "none",
cluster_cells = TRUE
)
This test shows how to replace default gene names (e.g., symbols) with custom labels on the y-axis.
# Create a mapping for a subset of genes
gene_mapping <- c(
"CD3D" = "T-cell Receptor CD3d",
"CD79A" = "B-cell Antigen Receptor CD79a",
"GZMK" = "Granzyme K",
"NKG7" = "Natural Killer Cell Granule Protein 7"
)
heatmap_map <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
gene_classification = gene_groups,
group_by = "group",
# NEW: Gene name mapping
gene_name_mapping = gene_mapping,
row_fontsize = 9
)
You can control clustering behavior for both genes and cells:
# Custom clustering
heatmap_clustering <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
group_by = "group",
cluster_cells = TRUE,
cluster_features = TRUE,
clustering_distance_rows = "pearson",
clustering_method_rows = "ward.D2",
clustering_distance_cols = "euclidean",
clustering_method_cols = "complete"
)
For time course experiments, focus on temporal patterns:
# Time course focused analysis
heatmap_time <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
group_by = "group",
time_points_order = c("Mock", "6hpi", "24hpi"),
cell_types_order = c("T_cell", "B_cell", "Monocyte"),
split_by = "time",
show_celltype_annotation = TRUE,
show_time_annotation = TRUE
)
For cell type-focused analysis:
# Cell type focused analysis
heatmap_celltype <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
group_by = "celltype",
split_by = "celltype",
show_time_annotation = FALSE,
show_celltype_annotation = TRUE
)
For basic expression visualization without grouping:
# Simple analysis
heatmap_sample <- create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
gene_classification = NULL, # No gene grouping
group_by = "group",
show_time_annotation = FALSE,
show_celltype_annotation = FALSE,
split_by = "none"
)
This final example combines several new and existing features to create a highly customized, publication-ready plot.
create_single_cell_complex_heatmap(
seurat_object = seurat_obj,
features = features,
gene_classification = gene_groups,
group_by = "group",
time_points_order = c("Mock", "6hpi", "24hpi"),
# --- New Features ---
gene_group_title = "Functional Category",
time_point_title = "Time Post-Infection",
cell_type_title = "Cell Identity",
show_cell_borders = TRUE,
cell_border_color = "white",
gene_name_mapping = c("MS4A1" = "CD20"),
# --- Color Customization ---
color_range = c(-2, 0, 2),
color_palette = c("#0072B2", "white", "#D55E00"), # Colorblind-friendly
gene_color_palette = "Dark2",
time_color_palette = "Set2",
celltype_color_palette = "Paired",
# --- Layout and Font ---
row_fontsize = 10,
col_fontsize = 9,
row_title_fontsize = 12,
col_title_fontsize = 12,
col_name_rotation = 45,
legend_side = "right",
merge_legends = TRUE,
# --- Clustering and Splitting ---
cluster_features = FALSE, # Rows are already grouped
cluster_cells = FALSE, # Columns are already grouped
split_by = "time"
)
The package provides helper functions for step-by-step analysis:
# Prepare matrices
matrices <- prepare_expression_matrices(
seurat_object = seurat_obj,
features = features,
group_by = "group",
idents = NULL # Use all groups
)
# Check the structure
dim(matrices$exp_mat)
#> [1] 5 9
dim(matrices$percent_mat)
#> [1] 5 9
head(matrices$dotplot_data)
#> avg.exp pct.exp features.plot id avg.exp.scaled
#> CD3D 105.56974 25.00 CD3D 24hpi_B_cell 0.40882740
#> CD3E 27.84701 18.75 CD3E 24hpi_B_cell -0.90555550
#> CD8A 20.66799 12.50 CD8A 24hpi_B_cell 0.91030585
#> IL32 70.30069 37.50 IL32 24hpi_B_cell -0.07758342
#> CD79A 56.25748 31.25 CD79A 24hpi_B_cell 0.58606789
#> CD3D1 192.27796 62.50 CD3D 24hpi_Monocyte 1.25892500
# Create gene annotations
if (!is.null(gene_groups)) {
gene_ann <- create_gene_annotations(
exp_mat = matrices$exp_mat,
percent_mat = matrices$percent_mat,
gene_classification = gene_groups,
color_palette = "Set1"
)
# Check results
dim(gene_ann$exp_mat_ordered)
levels(gene_ann$annotation_df$GeneGroup)
}
#> [1] "T_cell_markers" "B_cell_markers" "Activation_markers"
# Create cell annotations
cell_ann <- create_cell_annotations(
exp_mat = matrices$exp_mat,
percent_mat = matrices$percent_mat,
time_points_order = c("Mock", "6hpi", "24hpi"),
cell_types_order = c("T_cell", "B_cell", "Monocyte"),
show_time_annotation = TRUE,
show_celltype_annotation = TRUE
)
# Check results
dim(cell_ann$exp_mat_ordered)
#> [1] 5 9
head(cell_ann$annotation_df)
#> id Time Point Cell Type
#> 1 Mock_T_cell Mock T_cell
#> 2 Mock_B_cell Mock B_cell
#> 3 Mock_Monocyte Mock Monocyte
#> 4 6hpi_T_cell 6hpi T_cell
#> 5 6hpi_B_cell 6hpi B_cell
#> 6 6hpi_Monocyte 6hpi Monocyte
You can save plots directly from the function:
merge_legends = TRUE
for cleaner layoutsidents
parameter includes valid groupsIf you encounter issues:
?create_single_cell_complex_heatmap
sessionInfo()
#> R version 4.3.3 (2024-02-29)
#> Platform: x86_64-conda-linux-gnu (64-bit)
#> Running under: CentOS Linux 7 (Core)
#>
#> Matrix products: default
#> BLAS/LAPACK: /public3/home/fanxr/bin/miniforge3/envs/Monocle2/lib/libopenblasp-r0.3.28.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=zh_CN.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=zh_CN.UTF-8 LC_COLLATE=C
#> [5] LC_MONETARY=zh_CN.UTF-8 LC_MESSAGES=zh_CN.UTF-8
#> [7] LC_PAPER=zh_CN.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=zh_CN.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: NA
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] viridis_0.6.5 viridisLite_0.4.2
#> [3] ggsci_3.2.0 dplyr_1.1.4
#> [5] Seurat_5.1.0 SeuratObject_5.0.2
#> [7] sp_2.1-4 SingleCellComplexHeatMap_0.1.2
#>
#> loaded via a namespace (and not attached):
#> [1] RColorBrewer_1.1-3 jsonlite_1.8.9 shape_1.4.6.1
#> [4] magrittr_2.0.3 spatstat.utils_3.1-2 farver_2.1.2
#> [7] rmarkdown_2.29 GlobalOptions_0.1.2 vctrs_0.6.5
#> [10] ROCR_1.0-11 Cairo_1.6-2 spatstat.explore_3.3-4
#> [13] htmltools_0.5.8.1 sass_0.4.9 sctransform_0.4.1
#> [16] parallelly_1.41.0 KernSmooth_2.23-26 bslib_0.8.0
#> [19] htmlwidgets_1.6.4 ica_1.0-3 plyr_1.8.9
#> [22] plotly_4.10.4 zoo_1.8-12 cachem_1.1.0
#> [25] igraph_2.0.3 mime_0.12 lifecycle_1.0.4
#> [28] iterators_1.0.14 pkgconfig_2.0.3 Matrix_1.6-5
#> [31] R6_2.5.1 fastmap_1.2.0 fitdistrplus_1.2-2
#> [34] future_1.34.0 shiny_1.10.0 clue_0.3-66
#> [37] digest_0.6.37 colorspace_2.1-1 patchwork_1.3.0
#> [40] S4Vectors_0.40.2 tensor_1.5 RSpectra_0.16-2
#> [43] irlba_2.3.5.1 progressr_0.15.1 spatstat.sparse_3.1-0
#> [46] httr_1.4.7 polyclip_1.10-7 abind_1.4-5
#> [49] compiler_4.3.3 withr_3.0.2 doParallel_1.0.17
#> [52] fastDummies_1.7.5 MASS_7.3-60.0.1 rjson_0.2.23
#> [55] tools_4.3.3 lmtest_0.9-40 httpuv_1.6.15
#> [58] future.apply_1.11.3 goftest_1.2-3 glue_1.8.0
#> [61] nlme_3.1-165 promises_1.3.2 grid_4.3.3
#> [64] Rtsne_0.17 cluster_2.1.8 reshape2_1.4.4
#> [67] generics_0.1.3 gtable_0.3.6 spatstat.data_3.1-4
#> [70] tidyr_1.3.1 data.table_1.17.2 BiocGenerics_0.48.1
#> [73] spatstat.geom_3.3-4 RcppAnnoy_0.0.22 ggrepel_0.9.6
#> [76] RANN_2.6.2 foreach_1.5.2 pillar_1.10.1
#> [79] stringr_1.5.1 spam_2.11-1 RcppHNSW_0.6.0
#> [82] later_1.4.1 circlize_0.4.16 splines_4.3.3
#> [85] lattice_0.22-6 survival_3.8-3 deldir_2.0-4
#> [88] tidyselect_1.2.1 ComplexHeatmap_2.16.0 miniUI_0.1.1.1
#> [91] pbapply_1.7-2 knitr_1.49 gridExtra_2.3
#> [94] IRanges_2.36.0 scattermore_1.2 stats4_4.3.3
#> [97] xfun_0.50 matrixStats_1.5.0 stringi_1.8.4
#> [100] lazyeval_0.2.2 yaml_2.3.10 evaluate_1.0.3
#> [103] codetools_0.2-20 tibble_3.2.1 cli_3.6.3
#> [106] uwot_0.2.2 xtable_1.8-4 reticulate_1.40.0
#> [109] munsell_0.5.1 jquerylib_0.1.4 Rcpp_1.0.14
#> [112] globals_0.16.3 spatstat.random_3.3-2 png_0.1-8
#> [115] spatstat.univar_3.1-1 parallel_4.3.3 ggplot2_3.5.1
#> [118] dotCall64_1.2 listenv_0.9.1 scales_1.3.0
#> [121] ggridges_0.5.6 leiden_0.4.3.1 purrr_1.0.2
#> [124] crayon_1.5.3 GetoptLong_1.0.5 rlang_1.1.5
#> [127] cowplot_1.1.3
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.