Skip to content

docs(tutorial): run the whole pipeline at build, fail loudly on an empty mask - #55

Draft
xuefei-wang wants to merge 2 commits into
masterfrom
docs/tutorial-run-from-scratch
Draft

docs(tutorial): run the whole pipeline at build, fail loudly on an empty mask#55
xuefei-wang wants to merge 2 commits into
masterfrom
docs/tutorial-run-from-scratch

Conversation

@xuefei-wang

Copy link
Copy Markdown
Collaborator

Supersedes #54. Per @rossbar's review there, the tutorial must stay a real end-to-end demonstration (raw image → segmentation → cell-type prediction) since it is the only integration check that the pieces of this package work together. #54 took the opposite approach — defaulting to the archive's precomputed mask — and is being closed.

This PR keeps every step executing and fixes the two places where that had drifted.

1. Restore the napari screenshots

master replaced both nim.screenshot cells with prose:

The image and segmentation layers appear directly in the interactive Napari viewer. Static documentation builds do not execute or embed GUI screenshots.

so the rendered docs no longer show the segmentation or the cell-type layers. This restores the two hide-cell screenshot cells and their <img> embeds, matching the tutorial as of 616d4b5. docs/_static/_generated is already in .gitignore, so the images remain build artifacts.

2. Fail loudly on an empty segmentation

A user reported "the cell type prediction result appears empty." The only post-segmentation check verified the mask shape:

mask.shape == img.shape[1:]

A degenerate all-background mask has the correct shape, so this passed. predict() then returned [] for a mask with no cells and the DataFrame rendered empty, with nothing to explain it. Now:

assert mask.shape == img.shape[1:], "mask shape does not match the image H, W"
assert mask.max() > 0, (
    "segmentation produced no cells - try a different `membrane_channel` "
    "(see the note above) and confirm cellSAM is running as expected"
)

# Number of cells detected
int(mask.max())

A failed or misconfigured segmentation now stops the tutorial where it actually breaks, and the cell count is useful output in its own right.

Result

Execution structure now matches the 616d4b5 snapshot:

616d4b5 master this PR
executed {code-cell}s 23 22 24
executed cellsam_pipeline 1 1 1
nim.screenshot calls 2 0 2
cells loading a precomputed mask 0 0 0

(24 vs 23 is the download_model cell added on master since 616d4b5; the guard replaces the old shape-check cell 1:1.)

Nothing is precomputed — the two remaining ds["segmentations/…"] mentions are prose noting the archive's masks exist, unchanged from 616d4b5, with no cell loading them.

Verification

  • Diff is docs/site/tutorial.md only, 53 insertions / 8 deletions.
  • All 24 executed cells parse (ast.parse); code fences balanced; no non-executed python blocks (the 2 remaining plain fences are the bash install snippets, as on master).
  • Not verified locally: the docs build itself. cellSAM, napari, and jupytext are not installed in this environment, so the screenshot cells and the cellsam_pipeline run have not been exercised here — that needs a docs-env build.

Out of scope

master and the #54 branch also disagree on the wording of the abstention note. This PR leaves master's wording untouched.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FwCG7rydRT4EWWhuerxuuT

…n empty mask

The tutorial is the only end-to-end check that the pieces of this package work
together, so every step should actually execute: raw image -> cellSAM
segmentation -> cell-type prediction -> visualization.

Two things had drifted from that:

- The napari screenshots were replaced with prose ("Static documentation builds
  do not execute or embed GUI screenshots"), so the rendered docs no longer
  showed the segmentation or the cell-type layers. Restore the two hide-cell
  `nim.screenshot` cells and their `<img>` embeds, matching the tutorial as of
  616d4b5. `docs/_static/_generated` is already gitignored, so the images stay
  build artifacts.

- A user reported "the cell type prediction result appears empty". The only
  post-segmentation check verified the mask *shape*, and a degenerate
  all-background mask has the correct shape, so it passed; predict() then
  returned [] and the DataFrame rendered empty with nothing to explain it.
  Turn the shape check into a hard assert, add a cell-count assert, and report
  the number of cells detected, so a failed segmentation stops the tutorial at
  the point of failure.

Supersedes #54, which took the opposite approach (defaulting to the archive's
precomputed mask); per review, the computation must not be replaced.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01FwCG7rydRT4EWWhuerxuuT
cellSAM's segmentation labels are not contiguous, so `int(mask.max())`
under "Number of cells detected" reported the largest label ID rather
than the cell count. The rendered page then contradicted itself: the
guard cell showed 4644 while "Total number of cells" showed 1743 after
relabel_sequential -- and 1743 is what predict() returns.

Count distinct nonzero labels instead. Verified with a full docs build
running real cellSAM segmentation (not the archive's precomputed mask,
whose labels are already contiguous, which is why this only surfaces on
a from-scratch run): guard cell, cell-type total, and the prediction
DataFrame now all report 1743.

The empty-mask assertion is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01BHtuHjUExCH8bvCowX7GJ3
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