Skip to content

Subset a reduction's model along with the reduction - #316

Closed
BenjaminDEMAILLE wants to merge 1 commit into
satijalab:mainfrom
BenjaminDEMAILLE:fix/subset-umap-model
Closed

BenjaminDEMAILLE wants to merge 1 commit into
satijalab:mainfrom
BenjaminDEMAILLE:fix/subset-umap-model

Conversation

@BenjaminDEMAILLE

Copy link
Copy Markdown

Fixes satijalab/seurat#10445, reported with a clear diagnosis and a workaround; this is that workaround made part of subsetting.

The state

RunUMAP(return.model = TRUE) keeps the embedding it was fit on in the reduction's misc$model. Subsetting the reduction leaves it untouched:

ncol(subset)                                     50
nrow(Embeddings(subset[["umap"]]))               50
nrow(Misc(subset[["umap"]], "model")$embedding)  80

Why it matters

Projecting a query onto that reduction, which is what MapQuery() and ProjectUMAP() do, finds the query's neighbours among the reduction's current cells and then reads their coordinates out of the model. Every index past the subset therefore points at a different cell than the one that was matched. Nothing warns; the query simply lands in the wrong place, which is the distorted plot in that issue.

Measurement

Projecting a reference's own cells back through its own model, so each should land on its own coordinate, with a subset that is not a prefix of the original (a prefix hides the bug, since the first N rows still line up):

model median distance to own coordinate as a share of the embedding's spread
stale, 80 rows 3.184 13.7%
subset, 50 rows 0.579 2.5%

Change

subset.DimReduc() subsets the model's embedding to the cells the reduction keeps. Everything else in a uwot model describes features or parameters (n_neighbors, metric, scale_info, pca_models) and is left alone. A reduction with no model, or a model with no embedding, is untouched.

Tests

tests/testthat/test_subset_reduction_model.R: the model's embedding follows the reduction's cells and matches its coordinates, the rest of the model is unchanged, and a reduction with no model still subsets.

Two assertions fail without the change. SeuratObject suite: 183 passing, 0 failures. Seurat's own suite against this build: 1184 passing, the only 2 failures being ones that predate it and are unrelated (Read10X_Image, satijalab/seurat#10454).

🤖 Generated with Claude Code

RunUMAP(return.model = TRUE) keeps the embedding it was fit on in the
reduction's misc$model. Subsetting the reduction left that untouched:

  ncol(subset)                                    50
  nrow(Embeddings(subset[["umap"]]))              50
  nrow(Misc(subset[["umap"]], "model")$embedding) 80

Projecting a query onto that reduction, as MapQuery() does, looks its
neighbours up among the reduction's cells and then reads their coordinates
out of the model, so every index past the subset points at the wrong cell.
Nothing warns; the query simply lands in the wrong place.

Measured by projecting a reference's own cells back through its model, so
that each should land on its own coordinate, using a subset that is not a
prefix of the original:

  stale model, 80 rows   median distance 3.184   13.7% of the embedding's spread
  subset model, 50 rows  median distance 0.579    2.5%

Subset the model's embedding to the cells the reduction keeps. The rest of
the model describes features or parameters and is left alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@BenjaminDEMAILLE

Copy link
Copy Markdown
Author

Superseded by #318, which groups the correctness PRs into one so that a single review covers the subject. The commit is carried over unchanged; closing here to keep the queue down rather than because anything was wrong with it.

cyrillustan added a commit to BenjaminDEMAILLE/seurat-object that referenced this pull request Sep 25, 2026
This commit addresses only the satijalab#316 UMAP model subsetting issue carried into satijalab#318. Keep stored model row names aligned when a DimReduc is renamed, reject subsets whose model lacks retained cells, and avoid the misleading model overwrite warning. Add focused regression coverage for those paths.
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.

BUG: MapQuery gives aberrant results if reference is subset after RunUMAP

1 participant