Skip to content

dmcbffeng/codex-celltype

Repository files navigation

codex-celltype

codex-celltype assigns cell types to segmented cells in CODEX or other multiplexed images using marker fingerprints, QuPath positive-marker calls, and local marker intensity. It is a configurable and tested replacement for the dataset-specific scripts that originally lived in this working folder.

The pipeline reads tables, not image pixels. A typical input is QuPath's tab-delimited cell measurement export containing:

  • one row per cell;
  • an object ID and X/Y centroid coordinates;
  • marker intensity columns such as GCG: Cell: Mean; and
  • either a colon-separated Classification value such as PAX6:GCG, or explicit +/- columns for every marker.

Raw CODEX images and patient/donor tables are deliberately not included in this repository.

What is improved

  • A single command handles any number of samples.
  • All paths, column names, marker aliases, QC rules, and algorithm parameters live in one YAML configuration.
  • A sample manifest removes assumptions about QuPath filenames and directory structure.
  • codex-celltype validate catches missing files, columns, and markers before a long run starts.
  • Coordinate headers with µm, the common mangled µm, um, or pixels are detected automatically.
  • Markers that are absent, failed QC, excluded, or have constant intensity are handled safely.
  • Ambiguous first-round calls use a regularized intensity-profile tie breaker; if no profile exists, the result is deterministic.
  • Every output includes scores, margins, tie information, positive markers, a cell-type summary, marker enrichment tables, and a machine-readable run report.
  • A synthetic example, unit tests, packaging metadata, and GitHub Actions CI make the analysis reproducible.

Quick start

The project is tested with Python 3.10–3.12. In conda:

conda create -n codex-celltype python=3.10 -y
conda activate codex-celltype
python -m pip install -e ".[dev]"

Run the bundled synthetic example:

codex-celltype validate --config examples/demo/config.yaml
codex-celltype run --config examples/demo/config.yaml

Results appear under examples/demo/results/. Run the tests with:

pytest

Apply it to a new dataset

Create a small project skeleton:

codex-celltype init my_dataset

This creates:

my_dataset/
├── config.yaml       # column names, algorithm, QC, and output settings
├── fingerprint.csv   # cell-type/marker rules
├── samples.csv       # one row per image/table
└── data/             # place QuPath exports here, or use absolute paths

Then:

  1. Copy or link each QuPath measurement table into my_dataset/data/.
  2. Add one row per table to samples.csv.
  3. Edit fingerprint.csv for the tissue and antibody panel.
  4. Edit config.yaml only where your QuPath schema differs.
  5. Validate first, then run:
codex-celltype validate --config my_dataset/config.yaml
codex-celltype run --config my_dataset/config.yaml

The pipeline refuses to overwrite per-sample results unless --force is provided.

Input files

Sample manifest

samples.csv has two required columns and one optional column:

sample_id,measurement_file,hierarchy_file
donor_01,data/donor_01_measurements.tsv,
donor_02,/absolute/path/donor_02_measurements.tsv,/absolute/path/donor_02_hierarchy.txt
  • sample_id must be unique and is used in output filenames.
  • measurement_file may be relative to config.yaml or absolute.
  • hierarchy_file is needed only when region_filter.enabled: true.

QuPath measurement table

Default required columns are:

Purpose Default or example
Cell identifier Object ID
X coordinate auto-detected, e.g. Centroid X µm
Y coordinate auto-detected, e.g. Centroid Y µm
Positive calls Classification
Marker intensity {marker}: Cell: Mean

Override any nonstandard name under input: in config.yaml.

QuPath Classification values are interpreted as a configurable delimiter- separated list of positive markers. All panel markers not listed for that cell are treated as negative.

If marker calls are stored in separate columns, configure them explicitly:

positive_calls:
  mode: columns
  columns:
    GCG: GCG positive
    CPEP: CPEP positive
    CD45: CD45 positive
  positive_values: ["+", 1, true, positive]

Numeric values greater than zero are also accepted as positive.

Fingerprint

The fingerprint is a CSV with three columns:

