Single-cell RNA sequencing (scRNA-seq) enables the characterization
of cellular heterogeneity at single-cell resolution,but its
interpretation relies on computational workflows for dimensionality
reduction and visualization. These workflows require multiple parameter
choices in preprocessing, clustering, and visualization steps. Although
general recommendations exist, suitable parameter selection remains
dataset-specific, leaving manual configuration susceptible to
subjectivity and poor reproducibility when incompletely reported. We
address this gap with geneticUMAP, an objective, dataset-specific
optimization framework for configuring scRNA-seq visualization.
geneticUMAP embeds the complete workflow in a genetic
algorithm and optimizes its configuration using the Calinski-Harabasz
index to evaluate how well the intrinsic data structure is preserved in
the final visualization. We applied geneticUMAP to 18 publicly available
scRNA-seq datasets that span different species, tissues, and acquisition
protocols. Across all datasets, optimization improved
structure-preserving mappings. Additionally, we assess the robustness
under parameter perturbations and the biological relevance of the
resulting visualizations. Optimized configurations generally produced
more robust visualizations than default settings and improved agreement
with author-provided cell-type annotations for most datasets. By
automatically identifying a suitable configuration, geneticUMAP
eliminates the need for manual parameter tuning and enables more
objective and robust scRNA-seq data visualizations.
Alongside this R package, geneticUMAP is available as web application.
Make sure R is installed on your system. Install the package from Bioconductor:
Provide run_optimization() with a directory containing
either a 10X Genomics matrix (matrix.mtx,
barcodes.tsv, and features.tsv or
genes.tsv) or a 10X HDF5 file (.h5). If the
directory contains an HDF5 file, the package loads that file. The
package applies fixed quality-control filters to every dataset: cells
must have more than 200 and fewer than 2,500 detected features, and
mitochondrial content must be below 5% using the ^MT-
gene-name pattern.
The package includes a small HDF5 dataset* for this reproducible example. The optimization settings below match the lightweight configuration used by the package tests.
library(geneticumap)
data_dir <- system.file("extdata", "testdata", package="geneticumap")
results_dir <- file.path(tempdir(), "geneticumap-vignette-results")optimization_result <- run_optimization(
data_dir = data_dir,
results_dir = results_dir,
mu = 2,
lambda = 4,
max_iterations = 2,
num_processes = 1
)The function writes its results to results_dir and
returns the optimized parameters as a named vector. The same parameters
are saved in a JSON file within results_dir.
| File | What it contains |
|---|---|
| seurat-params.json | Selected values for the six pipeline parameters |
| umap-coordinates.tsv | One row per cell, with its barcode and two UMAP
coordinates (umap_1, umap_2) |
| cluster-identities.tsv | The Seurat cluster assignment for each cell barcode. These are the clusters used to calculate the CH index |
| scatter-fitness.png | CH fitness across generations |
| umap-static.png | Static UMAP plot for the selected parameter set |
| umap-static-default-seurat.png | Static UMAP plot using the package’s default parameter set, for comparison |
| umap-interactive.html | Interactive UMAP for the selected settings, with cluster labels and hover information for top marker genes |
The coordinate and cluster tables can be joined by
cell_id. Comparing the two static plots gives a quick
visual comparison between the default and selected settings; open the
interactive HTML file for cell-level exploration.
*The test dataset included in this package is a synthetic dataset. No biological interpretation can be deduced from the results retrieved from it.
utils::sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.04.1 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so; LAPACK version 3.12.0
#>
#> Random number generation:
#> RNG: L'Ecuyer-CMRG
#> Normal: Inversion
#> Sample: Rejection
#>
#> 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
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] knitr_1.52 Seurat_5.6.0 SeuratObject_5.4.0
#> [4] sp_2.2-4 ecr_2.1.1.1 smoof_1.7.0
#> [7] checkmate_2.3.4 ParamHelpers_1.14.2 BBmisc_1.13.1
#> [10] clusterCrit_1.3.0 geneticumap_0.99.6 rmarkdown_2.32
#>
#> loaded via a namespace (and not attached):
#> [1] RColorBrewer_1.1-3 sys_3.4.3 rstudioapi_0.19.0
#> [4] jsonlite_2.0.0 magrittr_2.0.5 spatstat.utils_3.2-5
#> [7] farver_2.1.2 vctrs_0.7.3 ROCR_1.0-12
#> [10] spatstat.explore_3.8-3 htmltools_0.5.9 sass_0.4.10
#> [13] sctransform_0.4.3 parallelly_1.48.0 KernSmooth_2.23-27
#> [16] bslib_0.12.0 htmlwidgets_1.6.4 ica_1.0-3
#> [19] plyr_1.8.9 plotly_4.12.1 zoo_1.9-1
#> [22] cachem_1.1.0 buildtools_1.0.0 igraph_2.3.4
#> [25] mime_0.13 lifecycle_1.0.5 pkgconfig_2.0.3
#> [28] Matrix_1.7-6 R6_2.6.1 fastmap_1.2.0
#> [31] fitdistrplus_1.2-6 future_1.80.0 shiny_1.14.0
#> [34] digest_0.6.39 patchwork_1.3.2 tensor_1.5.1
#> [37] RSpectra_0.16-2 irlba_2.4.1 crosstalk_1.2.2
#> [40] textshaping_1.0.5 labeling_0.4.3 progressr_1.1.0
#> [43] spatstat.sparse_3.2-0 httr_1.4.9 polyclip_1.10-7
#> [46] abind_1.4-8 compiler_4.6.1 withr_3.0.3
#> [49] bit64_4.8.6 S7_0.2.2 backports_1.5.1
#> [52] fastDummies_1.7.6 MASS_7.3-66 tools_4.6.1
#> [55] lmtest_0.9-40 otel_0.2.0 parallelMap_1.5.1
#> [58] httpuv_1.6.17 future.apply_1.21.0 goftest_1.2-3
#> [61] glue_1.8.1 nlme_3.1-171 promises_1.5.0
#> [64] grid_4.6.1 Rtsne_0.17 cluster_2.1.8.3
#> [67] reshape2_1.4.5 generics_0.1.4 hdf5r_1.3.16
#> [70] gtable_0.3.6 spatstat.data_3.1-9 tidyr_1.3.2
#> [73] data.table_1.18.6.1 xml2_1.6.0 spatstat.geom_3.8-3
#> [76] RcppAnnoy_0.0.23 ggrepel_0.9.8 RANN_2.6.3
#> [79] pillar_1.11.1 stringr_1.6.0 spam_2.11-4
#> [82] RcppHNSW_0.7.0 later_1.4.8 splines_4.6.1
#> [85] dplyr_1.2.1 lattice_0.23-1 bit_4.6.0
#> [88] survival_3.8-12 deldir_2.0-4 tidyselect_1.2.1
#> [91] maketools_1.3.2 miniUI_0.1.2 pbapply_1.7-5
#> [94] gridExtra_2.3.1 svglite_2.2.2 scattermore_1.2
#> [97] xfun_0.62 matrixStats_1.5.0 stringi_1.8.9
#> [100] lazyeval_0.2.3 yaml_2.3.12 kableExtra_1.4.1
#> [103] evaluate_1.0.5 codetools_0.2-20 tibble_3.3.1
#> [106] cli_3.6.6 uwot_0.2.5 xtable_1.8-8
#> [109] reticulate_1.47.0 systemfonts_1.3.2 jquerylib_0.1.4
#> [112] Rcpp_1.1.2 globals_0.20.0 spatstat.random_3.5-2
#> [115] png_0.1-9 spatstat.univar_3.2-0 parallel_4.6.1
#> [118] ggplot2_4.0.3 dotCall64_1.2 listenv_1.1.0
#> [121] viridisLite_0.4.3 scales_1.4.0 ggridges_0.5.7
#> [124] purrr_1.2.2 rlang_1.3.0 cowplot_1.2.0
#> [127] fastmatch_1.1-8