Skip to contents

makeShinyFiles() is a dispatcher. It inspects the object you give it and writes every modality it can find, calling the modality-specific writers on your behalf. Which tabs end up in the app is therefore decided by what is present in your object plus which arguments you supplied — not by anything you configure directly.

Code here is not evaluated when the site is built; it needs real data.

What triggers what

For a Seurat object:

modality writer called condition
Gene expression makeShinyFilesGEX() always
Spatial makeShinyFilesSpatial() length(obj@images) > 0
ATAC coverage makeShinyFilesATACsignac() a peaks assay and bigWigGroup supplied
DEG tables makeShinyFilesDEG() precomputed.deg points at an existing file and clusters given

For an ArchRProject, everything routes to makeShinyFilesATACarchr().

For a path ending in .h5ad, makeShinyFilesGEX() handles it (see the caveat below).

The practical consequence: ATAC and DEG tabs are opt-in. A Signac object with a peaks assay produces no track plot unless you also pass bigWigGroup, and that silence is easy to mistake for a bug.

Gene expression and CITE-seq

The default path. assay and assay.slot choose what gets written:

scConf <- createConfig(seu)

makeShinyFiles(
  seu, scConf,
  assay        = "RNA",
  assay.slot   = "data",
  shiny.prefix = "sc1",
  shiny.dir    = "shinyApp/"
)

assay.slot defaults to "data" — the log-normalised values, which is what you want for visualisation. Leave assay = NA to use the object’s default assay.

For CITE-seq, protein and RNA are separate assays, so build them as separate prefixes and let the app present them as two datasets:

makeShinyFiles(seu, scConf, assay = "RNA", shiny.prefix = "sc1", shiny.dir = "shinyApp/")
makeShinyFiles(seu, scConf, assay = "ADT", shiny.prefix = "sc2", shiny.dir = "shinyApp/")

makeShinyCodes(
  shiny.title   = "PBMC CITE-seq",
  shiny.prefix  = c("sc1", "sc2"),
  shiny.headers = c("Gene expression", "Surface protein"),
  shiny.dir     = "shinyApp/"
)

chunkSize (default 500) controls how many genes are written to HDF5 at a time. Lower it if you are memory-constrained on a large object; it affects build-time memory, not the app.

Spatial transcriptomics

Nothing extra to call — if the Seurat object carries images, the spatial tabs appear:

length(seu@images)
#> [1] 1

makeShinyFiles(seu, scConf, shiny.prefix = "sc1", shiny.dir = "shinyApp/")

Multi-slide objects are handled: when more than one image is present the app gains a slide selector on the spatial tabs, and both the zoom and side-by-side views switch to the multi-slide layout.

The labels in that selector are worth getting right, because they are derived rather than chosen. If your metadata has a column called exactly sample, CellSight labels each slide with the most common sample value among that slide’s cells; otherwise it falls back to the image names, names(obj@images). So either add a sample column or rename the images before building:

names(seu@images)
#> [1] "slice1" "slice1.2"

names(seu@images) <- c("Tumour_A", "Tumour_B")

makeShinyFilesSpatial() can be called directly, but takes only obj, scConf, shiny.prefix and shiny.dir — there are no spatial-specific tuning arguments at build time. Point size defaults for spatial panels are set per dataset by makeShinyCodes() via defPtSiz.

If you are starting from a raw 10x Visium HD output directory rather than a finished object, the container ships an ingest_10x.R helper that does the QC, normalisation, clustering and UMAP for you — see vignette("docker").

scATAC-seq with Signac

Coverage tracks need bigWig files grouped by some cell metadata, which is what bigWigGroup names. Passing it is what switches the track-plot tab on:

makeShinyFiles(
  seu, scConf,
  bigWigGroup  = "seurat_clusters",
  shiny.prefix = "sc1",
  shiny.dir    = "shinyApp/"
)

Track plots need bwtool and libbeato available as command-line tools on the machine that serves the app. They are not R packages and are not installed by install.packages():

git clone https://github.com/CRG-Barcelona/libbeato.git
cd libbeato && git checkout 0c30432 && ./configure && make && make install

cd .. && git clone https://github.com/CRG-Barcelona/bwtool.git
cd bwtool && ./configure && make && make check && make install

This is the one part of a CellSight app with a non-R runtime dependency. If you plan to deploy ATAC data to a hosted platform, confirm you can install system binaries there before you build.

scATAC-seq with ArchR

ArchRProject inputs are recognised by class and routed to makeShinyFilesATACarchr(), which accepts the same defaults arguments as the GEX writer plus bigWigGroup:

scConf <- createConfig(proj)

makeShinyFiles(
  proj, scConf,
  bigWigGroup    = "Clusters",
  dimred.to.use  = "UMAP",
  shiny.prefix   = "sc1",
  shiny.dir      = "shinyApp/"
)

ArchR is not on CRAN — see its install instructions. It is a Suggests dependency, so CellSight installs without it and only needs it for this path.

Differential expression tables

The DEG tab is driven by a precomputed table, not computed at build time. Both precomputed.deg and clusters are required, and the file must exist — makeShinyFiles() errors if the path is wrong rather than silently skipping:

makeShinyFiles(
  seu, scConf,
  precomputed.deg = "deg_results.csv",
  clusters        = c("0", "1", "2", "3"),
  shiny.prefix    = "sc1",
  shiny.dir       = "shinyApp/"
)

Computing the table first, with Seurat, then handing it over:

deg <- Seurat::FindAllMarkers(seu, only.pos = FALSE)
write.csv(deg, "deg_results.csv", row.names = FALSE)

Keeping this step outside CellSight is deliberate: differential expression depends on choices — test, covariates, filtering — that belong to your analysis, not to a visualisation tool.

AnnData / Scanpy input

Pass the .h5ad path as a string where you would pass an object, to both createConfig() and makeShinyFiles():

reticulate::py_install("anndata")

scConf <- createConfig("pbmc.h5ad")
makeShinyFiles("pbmc.h5ad", scConf, shiny.prefix = "sc1", shiny.dir = "shinyApp/")

Reading .h5ad goes through reticulate, so a Python environment with anndata installed must be discoverable. Metadata columns come from h5ad.obs, so meta.to.include takes obs column names.

Which matrix is read is controlled by assay, which defaults to "X": that value reads h5ad.X, and any other is looked up in h5ad.layers.

makeShinyFiles("pbmc.h5ad", scConf, assay = "X", shiny.prefix = "sc1", shiny.dir = "shinyApp/")
makeShinyFiles("pbmc.h5ad", scConf, assay = "counts", shiny.prefix = "sc1", shiny.dir = "shinyApp/")

assay.slot has no meaning for .h5ad input — AnnData has no slot concept — and is ignored on this path.

Calling the writers directly

The modality writers are exported, so you can call one on its own when you want just that modality, or want to pass arguments the dispatcher does not forward:

makeShinyFilesGEX(seu, scConf, gex.assay = "RNA", shiny.prefix = "sc1", shiny.dir = "shinyApp/")
makeShinyFilesSpatial(seu, scConf, shiny.prefix = "sc1", shiny.dir = "shinyApp/")

If you do, write every modality into the same shiny.dir under the same shiny.prefix before calling makeShinyCodes() — the code writer detects which tabs to generate from the data files it finds there.