cell_type,marker,weight
Endocrine,PAX6,specific
Endocrine|alpha,GCG,specific
Endocrine|beta,CPEP,specific
Immune,CD45,specific
Immune|Macrophage,CD11c,positive

Weights may be written as:

  • specific or 2: a defining marker. It contributes +2 to this cell type and its descendants and -1 to other types.
  • positive or 1: a supporting marker. It contributes +1 to this cell type and its descendants without penalizing other types.

The pipe character defines hierarchy. For example, a marker on Endocrine also applies to Endocrine|alpha. NONE is reserved for cells that do not exceed the score threshold.

The original pediatric-pancreas rules are available as fingerprints/pediatric_pancreas.csv. They are a starting point and still require validation for the antibody panel, age group, tissue processing, and QuPath thresholds in a new study.

Optional marker availability/QC table

For panels that differ by image, set:

input:
  availability_table: marker_availability.tsv
  availability_pass_values: [G, OK]

The table needs an image, sample, or sample_id column whose values match the manifest. Marker names are the other columns. Explanatory legend lines before the header are allowed. Only values listed in availability_pass_values enter that sample's model.

How annotation works

For each sample, the pipeline:

  1. intersects the fingerprint with intensity columns, QC-passing markers, and configured exclusions;
  2. z-standardizes every usable marker intensity within the image;
  3. represents each cell's positive/negative marker evidence;
  4. upgrades a positive call from 1.0 to 1.2 when the cell has greater intensity than its nearby cells for that marker;
  5. multiplies this evidence by the hierarchical fingerprint matrix;
  6. assigns the highest-scoring type above the configured threshold; and
  7. resolves exact ties from intensity profiles of unambiguous cells, with a variance floor for small or constant groups.

The main parameters are under algorithm::

algorithm:
  n_neighbors: 3
  max_neighbor_distance: 12
  score_threshold: 0.2

Distances use the units of the exported centroid coordinates.

Optional region filtering

The legacy pancreas workflow suppressed endocrine calls outside QuPath islet annotations. This behavior is optional and off by default:

region_filter:
  enabled: true
  parent_prefix: Islet
  restricted_markers: [PAX6, CHGA, GCG, CPEP, SST, GHRL, PPY]

When enabled, each manifest row needs a whitespace-delimited hierarchy file whose first field is the parent annotation and whose last field is the cell object ID.

Outputs

The output directory contains:

File Contents
{sample_id}_annotated.csv Original QuPath columns plus annotation results
cell_type_summary.csv Cell count and fraction by sample and cell type
marker_z_enrichment_long.csv Mean marker Z-enrichment across images
marker_z_enrichment_wide.csv Cell type × marker enrichment matrix
marker_z_enrichment_n_images.csv Number of contributing images
run_report.json Input files, cell counts, markers used, and tie counts

Important annotation columns are:

  • Cell_type_fingerprints: final label;
  • Cell_type_score: winning fingerprint score;
  • Cell_type_margin: separation from the next non-tied score;
  • Cell_type_tie_broken: whether the second round chose the label;
  • Cell_type_candidate_count: number of tied first-round candidates; and
  • Positive_markers_used: calls used after QC and optional region filtering.

Adapting the scientific model

This is a rule-based annotation tool, not a trained universal classifier. Before using it on another tissue or antibody panel:

  • revise the fingerprint with domain experts;
  • confirm QuPath positivity thresholds and segmentation quality;
  • inspect NONE, low-margin, and tie-broken cells;
  • compare calls with marker-expression plots and tissue morphology; and
  • treat the bundled example as a software test, not a validated biological reference.

Legacy files in the working folder

The original run_HANDELP.py, functions.py, enrichment figures, NumPy arrays, workbook, and dataset-specific availability table are retained locally for reference but ignored by Git. The public project contains the reusable package, synthetic example, tests, and documentation only.

License and citation

The software is released under the MIT License. Citation metadata is provided in CITATION.cff.

About

Configurable fingerprint-based cell-type annotation for CODEX and QuPath tables

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages