Cell type annotation is a fundamental step in single-cell RNA-seq analysis, for both smaller datasets as well as for atlas-sized efforts (Hemberg et al. 2025). While many automated approaches exist (Traversa and Chiara 2025), manual annotation is still seen as an ubiquitous step to ensure the best identities are assigned (Andrews et al. 2020). After dimensionality reduction and clustering, analysts need to visually inspect groups of cells, correlate them with known marker genes, and ultimately assign meaningful biological labels. This is a process that often times is very labor-intensive, as it typically involves several rounds of back-and-forth between the visualization(s) and the data.
iSEEid
extends the iSEE
framework (Rue-Albrecht et al. 2018) with
a dedicated Sample Identification Center panel. This
panel receives a cell selection transmitted from any other panel (e.g. a
brush on a ReducedDimensionPlot) and immediately generates ready-to-use
R code to assign a cell type label to those cells — including the
colData column to write into, the label to assign, and an
optional rationale comment for provenance tracking.
The generated command can be copied directly into a script or
notebook, making iSEEid a natural companion for interactive
annotation workflows.
A place to check out what belongs to the iSEE “core functionality”
would be the iSEE organization website (https://isee.github.io/)
and the “Extending iSEE” book (https://isee.github.io/iSEE-book/).
This package has been conceived and developed as a corollary to the iSEE
workshop delivered in Oxford in 2024, for which we also have put
together a resource documenting what is needed to write iSEE extensions
(https://isee.github.io/iSEEDemoEuroBioC2024/articles/workshop_isee_extension.html).
iSEEid can be installed from Bioconductor with the
following code:
if(!requireNamespace('BiocManager', quietly = TRUE))
install.packages('BiocManager')
BiocManager::install("iSEEid")Load the package after installation with
iSEEidWe use the Allen Brain Atlas dataset from scRNAseq as a running example, pre-processed with scater.
library("iSEE")
library("iSEEid")
library("scRNAseq")
library("scater")
#> Loading required package: scuttle
#> Loading required package: ggplot2
library("scrapper")
#>
#> Attaching package: 'scrapper'
#> The following objects are masked from 'package:scater':
#>
#> aggregateAcrossCells, normalizeCounts
#> The following objects are masked from 'package:scuttle':
#>
#> aggregateAcrossCells, normalizeCounts
sce <- ReprocessedAllenData(assays = "tophat_counts")
sce <- normalizeRnaCounts.se(sce, assay.type = "tophat_counts", size.factors = NULL)
sce <- runPCA(sce, ncomponents = 4)
sce <- runTSNE(sce)
colData(sce)["cell_type"] <- "unassigned"A minimal setup pairs a ReducedDimensionPlot with a
SampleIdentificationCenter - this is possible in a scripted
manner via the initial parameter. The
ColumnSelectionSource argument wires these two panels
together from the start, so any brush or lasso drawn on the plot can be
immediately reflected in the annotation panel.
SampleIdentificationCenter panelThe panel consists of two parts:
A basic configuration for using iSEEid.
Among the essential data parameters, we have:
## This is your SummarizedExperiment object
# se
## In this slot you store your annotation e.g. your cell label
# colData(se)[['cell_type']]
## To rename the selected cells to their new label, you can use the command(s) below
## Rationale: high Cd3e / Cd4 expression
colData(se)[
c('cell_A',
'cell_B',
...
), 'cell_type'] <- 'CD4+ T cells'When unchecked, the editor switches to a plain list of cell IDs - this can be useful when you just need the names to pass to another tool or paste into a spreadsheet (you still probably should not use Excel for this…).
The Annotation rationale: this is a free-text
field to record why you are making this assignment — e.g.
high Cd3e / Cd4 expression. When non-empty, the text is
injected as a ## Rationale: comment immediately above the
assignment command, providing lightweight provenance directly inside the
generated code.
The colData column to be used for annotation: The
name of the colData column where labels should be stored.
This column must already exist in your object. Defaults to
cell_type.
The Cell type label, i.e. the label to assign to
the selected cells, which becomes the right-hand side of the assignment
(when generating the commands). This defaults to
new_cell_type, but you can easily replace it with the
actual label before copying the command —
e.g. CD4+ T cells, Microglia,
Monocytes.
iSEEidA typical session with iSEEid looks like this:
iSEE with a ReducedDimensionPlot
linked to a SampleIdentificationCenter.FeatureAssayPlot to check marker gene expression, or
a ColumnDataTable to browse their metadata.SampleIdentificationCenter, fill in the
colData column, the cell type label,
and optionally a rationale.Because the command is generated fresh on every selection change, you can iterate at will — refine the brush, update the label, copy again — without any risk of accidentally overwriting prior annotations already committed to the object.
An important note: iSEE does not execute these
commands for you - nor changes silently the provided object. This is a
clear design choice!
All panel slots can be set at construction time, allowing you to pre-fill sensible defaults for your dataset:
iSEE(sce, initial = list(
ReducedDimensionPlot(
PanelWidth = 3L,
Type = "TSNE",
ColorBy = "Feature name",
ColorByFeatureSource = "RowDataTable1"
),
SampleIdentificationCenter(
ColumnSelectionSource = "ReducedDimensionPlot1",
PanelWidth = 3L,
ColDataColumn = "labels_from_automated_tool",
CellTypeLabel = "new_cell_type",
AnnotationRationale = "refined round: looking explicitly for markers"
),
FeatureAssayPlot(
PanelWidth = 3L,
XAxis = "Column data",
XAxisColumnData = "Primary.Type",
YAxisFeatureSource = "RowDataTable1"
),
RowDataTable(
PanelWidth = 3L,
Selected = "Foxp2",
Search = "Fox"
)
))A somewhat more complex example of iSEEid in action, with some extra panels.
Of course, more complex configurations are also possible - if not
even required, in complex datasets. For these cases, we suggest the
users to create a panel configuration by hand, directly within
iSEE, and export that afterwards with its native
functionality.
sessionInfo()
#> R version 4.6.0 (2026-04-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 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.26.so; LAPACK version 3.12.0
#>
#> 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] stats4 stats graphics grDevices utils datasets methods
#> [8] base
#>
#> other attached packages:
#> [1] scrapper_1.7.3 scater_1.41.1
#> [3] ggplot2_4.0.3 scuttle_1.23.1
#> [5] scRNAseq_2.27.0 iSEEid_0.99.1
#> [7] iSEE_2.25.0 SingleCellExperiment_1.35.1
#> [9] SummarizedExperiment_1.43.0 Biobase_2.73.1
#> [11] GenomicRanges_1.65.0 Seqinfo_1.3.0
#> [13] IRanges_2.47.2 S4Vectors_0.51.3
#> [15] BiocGenerics_0.59.7 generics_0.1.4
#> [17] MatrixGenerics_1.25.0 matrixStats_1.5.0
#> [19] BiocStyle_2.41.0
#>
#> loaded via a namespace (and not attached):
#> [1] splines_4.6.0 later_1.4.8 BiocIO_1.23.3
#> [4] bitops_1.0-9 filelock_1.0.3 tibble_3.3.1
#> [7] XML_3.99-0.23 lifecycle_1.0.5 httr2_1.2.2
#> [10] doParallel_1.0.17 lattice_0.22-9 ensembldb_2.37.3
#> [13] alabaster.base_1.13.0 magrittr_2.0.5 sass_0.4.10
#> [16] rmarkdown_2.31 jquerylib_0.1.4 yaml_2.3.12
#> [19] httpuv_1.6.17 otel_0.2.0 DBI_1.3.0
#> [22] buildtools_1.0.0 RColorBrewer_1.1-3 abind_1.4-8
#> [25] Rtsne_0.17 AnnotationFilter_1.37.0 RCurl_1.98-1.19
#> [28] rappdirs_0.3.4 circlize_0.4.18 ggrepel_0.9.8
#> [31] irlba_2.3.7 alabaster.sce_1.13.0 maketools_1.3.2
#> [34] codetools_0.2-20 DelayedArray_0.39.3 DT_0.34.0
#> [37] tidyselect_1.2.1 shape_1.4.6.1 UCSC.utils_1.9.0
#> [40] farver_2.1.2 viridis_0.6.5 ScaledMatrix_1.21.0
#> [43] shinyWidgets_0.9.1 BiocFileCache_3.3.0 GenomicAlignments_1.49.0
#> [46] jsonlite_2.0.0 GetoptLong_1.1.1 BiocNeighbors_2.7.2
#> [49] iterators_1.0.14 foreach_1.5.2 tools_4.6.0
#> [52] Rcpp_1.1.1-1.1 glue_1.8.1 gridExtra_2.3
#> [55] SparseArray_1.13.2 BiocBaseUtils_1.15.1 xfun_0.58
#> [58] mgcv_1.9-4 GenomeInfoDb_1.49.1 dplyr_1.2.1
#> [61] HDF5Array_1.41.0 gypsum_1.9.0 shinydashboard_0.7.3
#> [64] withr_3.0.2 BiocManager_1.30.27 fastmap_1.2.0
#> [67] rhdf5filters_1.25.0 shinyjs_2.1.1 digest_0.6.39
#> [70] rsvd_1.0.5 R6_2.6.1 mime_0.13
#> [73] colorspace_2.1-2 listviewer_4.0.0 RSQLite_3.53.2
#> [76] cigarillo_1.3.0 h5mread_1.5.0 rtracklayer_1.73.0
#> [79] httr_1.4.8 htmlwidgets_1.6.4 S4Arrays_1.13.0
#> [82] pkgconfig_2.0.3 gtable_0.3.6 blob_1.3.0
#> [85] ComplexHeatmap_2.29.0 S7_0.2.2 XVector_0.53.0
#> [88] sys_3.4.3 htmltools_0.5.9 ProtGenerics_1.45.0
#> [91] rintrojs_0.3.4 clue_0.3-68 scales_1.4.0
#> [94] alabaster.matrix_1.13.0 png_0.1-9 knitr_1.51
#> [97] rjson_0.2.23 nlme_3.1-169 curl_7.1.0
#> [100] shinyAce_0.4.4 cachem_1.1.0 rhdf5_2.57.1
#> [103] GlobalOptions_0.1.4 BiocVersion_3.24.0 parallel_4.6.0
#> [106] miniUI_0.1.2 vipor_0.4.7 AnnotationDbi_1.75.0
#> [109] restfulr_0.0.17 pillar_1.11.1 grid_4.6.0
#> [112] alabaster.schemas_1.13.0 vctrs_0.7.3 promises_1.5.0
#> [115] BiocSingular_1.29.0 dbplyr_2.6.0 beachmat_2.29.0
#> [118] xtable_1.8-8 cluster_2.1.8.2 beeswarm_0.4.0
#> [121] evaluate_1.0.5 GenomicFeatures_1.65.0 cli_3.6.6
#> [124] compiler_4.6.0 Rsamtools_2.29.0 rlang_1.2.0
#> [127] crayon_1.5.3 ggbeeswarm_0.7.3 viridisLite_0.4.3
#> [130] alabaster.se_1.13.0 BiocParallel_1.47.0 Biostrings_2.81.3
#> [133] lazyeval_0.2.3 colourpicker_1.3.0 Matrix_1.7-5
#> [136] ExperimentHub_3.3.1 bit64_4.8.2 Rhdf5lib_2.1.0
#> [139] KEGGREST_1.53.4 shiny_1.13.0 alabaster.ranges_1.13.0
#> [142] AnnotationHub_4.3.1 igraph_2.3.2 memoise_2.0.1
#> [145] bslib_0.11.0 bit_4.6.0