Pull everything back: highlights, labels and scores (Seurat, SingleCellExperiment)#
Whatever you make in the viewer — a lasso, a label field, a gene
signature score, a gene set — comes back onto your object in one call,
cellucid_pull(object, viewer): columns of a Seurat object’s
meta.data or a SingleCellExperiment’s colData, and the gene sets
in misc$cellucid / metadata(x)$cellucid. R copies on change, so
assign the result.
Time: 10 minutes. The same tutorial in Python: Pull everything back.
# A fresh R library (Google Colab's R runtime, a new machine) installs the packages once.
for (package in c("remotes", "SeuratObject")) {
if (!requireNamespace(package, quietly = TRUE)) install.packages(package)
}
if (!requireNamespace("cellucid", quietly = TRUE)) {
if ("cellucid" %in% rownames(available.packages())) install.packages("cellucid") else remotes::install_github("theislab/cellucid-r")
}
The data#
SeuratObject’s own example, pbmc_small: 80 blood cells, 230 genes, a
t-SNE and the clusters RNA_snn_res.1. Use your own Seurat or
SingleCellExperiment object in its place.
library(cellucid)
library(SeuratObject)
data("pbmc_small")
seu <- pbmc_small
seu
viewer <- cellucid_view(seu, dataset_id = "pbmc-small", dataset_name = "PBMC small")
Where the viewer appears:
Where you run R |
The viewer |
|---|---|
a Jupyter notebook (JupyterLab, Notebook 7, VS Code, Google Colab; IRkernel) |
in the cell’s output, once the cell finishes (a notebook widget over the kernel’s own connection: no port, no server) |
RStudio, Positron |
the Viewer pane |
any other R console |
a browser tab |
In a notebook, R hears the viewer between cells: run what reads the
viewer’s work (cellucid_selection(), cellucid_pull()) in a later cell
than the one that showed it.
Work in the viewer#
A lasso. In Highlighting choose Lasso, drag around a group of cells and click Confirm.
A label field. In the field list, Copy
groups, rename the copymy_labelsand, in its legend, rename a category (the pencil) or drag one onto another to merge them.A score. In Analysis › Gene signature, enter
MS4A1, CD79A, CD79Band run it.
Then run the next cell.
for (result in cellucid_results(viewer)) {
name <- c(result$meta$label, result$meta$key, result$meta$name, "")[[1]]
cat(sprintf("%-12s %-28s %s\n", result$kind, result$id, name))
}
cellucid_results() is what the viewer has sent; it stops with a
message only before the viewer has sent it once (when the dataset
opens): run the cell again then.
One call#
pulled <- cellucid_pull(seu, viewer, return_summary = TRUE)
seu <- pulled$data
names(pulled$summary$columns)
Result |
Column |
Type |
|---|---|---|
a highlight group |
|
|
a label field |
its name ( |
|
a score, a continuous field |
its name ( |
|
a gene set |
— |
|
The same names as Python’s viewer.pull(adata). A field pushed from R
(cellucid_push()) comes back only with include_pushed = TRUE.
written <- names(pulled$summary$columns)
head(seu[[]][, written, drop = FALSE])
lasso <- grep("^cellucid_highlight__", written, value = TRUE)
for (column in lasso) print(table(seu$groups, seu[[column]][, 1]))
Again and again#
Pull again after more work: the columns an earlier pull wrote are
replaced, and those whose result you deleted are removed
(summary$removed). A column of the same name that Cellucid did not
write is a conflict: on_conflict = "error" (the default) stops,
"replace" overwrites, "suffix" writes <name>_2 beside it.
pulled <- cellucid_pull(seu, viewer, return_summary = TRUE)
seu <- pulled$data
pulled$summary$removed
The cells themselves#
cellucid_selection(viewer) is the last selection ($cell_names,
$cells); cellucid_subset(object, viewer, which) gives the cells of
a highlight group (by id or label), of the last selection
(which = NULL) or the visible cells ("visible") as a subset of the
object.
groups <- Filter(function(result) identical(result$kind, "highlight"), cellucid_results(viewer))
vapply(groups, function(result) result$meta$label, "")
picked <- cellucid_subset(seu, viewer, groups[[1]]$id)
picked
cellucid_stop(viewer)
A SingleCellExperiment#
The same calls, with colData and metadata(). The object is built
here from pbmc_small; use your own.
library(SingleCellExperiment)
sce <- SingleCellExperiment(
assays = list(counts = LayerData(pbmc_small, layer = "counts")),
colData = pbmc_small[[]],
reducedDims = list(TSNE = Embeddings(pbmc_small, "tsne"))
)
sce_viewer <- cellucid_view(sce, dataset_id = "pbmc-small-sce", dataset_name = "PBMC small (SCE)")
Lasso some cells and Confirm, then:
sce <- cellucid_pull(sce, sce_viewer)
colData(sce)[, grep("^cellucid_highlight__", colnames(colData(sce))), drop = FALSE]
cellucid_stop(sce_viewer)
Next#
Without a notebook: the web app’s exports, read in one call.
Python: Pull everything back