Skip to content

Cell Segmentation - #161

Draft
cavenel wants to merge 7 commits into
devfrom
segmentation
Draft

cavenel wants to merge 7 commits into
devfrom
segmentation

Conversation

@cavenel

@cavenel cavenel commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

This PR adds optional cell segmentation for Visium HD, closing #145. When a segmentation is given, cells replace bins as the analysis unit. The bin table is kept in the SpatialData object as <sample>_bin_table.

Cells can come from:

  • Space Ranger's own nucleus segmentation (--segmentation_method spaceranger).
  • Cellpose or StarDist run on the samplesheet image (--segmentation_method cellpose|stardist).
  • A segmentation in the new samplesheet column segmentation_file: GeoJSON or a label mask, in full-resolution pixels.

How the segmentation is used depends on the input:

  • Samples run through Space Ranger (FASTQ input): the segmentation file is given to Space Ranger with --custom-segmentation-file. Cellpose and StarDist masks are converted to GeoJSON first. Space Ranger then writes segmented_outputs, which the pipeline reads.
  • Samples with existing Space Ranger output (spaceranger_dir): Space Ranger's segmented_outputs are read, or the 2 µm bins are grouped into cells with bin2cell.

Other changes this needed:

  • Local modules move to the spatialdata 0.8 stack. Reading Space Ranger's segmented outputs needs spatialdata-io >= 0.7, which brings anndata 0.13 and pandas 3. The same commit holds the compatibility fixes for those: the ADATA_EXTEND layer count, the SDATA_UPDATE_TABLE reindex and nft-anndata 0.5.2.
  • Space Ranger's nucleus segmentation is turned off for Visium HD unless cells are requested, so segmented_outputs/ is no longer produced by default. This is a change in behaviour.
  • Per-sample steps get more memory for Visium HD-sized tables, and their time limit is capped at 4 h per attempt.
  • SDATA_READ_VISIUM and SQUIDPY_SPATIAL_NEIGHBORS now take a per-sample value in their input tuple (read_cells, coord_type) instead of reading it from meta. Cells always use generic coordinates.

Two nf-core modules are patched. I will open PRs on nf-core/modules for both and link them here:

  • stardist calls the StarDist API instead of stardist-predict2d. The CLI's --n_tiles takes two values, so it can't tile RGB (H&E) images, and an untiled full-size image runs out of memory. ext.args is passed on to predict_instances.
  • spaceranger/count gets an optional segmentation input.

The new modules only have stub tests, because the Visium HD test data is too sparse to segment. Every route was run on the full-size Visium HD Human Lung Cancer dataset except Cellpose, which needs a GPU at that size. Route-level pipeline tests will come with the full-size test profiles in #150.

The PR is large. The commits are kept separate so it can be reviewed one commit at a time.

PR checklist

  • This comment contains a description of changes (with reason).
  • If you've fixed a bug or added code that should be tested, add tests!
  • If you've added a new tool - have you followed the pipeline conventions in the contribution docs
  • Make sure your code lints (nf-core pipelines lint).
  • Ensure the test suite passes (nextflow run . -profile test,docker --outdir <OUTDIR>).
  • Usage Documentation in docs/usage.md is updated.
  • Output Documentation in docs/output.md is updated.
  • CHANGELOG.md is updated.
  • README.md is updated (including new tool citations and authors/contributors).

Reading Space Ranger's segmented outputs needs spatialdata-io >= 0.7, which
brings spatialdata 0.8, anndata 0.13 and a newer pandas. Move all local
modules to one image built on that stack, and fix what breaks under it:

- ADATA_EXTEND: anndata 0.13 reports an empty `layers` group as a single
  `None` key, so count only real keys.
- update_table: newer pandas rejects element-wise assignment of mixed
  values into a float64 column. Assign the whole column with rename/reindex.
- nf-test: nft-anndata 0.4.1 cannot read categoricals written by anndata
  0.13; update to 0.5.2.
Several per-sample steps carry process_single (6 GB), sized for classic
Visium. On Visium HD bins or segmented cells they are killed on the first
attempt. Give them more memory through a config selector, alongside the
existing one for the merged pre-processing steps.

These steps are retried for memory rather than time, so cap their time
limit too: escalating to 16 h makes retries hard to schedule.
- nf-core cellpose and stardist modules. The stardist module calls the
  StarDist API instead of stardist-predict2d, whose --n_tiles takes two
  values and so cannot tile RGB (YXC) images; untiled, a full-size H&E is
  killed for memory. Tile counts are derived from the image size.
