Multi-Sample Spatial Factor Inference Analysis with FICTURE¶
Overview¶
run_ficture2_multi runs a joint FICTURE analysis across samples. It tiles each sample, builds joint hexagons (one or more widths), trains LDA models across samples per (width, factor count) — or projects a pre-trained model — then projects and pixel-decodes each sample, and writes per‑sample and shared JSON manifests.
Use it to learn shared spatial factors across samples and generate per‑sample outputs in a single, parallelizable Makefile. It also works with a single sample.
Usually run for you
run_together calls run_ficture2_multi for every FICTURE analysis (single- or multi-sample, de-novo or projection, and --prepare-only for --no-ficture). Use this page to run it directly in step-by-step or custom workflows.
Requirements¶
--in-list: a headerless, tab-delimited file with one line per sample:<sample_id>and the path to its transcript‑indexed SGE TSV (no blank or comment lines). Each transcript TSV has one header line; by default its first four columns are X, Y, feature, count (the unified SGE format).punkst:--ficture2must point to a repository containingbin/punkstandext/py/factor_report.py(default: the submodule<cartloader_dir>/submodules/punkst).spatula(default:<cartloader_dir>/submodules/spatula/bin/spatula),gzip,sort, andpython3.- R (
Rscripton thePATH) for the UMAPs, unless--skip-umapor--prepare-only. cartloaderon thePATH(the Makefile callscartloader feature_selectandcartloader write_json_for_ficture2_multi).
Actions¶
All actions run by default (UMAPs can be skipped with --skip-umap):
- Tiling: tiles each sample (
punkst multisample-prepare) and writes the per-sample and shared feature lists. - Hexagons: builds per-sample and joint hexagons at each
--width. - Feature selection (only with a feature filter): resolves the filters into
multi.selected_features.tsv. - LDA training: trains a joint model for each (
--width,--n-factor) pair, or projects--pretrained-modelonto the joint hexagons; writes DE and a factor report. - Projection: projects each model onto every sample's hexagons.
- UMAP: shared and per-sample UMAPs of the hexagon factor posteriors.
- Decode: pixel-level decoding of each sample with each model, with pseudobulk, DE, a factor report, and an image.
- Manifests: writes
samples/<sample>/ficture.params.jsonandficture.multi.params.json. - Hexagon MEX export (optional,
--segment-10x): converts each per-sample hexagon file into a 10x MEX directory.
--prepare-only stops after the hexagons: it writes each sample's ficture.params.json with only in_sge (tiled prefix, feature list, coordinate range) and an empty train_params. No model is trained, projected, or decoded, no UMAP is built, and feature filters are ignored; --n-factor is not required. This is what lets a dataset be packaged without any factor analysis — run_cartload2 reads the tiled TSV as its molecule source, so it produces transcripts + raster + images and a catalog with no factor layers. Re-running without --prepare-only in the same --out-dir adds models later and re-uses the existing tiles/hexagons. See run_together --no-ficture.
--segment-10x additionally exports every per-sample hexagon file as a 10x MEX directory, samples/<sample>/<sample>.hex_<width>.mex/ (barcodes.tsv.gz, features.tsv.gz, matrix.mtx.gz), via spatula sptsv2mex. The MEX is built from the very same samples/<sample>/<sample>.hex_<width>.txt/.json that the factor analysis uses — the hexagons are neither re-generated nor re-filtered, so the MEX contains exactly the hexagons that survive --min-ct-per-unit-hexagon. Barcodes are the hexagon centers as x:y (µm); features carry the gene name as both id and name, typed Gene Expression. By default every --width is exported; --segment-width-10x picks the widths instead (a width not in --width is simply added to the hexagon step, so its hexagon files get built too). The export depends only on the hexagon step, so it also works with --prepare-only — the way to get hexagon MEX files without any factor analysis. Each exported directory is recorded under mex (keyed by width) in the per-sample ficture.params.json and in ficture.multi.params.json (keyed by sample, then width).
Reruns and done flags¶
Re-invoking the command with unchanged inputs leaves the tiles, hexagons, and every model downstream of them alone:
- Tiling is tracked by
multi.tiles.done, which depends onmulti.tiles.params.json(sample IDs and transcript paths, column indices, tile size/buffer) and on the transcript files, so a re-ingested sample is re-tiled. - Each hexagon width is tracked by
multi.hex_<width>.done, which depends onmulti.hex_<width>.params.json(ordered sample list, width,--min-count-per-sample,--min-ct-per-unit-hexagon). - Feature selection depends on
multi.selected_features.params.json(thefeature_selectcommand) and on the list files.
A settings file is rewritten only when its content changes, so a changed setting, a changed sample list, or a new width reruns that step and everything built from it; a step whose outputs are missing reruns too. A changed sample list rebuilds every sample's tiles and hexagons. An output directory prepared by an older version (a single multi.done flag and no settings files) is adopted as up to date when its outputs exist and are not older than their inputs.
Feature filters¶
--include-feature-list, --exclude-feature-list, --include-feature-regex, and --exclude-feature-regex restrict the features that LDA training and projection use:
- They are resolved by
cartloader feature_select(--mode include) againstmulti.union_features.tsv(every feature seen in any sample) intomulti.selected_features.tsv, and the command is recorded inmulti.selected_features.params.json. - That list is passed as
lda4hex --featuresto the joint training and to every per-sample projection; the pixel decode inherits the restriction through the model. Each sample'sficture.params.jsonrecords it as the FICTURE feature file. - Tiling, the per-sample and shared feature lists, and the packaged genes keep every feature.
- Regexes use substring semantics (Python
re.search); a list and a regex combine. Listed names absent from the data are ignored, and an empty selection is an error. Filters are ignored with--prepare-only. --min-ct-per-unit-hexagoncounts all features, so when restricting to a small panel consider lowering--min-ct-per-unit-train, which counts only the selected features.
Example Usage¶
De-novo training:
1 2 3 4 5 6 7 8 | |
Projection of an existing model (no training):
1 2 3 4 5 6 | |
Parameters¶
Input/Output¶
--in-list(str, required): Sample list (see Requirements).--out-dir(str, required): Output directory.--out-json(str): Accepted but currently unused; the manifests are alwayssamples/<sample>/ficture.params.jsonandficture.multi.params.json.
Tiling / Hexagons¶
--width(str, required): Comma‑separated hexagon flat-to-flat widths in µm (e.g.,12,18).--colidx-x,--colidx-y,--colidx-feature,--colidx-count(int, 1‑based): X, Y, feature and count columns of the transcript TSV (defaults: 1, 2, 3, 4).--tile-size(int): Tile size (default: 500).--tile-buffer(int): Per-tile buffer size (default: 1000).--min-count-per-sample(int): Minimum total count for a feature to enter the shared feature listmulti.features.tsv(punkst --min-total-count-per-sample; default: 50).--min-ct-per-unit-hexagon(int): Minimum count per hexagon, over all features (default: 50).--prepare-only(flag): Tile and build hexagons only; write manifests with no models (--n-factornot required, UMAP forced off).--segment-10x(flag): Also export each per-sample hexagon file as a 10x MEX directory (samples/<sample>/<sample>.hex_<width>.mex/). Works with--prepare-only.--segment-width-10x(str): Comma‑separated widths (µm) to export with--segment-10x(default: the--widthlist); only valid with--segment-10x. Extra widths are added to the hexagon step.
Training / Projection¶
--n-factor(str): Comma‑separated factor counts (e.g.,12,24). Required unless--pretrained-modelor--prepare-only; not allowed with--pretrained-model. Every (width, factor count) pair is trained as modelt{width}_f{n_factor}.--pretrained-model(str): A model TSV (feature by factor, headerFeature 0 1 ...) to project instead of training; its factor count is read from the header.--retrain(flag): With--pretrained-model, use it as the prior and continue training instead of projecting only.--model-id(str): Name of the model in place oft{width}_f{n_factor}; only valid for a single model.--min-ct-per-unit-train(int): Minimum count per hexagon during training/projection, counted over the selected features (default:punkst's default).--minibatch-size(int): Minibatch size (default: 500).--train-epoch(int): Number of training epochs (default: 2).--seed(int): Random seed (default: 1).--cmap-file(str): Color map TSV; its firstn_factorcolors are used (default:<cartloader_dir>/assets/default_color_map.tsv).--skip-umap(flag): Skip the UMAPs.- Feature filters:
--include-feature-list,--exclude-feature-list,--include-feature-regex,--exclude-feature-regex(see Feature filters).
Decoding / DE¶
--anchor-res(int): Anchor resolution; the decode useswidth / anchor_ressliding moves (default: 6).--decode-pixel-res(float): Pixel resolution (µm) of the decode (default: 0.5).--single-molecule(flag): Decode each molecule instead of pixels at--decode-pixel-res.--decode-scale(int): Scale from coordinates to pixels of the decode PNG (default: 1).--de-min-ct-per-feature(int): Minimum count per feature for differential expression (default: 20).--de-max-pval(float): P-value cutoff for differential expression (default: 1e-3).--de-min-fold(float): Fold-change cutoff for differential expression (default: 1.5).
Run Options¶
--dry-run(flag): Write the Makefile and print the commands only.--restart(flag): Ignore existing outputs and rerun all steps.--threads(int): Max threads per job (default: 8).--n-jobs(int): Parallel Makefile jobs (default: 2).--makefn(str): Makefile name under--out-dir(default:run_ficture2_multi.mk).
Environment / Tools¶
--ficture2(str): Path to thepunkstrepository (default:<cartloader_dir>/submodules/punkst).--spatula(str): Path tospatula(default:<cartloader_dir>/submodules/spatula/bin/spatula).--gzip(str): Path togzip; considerpigzfor speed (default:gzip).--sort(str): Path tosort(default:sort).--python(str): Python 3 used forpunkst's factor report (default:python3).--R(str): R binary checked unless UMAPs are skipped (default:R); the UMAP scripts run withRscriptfrom thePATH.
Temporary files
multisample-prepare uses <out-dir>/tmp; lda4hex uses <out-dir>/<model_id>_lda4hex (joint) and samples/<sample>/<sample>.<model_id>_lda4hex (projection); pixel-decode uses <out-dir>/tmp/<sample>_<model_id>_pixel. The UMAP R scripts run with TMPDIR set to <prefix>_create_umap, <prefix>_draw_umap and <prefix>_draw_umap_single, where <prefix> is <out-dir>/<model_id> (shared) or samples/<sample>/<sample>.<model_id> (per sample). These directories are removed when their step finishes.
Output¶
Outputs are written under --out-dir:
-
Tiling and hexagons (joint):
multi.union_features.tsv: Every feature seen in any sample, with its total and per-sample counts.multi.features.tsv: Shared feature list.multi.hex_<width>.txtandmulti.hex_<width>.json: Joint hexagons and metadata per width.multi.tiles.done,multi.tiles.params.json,multi.hex_<width>.done,multi.hex_<width>.params.json: Done flags and their settings files (see Reruns and done flags).multi.selected_features.tsvandmulti.selected_features.params.json: With feature filters only.
-
Per sample, in
samples/<sample>/:<sample>.tiled.tsv,.tiled.index,.tiled.coord_range.tsv,.tiled.features.tsv: Tiled transcripts (read by packaging).<sample>.hex_<width>.txtand.json: The sample's hexagons.<sample>.hex_<width>.mex/: 10x MEX export (--segment-10x).
-
Joint LDA (per width × factor count), prefix
<model_id>(defaultt{width}_f{n_factor}):.model.tsv: Feature-by-factor weights..results.tsv.gz: Factor posteriors of the joint hexagons, with top factor columns..cmap.tsv: Factor colors..bulk_chisq.tsv: Per‑factor differential expression..factor.info.tsvand.factor.info.html: Factor summaries..umap.tsv.gz,.umap.png,.umap.single.prob.png: Shared UMAP (unless--skip-umap).
-
Per-sample projection, prefix
samples/<sample>/<sample>.<model_id>:.results.tsv.gz: Factor posteriors of the sample's hexagons..umap.tsv.gz,.umap.png,.umap.single.prob.png: Per-sample UMAP (unless--skip-umap).
-
Per-sample decode, prefix
samples/<sample>/<sample>.<model_id>_pixel:.binand.index: Binary pixel-level decoding results and their index..pseudobulk.tsv.gz: Feature-by-factor posterior counts..bulk_chisq.tsv,.factor.info.tsv,.factor.info.html: Per‑decode DE and factor summaries..png: Image of the pixel-level factors.
-
Done flags:
<model_id>.done,<model_id>_summary.done,<model_id>_each.done,<model_id>_pixel_each.done,multi_json_each.done, and per-sample.doneflags. -
Manifests:
samples/<sample>/ficture.params.json: Per-sample manifest of the tiled SGE, models, projections, UMAPs and decodes, read byrun_cartload2. With--segment-10x, amexobject maps each exported width to its MEX directory.ficture.multi.params.json: Shared manifest (see below).
See run_ficture2 for the single‑sample file formats.
Multi-sample manifest¶
Alongside the per‑sample JSONs, run_ficture2_multi writes a top‑level ficture.multi.params.json that ties the run together. It (a) points to each per‑sample manifest by relative path, (b) records the shared components — the joint LDA models, shared UMAPs, and multi‑sample hexagon files — and (c) with --segment-10x, lists the per‑sample hexagon MEX directories under mex (sample → width → directory), so other tools (notably run_cartload2_multi) can discover the samples and shared assets without re‑deriving paths. All paths are relative to --out-dir, so the directory is self‑contained.
It is written when the Makefile is generated. Entries are merged by model_id into an existing manifest, so running once per model (e.g. several projections into the same --out-dir) accumulates all models; a --prepare-only run overwrites it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
Cell analyses¶
run_ficture2_multi_cells (the cell/segmentation‑based analysis) runs on the tiles of a run_ficture2_multi output directory and writes the analogous ficture.multi.<prefix>.params.json for each output prefix (e.g. ficture.multi.cartloader.params.json). It points to each samples/<sample>/ficture.<prefix>.params.json and records the shared cell components — shared cluster pseudobulk/DE/info, shared heatmap, and shared UMAP/TSNE manifolds — for whichever steps ran.