Skip to content

Pna 2699 - #386

Open
elhb wants to merge 59 commits into
devfrom
pna-2699
Open

Pna 2699#386
elhb wants to merge 59 commits into
devfrom
pna-2699

Conversation

@elhb

@elhb elhb commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Description

Add typed panel combination system for PNA.

Adds distinct panel kinds (base / addon / sample-hashing) driven by metadata
panel_type, plus PNAAntibodyPanelCombination for samples that use several
panels together. Shared marker helpers live on PNAPanel.

PNAPanel (ABC)
├── PartialPNAAntibodyPanel
│   ├── PNABasePanel
│   ├── PNAAddonPanel
│   └── PNASampleHashingPanel
└── PNAAntibodyPanelCombination
  • Replaces the single PNAAntibodyPanel type with the hierarchy above.
    PNAAntibodyPanel remains a deprecated alias of PartialPNAAntibodyPanel
    (DeprecationWarning on access; removed in a future release).
  • Public exports from pixelator.pna.config include PNAPanel,
    PartialPNAAntibodyPanel, typed subclasses, PanelType,
    PNAAntibodyPanelCombination, and panel_from_* / load_antibody_panel.
  • panel_from_csv returns a typed PartialPNAAntibodyPanel from metadata
    panel_type. panel_from_adata / panel_from_pxl_dataset return that type
    or a combination when several partial panels are stored.
    load_antibody_panel always returns a PNAAntibodyPanelCombination.
  • Combinations are built from member panels:
    PNAAntibodyPanelCombination(panel) /
    PNAAntibodyPanelCombination([p1, p2, ...]). Members must not share the
    same product (including more than one member with product unset).
  • Hashing marker_id values must end with -<digits> (e.g. B2M-1) and must
    not collapse to another hashing id (B2M-1-1 next to B2M-1).
  • CLI --panel may be repeated on demux / collapse / graph.
  • New AnnData / .pxl files store panels under num_partial_panels +
    panel_metadata__{i} / panel_df__{i} (even for a single panel). Legacy
    panel_metadata + panel_columns files remain readable. Patch bumps via
    PNAAntibodyPanelDiff.upgrade_adata migrate legacy uns to the multi-panel
    layout (backwards compatibility for bumping patch versions of old pxl files).
  • Panel patch bumps of sample-called files no longer fail when hashing clones
    are absent from var. The upgrade records
    uns["sample_calling"]["collapsed"] (legacy files are inferred), remaps
    edgelist / proximity / layout marker columns, and denoise rebuilds AnnData
    from the current markers so hashing antibodies are not added back.
  • Docs: panel API docstrings and an AutoAPI class template for inheritance
    rendering.

Fixes: PNA-2699

THIS PR DOES NOT CHANGE ANY PANELS (panel CSVs are unchanged; typed
panel_type only applies when metadata sets it).

Type of change

  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

API impact vs dev:

  • Prefer PartialPNAAntibodyPanel (or a typed subclass) /
    PNAAntibodyPanelCombination / PNAPanel instead of PNAAntibodyPanel.
    Existing PNAAntibodyPanel imports still work but warn.
  • load_antibody_panel returns PNAAntibodyPanelCombination.
    panel_from_csv still returns a single typed panel, not a combination.
  • Pass panels into PNAAntibodyPanelCombination(...), not a raw dataframe and
    metadata. Combination members must have unique product.
  • New AnnData / .pxl files store panels under num_partial_panels +
    panel_metadata__{i} / panel_df__{i} (even for a single panel). Legacy
    panel_metadata + panel_columns files are still readable, but are no
    longer written (patch bumps migrate them to the new layout).
  • Hashing marker_id values must use a -<digits> suffix and must not nest
    (B2M-1-1 next to B2M-1).

How Has This Been Tested?

  • task test
  • Focused coverage for legacy AnnData panel round-trip and
    upgrade_adata migration to multi-panel uns
  • Docs build for AutoAPI inheritance rendering where applicable
  • nf-test test tests/proxiome_v2.nf.test --profile=+docker --verbose ran on the container built in this PR finished sucesfully.