- IMAGE_DOWNSCALE: optional downscaling of the tissue image.
- MASK_TO_GEOJSON: label mask to GeoJSON polygons in full-resolution
  pixels, classified as nucleus or cell.
- SDATA_BIN_TO_CELL: group 2 um bins into cells with bin2cell, for
  processed Space Ranger output.
- SEGMENTATION subworkflow tying the image steps together.
New --segmentation_method (spaceranger, cellpose, stardist) and a
samplesheet `segmentation_file` column. When either is given, cells
replace bins as the analysis unit; the bin table is kept in the
SpatialData object.

- Raw data: cellpose/stardist segment the tissue image and the result is
  passed to Space Ranger with --custom-segmentation-file. Whole-cell
  segmentations (cellpose) are not expanded.
- Processed data: Space Ranger's own segmentation is read, or bins are
  grouped into cells with bin2cell.
- Space Ranger's nucleus segmentation is turned off for Visium HD unless
  cells are requested.
- Segmentation runs at full image resolution by default; test profiles
  downscale, since their tissue image is full size.
- Input validation for segmentation on non-HD or incomplete output, and a
  clear error when no cell table or no cells are produced.
- Spatial neighbours use generic coordinates for cells.
Regenerated with nf-test 0.9.4 and Nextflow 25.10.4, as used in CI. Most
changes are tool versions from the updated image. The Visium HD pipeline
test no longer lists Space Ranger's segmented_outputs, which is now only
produced when cells are requested. New snapshots for IMAGE_DOWNSCALE,
MASK_TO_GEOJSON and SDATA_BIN_TO_CELL.
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown

Warning

Newer version of the nf-core template is available.

Your pipeline is using an old version of the nf-core template: 4.1.0.
Please update your pipeline to the latest version.

For more documentation on how to update your pipeline, please see the Synchronisation documentation.

@github-actions

github-actions Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

nf-core pipelines lint overall result: Passed ✅ ⚠️

Posted for pipeline commit f2a6d1a

+| ✅ 248 tests passed       |+
#| ❔  11 tests were ignored |#
#| ❔   1 tests had warnings |#
!| ❗   8 tests had warnings |!
Details

❗ Test warnings:

  • readme - README contains the placeholder zenodo.XXXXXXX. This should be replaced with the zenodo doi (after the first release).
  • pipeline_todos - TODO string in CHANGELOG.md: ## v1.0dev - [unreleased replace with date on release ]
  • pipeline_todos - TODO string in nextflow.config: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs
  • pipeline_todos - TODO string in README.md: Add citation for pipeline after first release. Uncomment lines below and update Zenodo doi and badge at the top of this file.
  • pipeline_todos - TODO string in README.md: Add bibliography of tools and data used in your pipeline
  • pipeline_todos - TODO string in CONTRIBUTING.md: Add any pipeline specific contribution guidelines here, such as coding styles, procedures, checklists etc.
  • pipeline_todos - TODO string in awsfulltest.yml: You can customise AWS full pipeline tests as required
  • pipeline_todos - TODO string in nextflow.config: Specify any additional parameters here

❔ Tests ignored:

  • files_exist - File is ignored: conf/igenomes.config
  • files_exist - File is ignored: conf/igenomes_ignored.config
  • files_exist - File is ignored: .github/workflows/linting_comment.yml
  • files_unchanged - File ignored due to lint config: .gitattributes
  • files_unchanged - File ignored due to lint config: .github/PULL_REQUEST_TEMPLATE.md
  • files_unchanged - File ignored due to lint config: .github/workflows/branch.yml
  • files_unchanged - File ignored due to lint config: .github/workflows/linting.yml
  • files_unchanged - File ignored due to lint config: assets/nf-core-spatialvi_logo_light.png
  • files_unchanged - File ignored due to lint config: docs/images/nf-core-spatialvi_logo_light.png
  • files_unchanged - File ignored due to lint config: docs/images/nf-core-spatialvi_logo_dark.png
  • files_unchanged - File ignored due to lint config: .gitignore or .prettierignore

❔ Tests fixed:

✅ Tests passed:

Run details

  • nf-core/tools version 4.1.0
  • Run at 2026-11-06 19:15:44

@cavenel cavenel changed the title Segmentation Cell Segmentation Nov 6, 2026
@cavenel
cavenel marked this pull request as draft November 9, 2026 11:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant