Specifying Inputs to run_together¶
run_together accepts inputs in three ways, from most convenient to most expressive. They compose — you can set the base run on the CLI and add only the extras in a config JSON.
| Mode | Flag | Use when |
|---|---|---|
| 1. Single sample (direct CLI) | --in-dir / --in-prefix or explicit --in-* file flags |
One sample; a standard platform directory, or a few individually-named files. |
| 2. Multi-sample (sample sheet) | --samples samples.tsv |
Several samples (a joint model by default). A wide TSV, one row per sample. |
| 3. Full config (JSON) | --config run.json |
Per-sample settings differ, or you need analyses/images beyond the profile defaults. |
Samples from all three are combined: the config's samples, then the --samples rows, then the one sample built from the single-sample flags. All samples sharing one --out-dir form one joint run.
Whichever you use, the platform profile (--platform <name>) supplies the defaults: which files to auto-detect, the default FICTURE and cell analyses, and the image conventions. See Supported Platforms for what each profile expects and the per-platform pages for worked examples.
Mode 1 — Single sample (direct CLI)¶
Two shapes, depending on how your files are laid out.
A standard platform directory — point --in-dir at it and the profile auto-detects every role inside:
1 2 3 | |
Individually-named files (not in a standard directory) — name each explicitly. Each flag is the CLI equivalent of a sample-sheet column:
1 2 3 4 5 | |
| Flag | Sample-sheet column | Meaning |
|---|---|---|
--in-dir |
in_dir |
Raw platform directory → roles auto-detected inside it. A platform may instead consume the directory whole (Seq-Scope: it is the MEX directory). |
--in-prefix |
in_prefix |
Raw platform path prefix → roles auto-detected by suffix (Stereo-seq). |
--raw-transcript |
raw_transcript |
Raw transcript CSV/TSV (or .parquet, converted first) to ingest through sge_convert. |
--in-transcript |
transcript |
An already-ingested transcript TSV; skips ingest. Mutually exclusive with --raw-transcript. |
--in-cell-xy |
xy |
Cell centroids / metadata file. |
--in-cell-boundary |
boundaries |
Cell boundary polygons. |
--in-cellxgene |
cellxgene |
Cell×gene matrix CSV → converted to a MEX (drives cell clustering). |
--id |
id |
Sample id. With --out-dir it defaults to rep1 (the packaged directory and catalog id become <out-dir basename>-rep1); with --out-root, to the in_dir / in_prefix basename. |
--in-dir is just a one-row sample sheet with only in_dir; the explicit --in-* flags are a one-row sheet with those columns. Other roles (clusters, mex, cell_tsv, gef, …) have no single-sample flag: use a one-row sample sheet or a config (or a ready-made --list-* file). Images use --image.
Mode 2 — Multi-sample (sample sheet)¶
A joint multi-sample run is a single-sample run with --samples samples.tsv in place of --in-dir. All rows share one --out-dir, so they train one joint FICTURE model. For the common case you only need id + in_dir:
1 2 | |
1 2 3 4 | |
For independent per-sample models, use --out-root instead of --out-dir; each row becomes its own <out_root>/<id>/. A sheet with a single row and --out-dir is a single-sample run.
The sample sheet is a wide table of input roles¶
Columns map to per-sample input roles. Every column is optional except that each sample needs a transcript source. Column names are case-sensitive; the listed aliases are accepted interchangeably.
| Column (aliases) | Role | Meaning |
|---|---|---|
id |
— | Sample identifier. Defaults to the in_dir / in_prefix basename; a lone --out-dir sample without an id is always rep1. |
in_dir |
— | Raw platform directory → the profile auto-detects roles inside it. |
in_prefix |
— | Raw platform path prefix → the profile auto-detects roles by suffix ({prefix}.tissue.gef, …); see BGI Stereo-seq. |
raw_transcript |
— | A raw transcript file to ingest (e.g. MERSCOPE detected_transcripts.csv, Xenium transcripts.csv.gz) through sge_convert. |
transcript (tsv) |
transcript | A pre-converted transcript TSV (the output of ingest) → skips ingest. Not for raw CSVs. |
xy (cell_xy) |
xy | Cell centroids file. |
boundaries (cell_boundary, cell_boundaries) |
boundaries | Cell boundary polygons. |
clusters |
clusters | External cluster labels. |
mex (mex_dir) |
mex | MEX directory. Or give the explicit triple mex_bcd / mex_ftr / mex_mtx when one directory does not apply. |
cellxgene (cell_by_gene) |
cellxgene | Cell×gene matrix CSV (e.g. MERSCOPE cell_by_gene.csv) → converted to a MEX that drives cell clustering (works without boundaries). Converted only for a sample that goes through ingest, and not on cosmx_smi / stereoseq. |
gef / cellbin_gef |
gef, cellbin_gef | Stereo-seq binary GEFs, when they do not match in_prefix + the standard suffix. |
cell_tsv |
cell_tsv | A standalone pixel TSV with a header row X Y gene count cell_id (columns read by name) that supplies cell counts on its own (Stereo-seq cell bins). |
dapi |
— | One DAPI OME-TIFF → a colorized dapi layer. A name ending in morphology.ome.tif (Xenium's z-stack, any prefix) is imported with --use-middle-page --high-memory. A value not ending in .ome.tif/.ome.tiff is imported without OME→PNG conversion and has no georeferencing source; give such images through --images with um_per_pixel instead. |
hne |
— | H&E image. On Visium HD it gets the profile's scale handling (see Visium HD); elsewhere it is a plain rgb layer, which needs an .ome.tif (scale read from its metadata) or, as on Seq-Scope, a profile image_defaults that supplies the bounds. Otherwise use --images with the georeferencing fields. Used as given (not resolved against in_dir) on Visium HD. |
tissue |
— | The sample's tissue, used by --anno-deep (falls back to --tissue). |
Other images are not sample-sheet columns — see Image Modalities. A config sample may also carry its own images list (JSON only).
Rules
- An explicit column overrides auto-detection for that role. The cell values
` (empty),-,., andNA` all mean unset. - Role columns,
dapi, and (except on Visium HD)hneare resolved againstin_dirwhen relative and not found as given;raw_transcriptis not — give it as an absolute path (or relative to the working directory). - Sheet columns are not validated on their own: a misspelled column (e.g.
transcripts) is ignored. The transcript-source check below lists unrecognized columns when it fails. (Config JSON samples are validated strictly; see Validation.)
Parquet inputs. raw_transcript, xy, boundaries and clusters may point at a .parquet file (Xenium ships transcripts.parquet, cells.parquet, cell_boundaries.parquet beside the .csv.gz files). Their consumers read CSV only, so each is converted to .csv.gz under OUT/tsv/<id>/parquet2csv/ with cartloader parquet_to_csv_rapid as the first ingest step — announced with a NOTE: at planning time — and every later stage uses the converted file. A failed or empty conversion aborts the run.
Transcript sources¶
Each sample gets its transcripts from exactly one source:
| Source | Applies to |
|---|---|
transcript (--in-transcript) — an already-ingested TSV; ingest is skipped |
every platform |
raw_transcript (--raw-transcript) — a raw CSV/TSV ingested by sge_convert |
platforms that ingest a transcript CSV: 10x_xenium, merfish, seqscope (raw per-molecule TSV), generic |
in_dir — the platform's raw directory |
10x_xenium, 10x_visium_hd, cosmx_smi, merfish, seqscope (the MEX directory); generic (a transcripts.tsv.gz inside it) |
in_prefix or a gef column |
stereoseq |
mex — the MEX directory |
illumina |
The source is checked before anything is planned: a sample with none, or one whose file is missing (including an in_dir without the platform's expected input), stops the run with an error naming each affected sample and listing any unrecognized sheet columns. The check is skipped when the ingest stage is not run (--only / --skip ingest), since a resumed run reuses the already-converted transcripts.
1 2 3 4 5 | |
An already-ingested transcript uses the layout ingest writes (transcripts.unsorted.tsv.gz): tab-separated, a header row X Y gene count (optionally a fifth cell_id column), coordinates in µm.
Column-name overrides¶
When input columns are non-standard, name them (CLI, or the ingest / roles blocks of the profile/--config). The CLI flags apply to every sample in the run:
--colname-transcript-x/-y/-feature/-count— the raw transcript's coordinate/gene/count columns (ingest.csv_colnames). Without a count column each row counts as 1.--colname-xy-cell/-x/-y— the xy file's columns (roles.xy; use--colname-xy-cell ''for an unnamed index column).--colname-boundary-cell/-x/-y— the boundary file's columns as read byspatula tsv-add-cell-id(roles.boundaries; MERSCOPE, Illumina).
Boundary files for polygon rendering
The cell-polygon layer is built by run_cartload2 → run_boundaries2pmtiles, which expects a comma-separated file whose first three columns are cell_id, vertex_x, vertex_y (vertices grouped by cell, µm). The --colname-boundary-* overrides do not reach this step.
Transcript that already carries a cell_id column (rare)
If your raw transcript CSV already has a per-molecule cell-id column, name it with
--colname-transcript-cell <name> (or ingest.csv_colname_cell in --config).
The column is carried through ingest to transcript column 5 and used directly for
cell analysis, skipping spatula tsv-add-cell-id. A cellxgene MEX, if also
present, still drives the clustering.
FICTURE mode (de-novo vs. projection)¶
Independent of how inputs are specified, the CLI selects the base FICTURE work. Exactly one mode is the base (a config JSON can add more analyses on top).
Train new LDA models. --width and --n-factor accept comma lists → the cross-product is trained (multiple widths supported). They override the width / factor count of the profile's training entry; either alone keeps the profile's value for the other.
1 2 | |
Reuse already-trained models — no LDA training runs. Point --project-models at one or more existing FICTURE directories; run_together reads each ficture.params.json and re-projects every model it lists onto the current data (at --width if given, else each model's training width). The profile's training entry is dropped.
1 2 | |
Ingest still runs (the data is current); only training is skipped.
Host a dataset with no FICTURE at all — transcripts, the SGE raster, and histology, with no factor layers. --no-ficture runs only FICTURE's tiling step (run_ficture2_multi --prepare-only), and packaging reads the resulting tiled TSV directly.
1 | |
Applies to every platform. Cell analyses are skipped too (they decode against a model). Cannot be combined with --n-factor or --project-models. The hexagon files are still built alongside the tiles (at --width, else the profile's width, else 12), so adding factors later re-uses them instead of re-tiling — rerun without --no-ficture in the same --out-dir.
Cell analyses decode against the model with the largest factor count unless an analysis names its own model_id.
Hexagon MEX export (any mode): --segment-10x additionally writes each sample's hexagon file as a 10x MEX directory, fic/samples/<id>/<id>.hex_<width>.mex/ (barcodes.tsv.gz with hexagon centers as x:y, features.tsv.gz, matrix.mtx.gz). It converts the very hexagon files the factor analysis uses (same --min-ct-per-unit-hexagon filter), so the two are consistent. By default every analysis' --width is exported; --segment-width-10x 12,24 picks the widths instead (extra widths get their hexagon files built too). Works with --no-ficture — the way to get hexagon MEX files without any factor analysis, e.g. for Seq-Scope:
1 2 | |
Config equivalent: top-level "segment_10x": true or { "widths": "12,24" } (a CLI flag wins). The directories are recorded under mex in the per-sample ficture.params.json and in ficture.multi.params.json; see run_ficture2_multi --segment-10x.
Tiling (run-wide, rarely needed): --tile-size and --tile-buffer are forwarded to run_ficture2_multi (punkst multisample-prepare) and otherwise keep its defaults of 500 µm and 1000 lines. punkst rejects a tile size under 20× the hexagon side length (width / √3) and recommends 50–100×, so only a wide hexagon needs this — e.g. --width 100 wants roughly --tile-size 5000. The buffer is a per-tile line buffer, not a spatial size. Config equivalents: top-level "tile_size" / "tile_buffer" (a CLI flag wins).
Common decode overrides (else profile / built-in default): --exclude-feature-regex, --include-feature-list / --exclude-feature-list, the --ingest-*-feature-* family, --min-ct-per-unit-hexagon (default 50), --min-ct-per-unit-train, --cell-min-cell-count / --cell-min-feature-count, and --always-single-molecule / --never-single-molecule (default: single-molecule ON for pixel FICTURE, OFF for cell decode). For these, an explicit CLI flag wins over a --config/profile value, which wins over the built-in default. Settings that do not follow that order: resources.n_jobs / resources.threads in a config win over -j / --threads (see Mode 3), and --units-per-um has no effect on seqscope or 10x_visium_hd (see Coordinate units).
Feature filtering: two independent layers¶
Feature filters come in two flavours that do not interact. Each takes a regex and/or a plain text file of feature names (one per line), and each has a default that applies to every platform:
| default regex | rationale | |
|---|---|---|
| ingest | ^(Unassigned|Neg|BLANK|Blank|Intergenic|Deprecated|System|NCS-|NCP-) |
technical artifacts — not genes, so they never enter the data |
| analysis | ^(Gm[0-9]|MT-|mt-|Rps|Rpl) |
real genes that distort a factorization — kept in the data, kept out of the models |
Pass '' to either flag to disable its default; a profile or --config value overrides it.
1. Analysis (FICTURE) filters — --include-feature-list / --exclude-feature-list / --exclude-feature-regex. These restrict the factor model only (lda4hex --features); the data — counts, pseudobulk, DE — keep every gene. --include-feature-list is the natural place for a highly-variable-gene set: the model is built on those genes, but all genes are still emitted afterwards.
| stage | affected |
|---|---|
| ingest, tiled transcripts, feature list, packaged tiles | no — every gene is kept |
| pixel FICTURE: the LDA/projection model (and hence pixel decoding, which reads that model) | yes |
| cell clustering: the LDA is a projection onto the pixel model, so it inherits the same restriction | yes (via the model) |
| cell counts, pseudobulk, DE | no — excluded/non-HVG genes stay in and reappear here |
A list and the regex combine: the regex narrows what the list leaves. The features the pixel model was trained on are written to fic/multi.selected_features.tsv and recorded per model as feature in ficture.params.json.
Because the restriction lives in the model (not the counts), the cell pseudobulk and DE report every gene, and the pixel decode — which reads the restricted model — reports only the model's genes. That asymmetry is intentional: the pixel decode is the model, the cell pseudobulk is an independent aggregate of the raw counts.
2. Ingest filters — --ingest-include-feature-list / --ingest-exclude-feature-list / --ingest-include-feature-regex / --ingest-exclude-feature-regex. These drop features from the transcript TSV as it is written, so a filtered feature is gone from everything downstream: the feature list, the packaged tiles, the browser's gene list and every analysis. Use them for features that should not be part of the dataset at all (negative-control probes, blanks); use the analysis filters for features that should be visible but not drive the factorization.
The ingest regex always replaces sge_convert's per-platform default (e.g. Xenium's negative-probe pattern), so one pattern governs every platform.
- Applied by whichever step writes the transcript:
sge_convert,reformat_cosmx(CosMx), and the Stereo-seq cell-bin conversion. - Also applied to the cell count matrices (
mex2sptsv/pixel2sptsv), so a MEX-derived cell source (acell_by_genematrix or an externalmexrole) — which never passes throughsge_convert— drops the same technical artifacts. This is the only feature filter on the cell counts; the FICTURE filters deliberately are not applied there (see above), so the cell pseudobulk keeps every real gene. - Ignored, with a warning, for a sample that supplies an already-ingested
transcript— that file is used as given. Filter it beforehand, or supply the raw input. - On the MEX-based platforms (
10x_visium_hd,seqscope,illumina) filtering happens insidespatula convert-sge, which accepts only one include-type and one exclude-type filter; a list and a regex of the same polarity is an error there. Resolve them into one list withcartloader feature_select.
Count thresholds and the analysis filter
--min-ct-per-unit-hexagon is applied over all genes, while the model is fit over the restricted set, so restricting to a small panel leaves hexagons whose surviving counts are low; --min-ct-per-unit-train, counted over the features the model uses, is the threshold to lower. The cell counts are not restricted by the analysis filters (only by the ingest filters), so --cell-min-cell-count counts over every gene that survived ingest; it applies to cells built from a transcript or cell_tsv, not to MEX-derived cells. Ingest filters run before any counting.
Coordinate units at ingest¶
--units-per-um <n> tells ingest how many coordinate units of the raw input make one micron — the factor sge_convert divides the input X/Y by. 1 means the input is already in microns, 1000 means nanometers, 2 is Stereo-seq's 500 nm bins. Everything downstream of ingest is in microns, so this is the one place the input's unit convention is declared.
Normally you never set it: each platform's ingest preset knows its own convention. Set it when a dataset departs from that convention — notably Illumina StrataMap, which ships two barcode formats:
| Barcode | Units | --units-per-um |
|---|---|---|
SBC:433503:2393851 (older) |
nanometers | 1000 |
SBC:686.951:4668.15 (current) |
microns | 1 |
Ingest detects which of the two a StrataMap barcode file uses (a fractional coordinate means microns; otherwise the coordinate magnitude decides) and reports the value it picked, so both formats run correctly with no flag. --units-per-um overrides the detection; if the value you give contradicts the file, the run warns and uses yours.
- Applied by
sge_convert, in both of its routes (MEX viaspatula convert-sge, CSV viasge_format_generic), so it covers every platform whose ingest issge_convert. Onstereoseqit also scales the cell-bin TSV, keeping the pixel and cell coordinates on one system. - Not supported on
cosmx_smi, whose ingest (reformat_cosmx) writes the transcript TSV itself. Asking for it there is an error. - No effect on
seqscopefrom the CLI oringest.units_per_um: the profile'singest.extra_flagsalready contains--units-per-um 1000, which comes later on thesge_convertcommand line and takes precedence. To change it, replaceingest.extra_flagsin a config (see the Seq-Scope page). - No effect on
10x_visium_hd:sge_convertreplaces it with the value derived frommicrons_per_pixelin the scale factors JSON (--scale-json) that the profile passes. - Ignored, with a warning, for a sample that supplies an already-ingested
transcript— that file is used as given, in microns. - Boundary/centroid files are not rescaled by this flag: they must already be in microns (see the platform pages).
1 2 | |
The config equivalent lives in the ingest block (a CLI --units-per-um wins over it):
1 | |
Coordinate jitter at ingest¶
--jitter-xy <um> adds a uniform random offset in [-um, +um] to each transcript's X and Y — drawn independently per transcript and per axis — as the transcript TSV is written. It is off by default (0).
Use it on coarse-resolution platforms whose molecules sit on a lattice rather than at measured positions. On 10x Visium HD, for example, every transcript in a 2 µm bin carries that bin's single coordinate, so the transcript cloud is a grid of stacked points; hexagon binning, pixel decoding and the rendered tiles all see the lattice. Jittering by roughly half the bin pitch (--jitter-xy 0.8 for 2 µm bins) spreads each bin's molecules across the area they came from.
Like the ingest feature filters, this rewrites the data itself: the jittered coordinates are what every later stage reads — hexagons, FICTURE, the packaged tiles, the browser.
- Applied by
sge_convert, in both of its routes:spatula convert-sgefor MEX input (10x_visium_hd,seqscope,illumina) andsge_format_genericfor CSV input (10x_xenium,merfish,stereoseq's bin1 GEM,generic). Jitter is in microns, applied after the input's units are converted. - Not supported on
cosmx_smi, whose ingest (reformat_cosmx) writes the transcript TSV itself. Asking for it there is an error, not a silently dropped flag. - On
stereoseqit covers the bin1 pixel transcript only; the cell-bin TSV (convert_stereoseq_cellbin) has no jitter option and stays on the original grid. The run warns when you ask. - Ignored, with a warning, for a sample that supplies an already-ingested
transcript— that file is used as given.
1 | |
The config equivalent lives in the ingest block (a CLI --jitter-xy wins over it):
1 | |
Mode 3 — Full config (JSON)¶
Escalate to --config run.json when samples need different settings, or to add analyses/images beyond the profile defaults. Everything a run can express reduces to one canonical, list-based configuration that the three layers (profile → CLI → JSON) assemble:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Publishing (annotation + S3 upload) is not part of this config — it is driven entirely by CLI flags (see Overview → Publishing).
Top-level keys¶
Dict values are deep-merged into the profile; other values replace it, except the three lists merged by id (next section).
| Key | Meaning |
|---|---|
platform, out_dir, out_root, saw, colname_cell |
As --platform, --out-dir, --out-root, --saw, --colname-cell (the CLI wins). |
samples |
Sample entries (below), added to any --samples rows and the single-sample CLI sample. |
exclude_feature_regex, include_feature_list, exclude_feature_list |
Analysis feature filters (the CLI wins). |
ingest_include_feature_regex, ingest_exclude_feature_regex, ingest_include_feature_list, ingest_exclude_feature_list |
Ingest feature filters (the CLI wins). |
cell_lists |
Run-wide ready-made --list-* files, role → path (a --list-* flag wins per role). |
ingest |
Ingest settings (below). |
roles |
Per-role auto-detection and column settings (below). |
cartload |
use_pmpoint, sge_scale, bin_count (--bin-count wins). |
resources |
n_jobs, threads — passed to every command; wins over -j / --threads (make itself still runs with the CLI -j). |
ficture_defaults / cell_defaults |
Defaults merged into every ficture / cell_analyses entry (per-entry keys win). |
ficture, cell_analyses, images |
Lists merged by id (below). |
segment_10x, tile_size, tile_buffer |
As --segment-10x / --segment-width-10x, --tile-size, --tile-buffer. |
image_defaults |
Fallback image settings; see Image Modalities. |
image_transform |
{ "column": ..., "flag": ... }: the platform transform column of image rows (MERSCOPE: merfish_csv → --micron2pixel-csv). |
hne |
Settings for a sample's hne image (Visium HD profile: georef_plain, um_per_pixel_json, um_per_pixel_key, out_id). |
squares |
Visium HD square-bin imports, a list of { "subdir", "bin_size", "suffix" }. |
cell_import |
Visium HD segmented-cell import, { "detect_dir", "suffix" }. |
publish |
Accepted but not read (publishing is CLI-only). |
Sample entries accept id, in_dir, in_prefix, raw_transcript, the role keys and their aliases (transcript/tsv, xy/cell_xy, boundaries/cell_boundary/cell_boundaries, clusters, mex/mex_dir or mex_bcd+mex_ftr+mex_mtx, cellxgene/cell_by_gene, cell_tsv, gef, cellbin_gef), dapi, hne, tissue, and images — a list of image entries in the config JSON form that take precedence over the profile's entries with the same id.
ingest keys:
| Key | Meaning |
|---|---|
method |
sge_convert (default), reformat_cosmx, or stereoseq. |
sge_platform |
sge_convert --platform (default: the profile name). |
units_per_um, jitter_xy |
As --units-per-um, --jitter-xy (the CLI wins). |
autodetect |
List of { "file", "flag" }: raw transcript candidates under in_dir; the first that exists is used. |
inputs |
Flag → path under in_dir (sge_convert), or flag → glob (reformat_cosmx; null drops that input). |
input_roles |
Flag → role whose path is passed (Illumina: --in-mex ← mex). |
in_dir_flag |
Flag that receives in_dir itself (Seq-Scope: --in-mex); skipped when the sample has a raw_transcript. |
raw_input_flag |
Flag that receives raw_transcript (default --in-csv). |
produces |
reformat_cosmx: output suffix per role (transcript, xy, boundaries). |
csv_colnames |
{ "x", "y", "feature", "count" } raw transcript columns (the --colname-transcript-* flags). |
csv_colname_cell |
As --colname-transcript-cell. |
csv_colnames_others |
Extra raw columns carried into the transcript TSV (Xenium: cell_id, z_location, …). |
assign_cell_id |
true, or { "expand_um", "colname_x", "colname_y" }: run spatula tsv-add-cell-id for samples with boundaries (colname_x/colname_y are the transcript's columns, default X/Y; expand_um assigns an outside-all-cells transcript to the nearest cell within that distance). |
cellxgene_blank_prefix |
convert_cellxgene --blank-prefix (its default: Blank). |
extra_flags |
Raw flags appended to the ingest command (for Stereo-seq, the bin1 sge_convert). Lists are replaced, not merged. |
gef_suffix |
Stereo-seq: only shown in error messages (the detected suffix is roles.gef.suffix). |
feature_file |
Stereo-seq: the feature file the cell-bin conversion checks against (default feature.clean.tsv.gz). |
roles — one entry per role: file (auto-detect at this path under in_dir) or suffix (auto-detect at in_prefix + suffix), and colname_cell / colname_x / colname_y (xy: passed to the cell decode; boundaries: read by tsv-add-cell-id). A boundaries entry may also set format (geojson: derive cell centroids from the polygons), cell_id_format, cell_id_prop, units_key, and units_json (scale JSON under in_dir) — see the Visium HD profile.
Validation of config keys¶
A misspelled key would otherwise be merged in and never read, so --config is checked before planning; any of the following aborts the run with the list of recognized keys:
- an unrecognized top-level key (e.g. a top-level
csv_colnames, which belongs underingest); - an unrecognized key in a sample entry, or in the closed-schema blocks
ingest,cartload,resources,image_defaults, andsegment_10x; - a sample role the platform cannot consume (e.g.
cell_tsvon10x_xenium) — usually a wrong--platformor a leftover column.
--allow-unknown-config-keys downgrades all of these to "ignore and continue". Open maps (roles, hne, image_transform, cell_import, squares, publish, per-entry list fields), --platform-json, and sample-sheet columns are not checked.
List assembly rule (append-by-default, keyed by id)¶
For ficture, cell_analyses, and images, JSON entries are merged into the profile/CLI-derived list:
ficture,cell_analyses: an entry with a newidis appended; one reusing an existingidis deep-merged into it.images: an entry replaces every profile entry with the sameid(profiles may list several same-idfallbacks, e.g. Xenium'sdapi); new ids are appended.{ "replace": [ ... ] }discards the base list entirely;{ "add": [ ... ] }is the same as a plain list.
This is what lets you set the base on the CLI and add only the extras in JSON:
1 2 | |
1 2 3 4 5 6 | |
ficture analyses¶
Each entry is either de-novo or a projection:
1 2 | |
| Key | Meaning |
|---|---|
id |
Entry id. A de-novo entry produces models t<width>_f<n_factor>; a projection's model id is its id. |
mode |
train (default) or project. |
width, n_factor |
Comma lists; de-novo trains every combination. On a projection, n_factor only informs which model is the default for cell analyses (largest wins). |
model |
Projection: path to the trained *.model.tsv. |
min_ct_per_unit_hexagon, min_ct_per_unit_train, decode_scale |
Per-analysis run_ficture2_multi parameters. |
alias |
A factor-label file copied beside the factor as <id>-alias.tsv (_ → - in the id) and recorded under the factor's alias key. The entry's id must be the catalog's factor id, so this is for projection entries; the file is copied as given. |
ficture_defaults (e.g. decode_scale, min_ct_per_unit_hexagon, min_ct_per_unit_train) apply to every analysis, including projections; per-entry keys win. cell_defaults does the same for cell_analyses entries (min_cell_count, min_feature_count).
cell_analyses¶
Cell-level decode is platform-default and automatic: an analysis runs whenever a sample provides its required roles. A sample contributes when it has every role in uses and (if present) at least one role in any_uses; roles in optional_uses are added to the decode when available.
1 | |
| Key | Meaning |
|---|---|
id |
Analysis id; names the factor in the catalog. |
uses / any_uses / optional_uses |
Required (all) / alternative (at least one) / optional roles. The pseudo-role tx_cell_id matches a sample whose transcript already carries a cell_id column. |
require_all |
Run only when every sample in the group contributes. |
generic_cell |
generic platform: run from --colname-cell or from a mex present in every sample (not both); see Generic. |
multi_import |
On joint runs, import per sample with this command instead of decoding jointly (Xenium: import_xenium_cell). |
model_id |
FICTURE model to decode against (default: the largest-factor model). |
min_cell_count, min_feature_count |
Per-analysis run_ficture2_multi_cells thresholds (else cell_defaults, else --cell-min-*). |
lists |
Ready-made --list-* files for this analysis, role → path (see below). |
extra_flags |
Raw flags appended to this analysis's run_ficture2_multi_cells call (e.g. ["--zero-based-clust-id"], ["--tsne"]). |
name |
Display name in the catalogs (below). |
alias |
Companion cluster-label file (below). |
any_uses lets an analysis accept alternative cell-count sources — e.g. MERSCOPE runs cell analysis from either boundaries or a cellxgene MEX, and a mixed joint run (some samples with boundaries, some with a MEX) is resolved per sample and packaged from one call. See the MERSCOPE page for the source-precedence rules.
A multi_import analysis (e.g. Xenium's xeniumranger → import_xenium_cell) relies on sample-specific cluster labels: on a single-sample run it goes through run_ficture2_multi_cells as usual; on a joint run it is imported per sample in the images stage instead (sheet-provided xy/boundaries/clusters paths are forwarded as --csv-* overrides). See the Xenium page.
TSNE manifolds are not generated by default (only UMAP is; nothing downstream reads TSNE, and it is slow on large datasets). To add them for an analysis, pass "extra_flags": ["--tsne"].
name sets the factor's human-readable name: in catalog.yaml and multi-catalog.yaml — the label shown for the layer. The factor id is unchanged (it still names every file and asset key), so this is purely cosmetic:
1 | |
Without it, a cell analysis displays its bare id (published), and the multi-catalog's cell factors carry no name at all. The name is written after packaging, into the shared multi-catalog and every contributing sample's catalog. Plain text only — quotes, $, backticks, backslashes and newlines are rejected up front, since the name travels through a generated make recipe. Unrelated to alias, which points a factor at a companion factor-label TSV.
alias names a companion cluster-label file for the analysis — one label per cluster id:
1 2 | |
1 2 3 4 | |
Two columns, cluster id then label, with an optional header; tab-, comma- or whitespace-separated (a label may contain spaces unless the file is comma-separated). The ids use the same numbering as the analysis's cluster files: 1-based for supplied cluster labels, unless the analysis passes --zero-based-clust-id in extra_flags, in which case they are 0-based. A Leiden analysis clusters on demand, so its alias ids are 0-based, matching the packaged output. At planning time the file is validated (integer ids at or above the base, no duplicates, non-empty labels) and rewritten to the packaged layout (index<TAB>alias, 0-based) as <out_dir>/tsv/alias.<analysis_id>.tsv. After packaging it is deployed as <analysis_id>-alias.tsv and recorded under the factor's alias key in the multi-catalog and every contributing sample's catalog. A factor that carries alias is skipped by the AI annotation stage (--anno / --anno-deep), so curated labels are not overwritten.
Supplying your own --list-* files¶
By default run_together derives each --list-* file that run_ficture2_multi_cells consumes, writing <out_dir>/tsv/in_<role>.<analysis_id>.tsv from the samples' resolved roles. To supply one yourself instead — most often externally assigned cell clusters, since without --list-cluster the cells stage computes Leiden clusters on demand — name it per role, either run-wide or per analysis:
| role | flag it feeds | CLI flag | line format |
|---|---|---|---|
clusters |
--list-cluster |
--list-cluster |
SAMPLE_ID<TAB>CLUSTER_FILE |
xy |
--list-xy |
--list-xy |
SAMPLE_ID<TAB>XY_FILE |
boundaries |
--list-boundaries |
--list-boundaries |
SAMPLE_ID<TAB>BOUNDARY_FILE |
mex |
--mex-list |
--list-mex |
SAMPLE_ID<TAB>MEX_DIR (or a bcd/ftr/mtx triple) |
cell_tsv |
--tsv-list |
--list-cell-tsv |
SAMPLE_ID<TAB>CELL_TSV |
1 2 3 | |
1 2 3 4 5 6 7 | |
A named list is passed verbatim (no file is generated for that role) and:
- satisfies that role's gating — no sample has to carry the role on disk, and the role need not appear in the analysis's
usesat all, so a cluster list can be attached to an analysis that would otherwise cluster on demand; - is validated at plan time — unknown role name, missing file, empty file, and a first column matching none of the run's sample ids are hard errors; partial coverage and ids outside the run are warnings. The first column must use the run's sample ids (e.g.
rep1for a lone--out-dirsample without--id); - does not change
multi_importrouting — that path is per-sample by nature, so on a joint Xenium run attach the list to the jointly decodedcartloaderanalysis, andxeniumrangerkeeps its per-sample import.
Cluster ids are read as 1-based and decremented; for 0-based labels add "extra_flags": ["--zero-based-clust-id"].
See also¶
run_togetherOverview — the pipeline, stages/resume, publishing, output.- Image Modalities — how to attach DAPI/H&E/protein images.
- Supported Platforms and the per-platform pages.
- Guides: single sample, multiple samples.