Getting Started with SingleCellComplexHeatMap

XueCheng

2025年06月24日

Introduction

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.

Key Features

  • Dual Information Display: Shows both expression intensity and percentage in a single visualization
  • Gene Grouping: Organize genes by functional categories with color-coded annotations
  • Time Course Support: Handle time series data with proper ordering and visualization
  • Cell Type Annotations: Annotate and group different cell types
  • Flexible Display Options: Show/hide different annotation layers
  • Highly Customizable: Extensive parameters for colors, sizes, fonts, and layouts
  • Seurat Integration: Direct integration with Seurat objects

Installation

 # Install from GitHub
devtools::install_github("FanXuRong/SingleCellComplexHeatMap")

Quick Start

Loading Libraries and Data

 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

Basic Usage

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"
)

Advanced Usage with Gene Grouping

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"
)

Understanding the Visualization

Dual Information Display

The complex heatmap displays two types of information simultaneously:

  1. Color Intensity: Represents the scaled expression level of each gene
  2. Circle Size: Represents the percentage of cells expressing each gene

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)

Data Preparation Requirements

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

Customization Options

Custom Annotation Titles

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"
)

Color Schemes

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"
)

Using ggsci Palettes

 if (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")
 )
} 

2.2 Using viridis and Custom Colors

 if (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")
 )
} 

Font and Size Adjustments

 # 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"
)

Visual Element Control

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
)

Gene Name Mapping

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
)

Clustering Control

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"
)

Different Use Cases

Case 1: Time Course Analysis

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
)

Case 2: Cell Type Comparison

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
)

Case 3: Simple Expression Analysis

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"
)

Comprehensive Example

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"
)

Working with Helper Functions

The package provides helper functions for step-by-step analysis:

Step 1: Prepare Expression Matrices

 # 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

Step 2: Create Gene Annotations

 # 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"

Step 3: Create Cell Annotations

 # 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

Saving and Exporting

You can save plots directly from the function:

 # Save plot to file
heatmap_saved <- create_single_cell_complex_heatmap(
 seurat_object = seurat_obj,
 features = features,
 gene_classification = gene_groups,
 group_by = "group",
 save_plot = "my_heatmap.png",
 plot_width = 12,
 plot_height = 10,
 plot_dpi = 300
)

Tips and Best Practices

1. Data Preparation

  • Ensure your metadata columns are properly formatted
  • Use consistent naming conventions for time points and cell types
  • Consider the number of features - too many can make the plot cluttered

2. Color Selection

  • Use diverging color palettes for expression data
  • Ensure sufficient contrast for accessibility
  • Consider colorblind-friendly palettes

3. Performance Optimization

  • For large datasets, consider subsetting cells or using representative clusters
  • Reduce visual complexity with smaller circle sizes and fonts
  • Use merge_legends = TRUE for cleaner layouts

4. Publication Guidelines

  • Use high DPI (300+) for publication figures
  • Ensure font sizes are readable in the final format
  • Include scale bars and legends
  • Consider splitting complex plots into multiple panels

Troubleshooting

Common Issues

  1. "Features not found": Check that gene names match exactly with your Seurat object
  2. "group_by column not found": Verify the metadata column name exists
  3. Empty heatmap: Check that your idents parameter includes valid groups
  4. Clustering errors: Ensure you have enough features for clustering algorithms

Getting Help

If you encounter issues:

  1. Check the function documentation: ?create_single_cell_complex_heatmap
  2. Review the examples in this vignette
  3. File an issue on GitHub: https://github.com/FanXuRong/SingleCellComplexHeatMap/issues

Session Information

 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

AltStyle によって変換されたページ (->オリジナル) /