PR checklist:

  • This comment contains a description of changes (with reason).
  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • If a new tool or package is included, I have updated dependencies in pyproject.toml and cited it properly
  • I have checked my code and documentation and corrected any misspellings
  • I have documented any significant changes to the code in CHANGELOG.md

Note

High Risk
Breaking panel API and AnnData write format, with patch-upgrade and marker-remap logic on core PNA pipeline paths (demux through pixel I/O) including post–sample-calling edge cases.

Overview
Introduces a typed PNA panel model and first-class support for multiple panels per sample. The monolithic PNAAntibodyPanel is split into PartialPNAAntibodyPanel with PNABasePanel, PNAAddonPanel, and PNASampleHashingPanel (driven by CSV metadata panel_type), combined via PNAAntibodyPanelCombination. load_antibody_panel always returns a combination; --panel may be repeated on demux, collapse, and graph. PNAAntibodyPanel remains as a deprecated alias.

AnnData / .pxl panel storage for new files uses num_partial_panels and indexed panel_metadata__{i} / panel_df__{i} (legacy single-key layout is still read). add_panel_information and patch bumps via PNAAntibodyPanelDiff.upgrade_adata follow that layout. Hashing marker_id values must end with -<digits> and cannot nest (e.g. B2M-1-1 beside B2M-1).

Sample-called files are handled when panel patch versions differ: upgrades tolerate missing hashing clones in var using uns["sample_calling"]["collapsed"] (with legacy inference), remap edgelist / proximity / layout marker columns on read, and denoise rebuilds counts from current var while preserving sample-calling metadata. Sphinx AutoAPI gets a custom class.rst so inheritance links resolve on class pages.

Reviewed by Cursor Bugbot for commit 1eb146b. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread src/pixelator/pna/config/panel.py Outdated
…n sync with df

Co-authored-by: Cursor <cursoragent@cursor.com>
@elhb
elhb requested review from Aratz and johandahlberg August 21, 2026 09:20
Split config/panel.py over multiple files
Comment thread src/pixelator/pna/config/panel/utils.py Outdated
pd.concat upcast bool flags to float (True → 1.0), and sample_hashing_mask
did not treat "1.0" as hashing, so sample calling saw an empty hashing set.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/pixelator/pna/config/panel/combination.py Outdated
Comment thread src/pixelator/pna/config/panel/combination.py Outdated
Comment thread src/pixelator/pna/config/panel/partial.py Outdated
…type.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/pixelator/pna/analysis/denoise.py
Multi-panel names are stored as "base + hash", so splitting on "+" without
stripping left padded fragments that load_antibody_panel could not resolve.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/pixelator/pna/sample_calling/__init__.py
elhb and others added 2 commits August 27, 2026 14:01
Sample calling now records uns["sample_calling"]["collapsed"] and keeps
the original panels in uns, so a later patch bump no longer fails when
hashing clones are absent from var.

Co-authored-by: Cursor <cursoragent@cursor.com>
Edgelist, proximity, and layout reads now share the AnnData helper rename
so stored marker ids follow the upgraded var names.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/pixelator/pna/config/panel/diff.py
Comment thread src/pixelator/pna/config/panel/diff.py
Comment thread src/pixelator/pna/pixeldataset/io/anndata_helper.py

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1eb146b. Configure here.

# update the anndata var table
org_var_shape = adata.var.shape
org_index = adata.var.index.name
collapsed = sample_calling_hashing_collapsed(adata)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collapsed inference uses upgraded snapshots

Medium Severity

upgrade_adata rewrites panel_metadata__* / panel_df__* to the new panel before calling sample_calling_hashing_collapsed. When the collapsed flag is absent, that helper rebuilds the combination from uns and treats hashing clones as collapsed if those ids are missing from var. After a hashing marker_id rename, var still holds the old names, so an uncollapsed file is inferred as collapsed for the rest of the upgrade (missing-clone skips and collapsed index remaps).

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1eb146b. Configure here.

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.

2 participants