From a Seurat object¶
STELLAR accepts Seurat .rds files as inputs directly — just point
stellar.yaml at the .rds and run stellar ingest. Under the hood,
the first ingest shells out to Rscript to convert the object to an
h5ad and caches the result next to the source (<name>.cached.h5ad),
so every subsequent ingest reuses it instantly.
What you need on the system¶
- R 4.x with
RscriptonPATH - One of:
SeuratDisk(preferred — lossless, fastest)sceasy(fallback)
No Python R-bridge (no rpy2) is required — STELLAR runs Rscript as a
plain subprocess.
Install (one-time)¶
# Inside R:
install.packages("remotes")
remotes::install_github("mojaveazure/seurat-disk")
# OR
remotes::install_github("cellgeni/sceasy")
Then verify:
Configure¶
In stellar.yaml:
input:
matrices:
- name: primary
path: data/raw/my_atlas.rds # ← Seurat .rds, not .h5ad
role: primary
That's it. Everything else (cohort columns, modules, branding) works the same as the h5ad path.
How the conversion works¶
When stellar ingest sees a .rds path, it calls
stellar.core.io.seurat.convert_rds_to_h5ad, which:
- Checks if
<name>.cached.h5adalready exists and is at least as new as the.rds— if so, uses it immediately. - Otherwise runs
Rscript -e <SNIPPET>with the.rdsas input. The snippet: - Loads the object with
readRDS(). - Validates it's actually a
Seurat(not e.g.SingleCellExperiment). - Calls
SeuratDisk::SaveH5Seurat → SeuratDisk::Convertto produce an h5ad. Falls back tosceasy::convertFormatif SeuratDisk isn't installed. - Writes the cached h5ad next to the source.
The h5ad you get back has:
X= the default assay'sdataslotobs= the Seurat object'smeta.dataobsm= allReductions(obj)(UMAP, t-SNE, PCA — STELLAR usesX_umap)var= the default assay's features
Pre-flight check¶
Run stellar doctor after editing the config. It surfaces:
- ✗
Rscript is not on PATH— install R 4.x. - ·
Seurat input — will auto-convert to <name>.cached.h5ad on ingest— all good.
After the first stellar ingest, the cached h5ad is what subsequent
runs check; doctor will then validate obs columns and UMAP normally.
Troubleshooting¶
"readRDS produced a SingleCellExperiment object — expected Seurat"¶
Your .rds isn't a Seurat object. Convert it on the R side first:
sce <- readRDS("my.rds")
seurat_obj <- Seurat::as.Seurat(sce, counts = "counts", data = "logcounts")
saveRDS(seurat_obj, "my_as_seurat.rds")
…then point STELLAR at my_as_seurat.rds.
"Need either SeuratDisk or sceasy installed"¶
Install one (see "Install" above). If both are installed, SeuratDisk is preferred (it's lossless on most Seurat objects).
Repeated full conversion on every ingest¶
If the cache is being invalidated each run, check that the .rds mtime
isn't being touched by another process (e.g. an rsync -a that updates
mtimes). You can force a one-time rebuild with:
from stellar.core.io.seurat import convert_rds_to_h5ad
convert_rds_to_h5ad("data/raw/my.rds", force=True)
Conversion is slow on the first run¶
It scales with cell count — a 1 M cell Seurat object can take 5-15 minutes. The result is cached; subsequent ingests skip it entirely.
Skipping the auto-conversion¶
If you'd rather convert manually once and point STELLAR at the h5ad:
# In R, one time:
library(SeuratDisk)
SaveH5Seurat(my_seurat, "my.h5seurat", overwrite = TRUE)
Convert("my.h5seurat", dest = "h5ad", overwrite = TRUE)
# → my.h5ad
The end result is identical.