Conversation
* feat: add segment_cell for conjugate graph node classification Port pixelatorR segment_cell onto PNAGraph so two cell types (and an optional interface) can be labeled from cc_protein_weights. Co-authored-by: Cursor <cursoragent@cursor.com>
elhb
marked this pull request as ready for review
September 17, 2026 11:43
ludvigla
approved these changes
Sep 22, 2026
ludvigla
left a comment
Contributor
There was a problem hiding this comment.
Looks great! I have no additional comments.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR adds the public Python APIs for PNA cell:cell conjugate segmentation, matching the pixelatorR workflow:
cc_protein_weights— rank-2 NMF protein weights for two labeled populations (thewmatrix).distance_from_node_set— integer hop distance from a set of seed nodes on aPNAGraph.partition_counts— protein counts summed by node partition (cell type / interface / other).segment_cell— classify conjugate-graph nodes into the two cell types, with an optional interface.They live in
pixelator.pna.analysis.segmentationand are re-exported frompixelator.pna.analysis. Input for graph steps is aPNAGraph(the same object you get fromdataset.edgelist().iterator()); weights are fit on AnnData (dataset.adata()with population labels inobs).cc_protein_weightscurrently implementsmode="cell_abundance"(the default, and the path used bysegment_celland the R tutorial).mode="k_neighborhood"raisesNotImplementedError. Projection ofwonto neighborhood profiles is non-negative least squares via sklearn (LinearRegression(positive=True)), without pixelatorR’s RcppMLL1 = 0.2. That difference is documented; see the comparison below.Collects the already-reviewed pieces from #458, #459, #460, and #464.
Type of change
How Has This Been Tested?
CI (pytest). Shape, column names, error paths, and behavioral smoke.
PNAGraph(exclusive T/B markers, two crossing edges, a disconnected island): core compartments are stable, crossing nodes becomeinterfacewhen detection is on, the island isotherunder LCC filtering..pxl(same cells as pixelatorRminimal_pna_pxl_file()): the functions run on a real graph. That file is not a biological conjugate; R’s own tests only check that labels fall in{Mono, CD4T, interface, other}.Comparison with pixelatorR (not in CI). The R
test-segment_cell.Rcase was run in both languages on the same 5-cell PXL, same component (2708240b908e2eba), same population labels (MonovsCD4T), and the same NMF seed (7331). Python node ids are integer UMIs; R names have a-umi1/-umi2suffix — those were stripped before scoring.Two comparisons:
w, then runssegment_cell. This is what a scientist would do in each language.segment_cellis given the Rwmatrix. This isolates the graph/NNLS steps from NMF.Results on 37,665 nodes:
segment_cellsettingwwdetect_interface=Falsek_interface_expansion=4min_comp_size=1NMF weights: 103 proteins in both languages, identical top-8 markers per population, cosine similarity 1.000 on both columns.
With shared
w, labels match exactly except one node when every connected component of size ≥ 1 is kept (2-means threshold RNG). Independent-path disagreements are almost all Rothervs PythonCD4T— small fragments around the LCC cutoff, not core compartment swaps.A separate planted T/B conjugate (learned weights →
segment_cell→partition_counts) recovered cores and the interface at 100% against the planted labels. That graph is the conjugate-correctness check; the 5-cell file is the R-parity smoke check.PR checklist:
pyproject.tomland cited it properlyNote
Medium Risk
New analysis-only surface area with no pipeline changes, but
segment_cell/cc_protein_weightsdrive scientific labels on conjugate graphs and can diverge slightly from R at boundaries due to NNLS differences.Overview
Adds public Python APIs for PNA cell:cell conjugate segmentation, aligned with pixelatorR, under
pixelator.pna.analysis.segmentationand re-exported frompixelator.pna.analysis.cc_protein_weightsfits rank-2 NMF on whole-cell protein abundance from AnnData (two labeled populations;mode="cell_abundance"only;k_neighborhoodraisesNotImplementedError) and returns thewmatrix used downstream.segment_cellannotates a conjugatePNAGraphin place with acompartmentattribute (two cell-type names, optionalinterface, orother) via k-hop neighborhood profiles, non-negative projection ofw, optional spatial smoothing, connected-component filtering, and interface detection.distance_from_node_setwrites multi-source BFS hop distances todistance_from_seed.partition_countscollapses node marker counts by partition vector or node attribute.Docs (
CHANGELOG.md,docs/api/overview.rst) list the new entry points. Tests cover synthetic conjugates, R-parity checks on a shared 5-cell PBMC fixture, and validation/error paths. Python’ssegment_cellprojection omits pixelatorR’s RcppML L1 penalty, so boundary labels can differ slightly from R when weights are fit independently.Reviewed by Cursor Bugbot for commit cdb1c12. Bugbot is set up for automated code reviews on this repo. Configure here.