reglScatterplot is a thin R wrapper around the JavaScript
regl-scatterplot library,
exposing it as an htmlwidgets widget. It renders millions of
two-dimensional points in the browser via WebGL, which makes it well suited
to:
(x, y) scatter that ggplot2 would draw too slowly.The widget works in:
htmlwidgets::saveWidget(),IRkernel (e.g. VSCode’s Jupyter extension).# (chunk intentionally not run during knit)
# From GitHub
remotes::install_github("george123ya/reglScatterplotR")
# Once accepted into Bioconductor
if (!requireNamespace("BiocManager", quietly = TRUE)) {
install.packages("BiocManager")
}
BiocManager::install("reglScatterplotR")
library(reglScatterplotR)
The simplest call needs only a data.frame and the names of the two
coordinate columns.
set.seed(1L)
df <- data.frame(
x = rnorm(20000),
y = rnorm(20000),
cluster = sample(letters[1:6], 20000, replace = TRUE),
score = runif(20000)
)
reglScatterplot(df, x = "x", y = "y")
plot of chunk basic
Pass a character or factor column name (or vector) to colorBy. A draggable
legend appears in the upper-right corner of the plot; clicking a legend
entry filters the data, and shift/ctrl-click extends the selection.
reglScatterplot(df,
x = "x", y = "y", colorBy = "cluster",
legendTitle = "Cluster"
)
plot of chunk categorical
Numeric colorBy produces a continuous colour scale. Use vmin/vmax
to clip outliers; the strings "p1", "p99" and so on select percentiles.
reglScatterplot(df,
x = "x", y = "y", colorBy = "score",
continuousPalette = "magma",
vmin = "p1", vmax = "p99"
)
plot of chunk continuous
For log-fold-change-style data use centerZero = TRUE to force a symmetric
diverging scale.
reglScatterplot() works directly on a SingleCellExperiment. Pass the
name of a reducedDim() as x. colorBy and groupBy can name a
colData() column or a gene in rownames(). Gene values are read from the
logcounts assay by default; use assay to pick another one.
Here we wrap the bundled example data in a small SingleCellExperiment.
library(SingleCellExperiment)
#> Loading required package: SummarizedExperiment
#> Loading required package: MatrixGenerics
#> Loading required package: matrixStats
#>
#> Attaching package: 'MatrixGenerics'
#> The following objects are masked from 'package:matrixStats':
#>
#> colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse,
#> colCounts, colCummaxs, colCummins, colCumprods, colCumsums,
#> colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs,
#> colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats,
#> colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
#> colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads,
#> colWeightedMeans, colWeightedMedians, colWeightedSds,
#> colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet,
#> rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods,
#> rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
#> rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins,
#> rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks,
#> rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars,
#> rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
#> rowWeightedSds, rowWeightedVars
#> Loading required package: GenomicRanges
#> Loading required package: stats4
#> Loading required package: BiocGenerics
#> Loading required package: generics
#>
#> Attaching package: 'generics'
#> The following objects are masked from 'package:base':
#>
#> as.difftime, as.factor, as.ordered, intersect, is.element, setdiff,
#> setequal, union
#>
#> Attaching package: 'BiocGenerics'
#> The following objects are masked from 'package:stats':
#>
#> IQR, mad, sd, var, xtabs
#> The following object is masked from 'package:utils':
#>
#> data
#> The following objects are masked from 'package:base':
#>
#> Filter, Find, Map, Position, Reduce, anyDuplicated, aperm, append,
#> as.data.frame, basename, cbind, colnames, dirname, do.call,
#> duplicated, eval, evalq, get, grep, grepl, is.unsorted, lapply,
#> mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
#> rank, rbind, rownames, sapply, saveRDS, scale, sequence, table,
#> tapply, transform, unique, unsplit, which.max, which.min
#> Loading required package: S4Vectors
#>
#> Attaching package: 'S4Vectors'
#> The following object is masked from 'package:utils':
#>
#> findMatches
#> The following objects are masked from 'package:base':
#>
#> I, expand.grid, unname
#> Loading required package: IRanges
#> Loading required package: Seqinfo
#> Loading required package: Biobase
#> Welcome to Bioconductor
#>
#> Vignettes contain introductory material; view with
#> 'browseVignettes()'. To cite Bioconductor, see
#> 'citation("Biobase")', and for packages 'citation("pkgname")'.
#>
#> Attaching package: 'Biobase'
#> The following object is masked from 'package:MatrixGenerics':
#>
#> rowMedians
#> The following objects are masked from 'package:matrixStats':
#>
#> anyMissing, rowMedians
data(reglScatterExample)
ex <- reglScatterExample
sce <- SingleCellExperiment(
assays = list(logcounts = t(as.matrix(ex["CD3D"]))),
colData = ex[, c("celltype", "nCount", "percentMito")],
reducedDims = list(UMAP = as.matrix(ex[, c("UMAP_1", "UMAP_2")]))
)
sce
#> class: SingleCellExperiment
#> dim: 1 3400
#> metadata(0):
#> assays(1): logcounts
#> rownames(1): CD3D
#> rowData names(0):
#> colnames: NULL
#> colData names(3): celltype nCount percentMito
#> reducedDimNames(1): UMAP
#> mainExpName: NULL
#> altExpNames(0):
reglScatterplot(sce, x = "UMAP", colorBy = "celltype")
plot of chunk sce
Colouring by a gene reads its row from the assay:
reglScatterplot(sce, x = "UMAP", colorBy = "CD3D", vmax = "p99")
plot of chunk sce-gene
A SpatialExperiment works the same way. Use x = "spatial" to plot the
tissue coordinates from spatialCoords():
reglScatterplot(spe, x = "spatial", colorBy = "celltype")
Seurat objects and in-memory AnnData objects (from anndataR) are also
accepted. They need the optional SeuratObject and anndataR packages.
When several reglScatterplot() widgets share the same plotIds, you can
synchronise pan/zoom across them with enableReglScatterplotSync():
library(shiny)
ui <- fluidPage(
fluidRow(
column(6, reglScatterplotOutput("plotA")),
column(6, reglScatterplotOutput("plotB"))
),
actionButton("link", "Link cameras")
)
server <- function(input, output, session) {
output$plotA <- renderReglScatterplot({
reglScatterplot(df,
x = "x", y = "y", colorBy = "cluster",
plotId = "plotA"
)
})
output$plotB <- renderReglScatterplot({
reglScatterplot(df,
x = "x", y = "y", colorBy = "score",
plotId = "plotB"
)
})
observeEvent(input$link, {
enableReglScatterplotSync(c("plotA", "plotB"))
})
}
shinyApp(ui, server)
On first use the JavaScript bundles (d3, regl-scatterplot, pickr,
html2canvas, jsPDF) are loaded from a CDN (esm.sh and
cdnjs.cloudflare.com). Once loaded they are cached by the browser. A
helpful error message is displayed in-place if the network is unavailable.
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.5 LTS
#>
#> Matrix products: default
#> BLAS: /home/biocbuild/bbs-3.24-bioc/R/lib/libRblas.so
#> LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0 LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_GB LC_COLLATE=C
#> [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: America/New_York
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats4 stats graphics grDevices utils datasets methods
#> [8] base
#>
#> other attached packages:
#> [1] SingleCellExperiment_1.35.2 SummarizedExperiment_1.43.0
#> [3] Biobase_2.73.2 GenomicRanges_1.65.4
#> [5] Seqinfo_1.3.2 IRanges_2.47.5
#> [7] S4Vectors_0.51.10 BiocGenerics_0.59.12
#> [9] generics_0.1.4 MatrixGenerics_1.25.0
#> [11] matrixStats_1.5.0 reglScatterplotR_0.99.6
#>
#> loaded via a namespace (and not attached):
#> [1] Matrix_1.7-6 jsonlite_2.0.0 compiler_4.6.1
#> [4] promises_1.5.0 Rcpp_1.1.2 later_1.4.8
#> [7] yaml_2.3.12 fastmap_1.2.0 mime_0.13
#> [10] lattice_0.23-1 R6_2.6.1 XVector_0.53.0
#> [13] commonmark_2.0.0 S4Arrays_1.13.2 knitr_1.52
#> [16] htmlwidgets_1.6.4 DelayedArray_0.39.8 shiny_1.14.0
#> [19] RColorBrewer_1.1-3 rlang_1.3.0 litedown_0.11
#> [22] httpuv_1.6.17 xfun_0.62 otel_0.2.0
#> [25] viridisLite_0.4.3 SparseArray_1.13.4 cli_3.6.6
#> [28] magrittr_2.0.5 digest_0.6.39 grid_4.6.1
#> [31] xtable_1.8-8 lifecycle_1.0.5 evaluate_1.0.5
#> [34] abind_1.4-8 tools_4.6.1 htmltools_0.5.9