Skip to content

genoABO Workflow: Loading to Output

This document describes how genotype data moves through genoABO from file load to written results. For CLI flags and the Python API see usage.md; for inference rules see methods.md; for marker coordinates see markers.md; for limitations see assumptions.md.

Research use only. genoABO is not a clinical blood-transfusion typing tool.

Overview

genoABO reads four ABO tag SNPs (rs8176719, rs8176746, rs8176747, rs505922) from a cohort genotype file, detects the genome build, normalizes alleles to biological marker states, infers haplotypes and diplotypes, and writes per-sample ABO calls with QC metrics. Indexed VCF/BCF fetches those sites by region. Unindexed VCF is scanned into an in-memory cache. PGEN and BGEN parse full variant-metadata indexes, then read genotypes only for the matched markers.

The package is organized into four modules plus YAML registries:

flowchart TB
    Input[Genotype file]
    Readers[readers/]
    Core[core/]
    Methods[methods/]
    CLI[cli/]
    Data[data/*.yaml]
    OutABO["PREFIX.abo.tsv"]
    OutQC["PREFIX.qc.tsv"]
    OutSum["PREFIX.summary.txt"]
    OutRep["PREFIX.report.html"]

    Input --> Readers
    Readers --> Core
    Core --> Data
    Core --> Methods
    Methods --> CLI
    CLI --> OutABO
    CLI --> OutQC
    CLI --> OutSum
    CLI --> OutRep
Module Role
readers/ Format detection and indexed marker fetch (VCF, BGEN, PGEN, PLINK1)
core/ Types, YAML registry, build detection, genotype interpretation, normalization, haplotype logic
methods/ Inference methods and ABOCaller orchestration
cli/ Command-line interface, output writers, citations
data/ YAML single source of truth for coordinates, states, methods

Entry points

Both paths run the same pipeline via ABOCaller. See Usage for the full CLI and Python API.

Entry Code path
CLI genoabo DATA -o PREFIX → cli/cli_main.py → ABOCaller.call() → cli/cli_qc.py writers
Python API from genoabo import ABOCaller → methods/methods_caller.py
# Full inference + output
genoabo cohort.pgen --out abo

# Marker inspection only (stops after step 7; no .abo.tsv)
genoabo cohort.pgen --inspect
from genoabo import ABOCaller

caller = ABOCaller(method="auto", build="auto", genotype_mode="auto", phase="auto")
result = caller.call("cohort.pgen")

for call in result.calls:
    print(call.sample.iid, call.abo_group, call.abo_genotype)

Pipeline stages

The orchestrator is ABOCaller._run() in methods/methods_caller.py. Stages run in this order:

Step Module What happens
1. Format detection readers/ open_reader(path, format) auto-detects VCF/BCF, PGEN, PLINK1, or BGEN from file extensions and companion files (.pvar/.psam, .bim/.fam, .sample)
2. Sample list readers/ reader.samples() returns the cohort SampleID list (FID/IID)
3. Marker probe readers/ + core/ For each rsID, build a MarkerQuery from assemblies.yaml + markers.yaml and fetch using multi-key lookup (rsID, contig:pos, contig:pos:nea:ea; contigs may be 9, chr9, or NC accessions)
4. Build detection core/ detect_build() matches observed positions and VCF ##reference= / similar header tokens; returns build + confidence. Ambiguous results raise an error unless --build is set explicitly. Chromosome-length scoring exists in detect_build but the caller does not pass contig lengths. PGEN/BGEN headers are not assembly metadata
5. Full marker fetch readers/ Re-fetch all four markers using the same multi-key lookup at the resolved build
6. Method selection methods/ select_method() applies the auto-selection hierarchy from data/methods.yaml, or honors --method / --strict-method
7. Inspection report core/ + cli/ inspect_markers() builds an InspectReport (positions, call rates, recommended method). Printed with --inspect; also embedded in QC output
8. Phase resolution methods/ resolve_phase() — auto is cohort-wide (any phased GT → all samples phased); phased / unphased force the mode
9. Per-sample normalization core/ For each sample × marker: interpret_genotype() resolves hardcall from dosage/probability, then normalize_marker() maps REF/ALT → biological MarkerAlleleState using data/markers.yaml
10. Inference methods/ + core/ get_method(name).call_sample() applies method rules (methods/methods_infer.py); haplotype/diplotype logic lives in core/core_haplotype.py
11. Output cli/ write_abo_tsv, write_qc_tsv, write_summary, and write_report write the four output files

Per-sample sub-flow

For each sample, marker data passes through normalization before method-specific inference:

flowchart LR
    GT[GenotypeCall per marker]
    Geno[interpret_genotype]
    Norm[normalize_marker]
    Hap[infer_haplotype]
    Method[method.call_sample]
    Call[ABOCall]

    GT --> Geno --> Norm --> Hap --> Method --> Call

Layers are strictly separated: readers know file formats but not ABO biology; normalization knows biological states but not inference rules; methods know decision tables but not VCF/PGEN syntax.

Genotype and phase modes

CLI flags map to CallerConfig and affect step 9:

Flag Values Behavior
--geno-mode auto, hardcall, dosage, probability How to resolve discrete allele copies from GT, DS, or GP
--dosage-hardcall-threshold float (default 0.1) Dosage bands for 0/1/2 alt copies
--min-genotype-prob float (default 0.9) Minimum max(GP) for probability mode
--phase auto, phased, unphased auto is cohort-wide: any phased GT switches the whole run to phased mode
--assume-bo / --no-assume-bo flag (default on) Unphased double-het (O_DEL/NON_O × A/B): assign B/O, or leave ambiguous

In auto genotype mode, GP is used when available, else DS, else hardcall GT. GP and DS replace leftover phased GT so the requested mode wins.

Missing genotypes and dosage/GP below threshold become MISSING_MARKER with confidence=none on methods that require that marker. Conflicting A/B SNPs under three-marker become CONFLICT with confidence=low. The geno_mode column stores the requested mode (auto stays auto).

Marker identification (probe and fetch)

When locating variants in input files, genoABO tries keys in priority order (first hit wins):

  1. rsID — e.g. rs8176719
  2. contig + position — all equivalent contig names for the build:
  3. numeric: 9:133257521
  4. chr-prefixed: chr9:133257521
  5. RefSeq NC: NC_000009.12:133257521 (GRCh38 chr9)
  6. contig + position + alleles — chr:pos:nea:ea for each representation in markers.yaml, both orientations (e.g. 9:133257521:G:GC and 9:133257521:GC:G)

Contig aliases are defined per build in assemblies.yaml (contigs section). Input files are indexed under every alias derived from their CHROM field, so a VCF using NC_000009.12 matches the same marker as one using 9 or chr9.

For indexed VCF/BCF, region queries are attempted for each contig alias. Allele-aware keys disambiguate when they match. A position-only key (chr:pos) keeps the first indexed variant at that site, so rsID or allele keys are preferred when several records share a position.

Output files

Default CLI invocation:

genoabo cohort.pgen --out abo

writes four files (if -o is omitted, the prefix is the input path with its last suffix stripped):

File Contents
PREFIX.abo.tsv One row per sample with ABO call, haplotypes, method, QC fields
PREFIX.qc.tsv Cohort-level metrics: build, method, marker call rates, group counts
PREFIX.summary.txt Human-readable summary of counts and marker availability
PREFIX.report.html Self-contained run report (results, output, then input, methods, citations, limitations)

--report PATH.html overrides the HTML path. Column descriptions in the report come from data/report.yaml (same schema as .abo.tsv).

genoabo cohort.pgen --out abo
genoabo cohort.pgen --out abo --report custom_report.html

Python:

from genoabo import ABOCaller
from genoabo.visualize import write_report

result = ABOCaller().call("cohort.pgen")
write_report(result, "abo.report.html")
# result.stats.n_input_samples, result.stats.n_group_A, ...
# result.config, result.input_path, result.phase_resolved

See also Examples for runnable demos across formats.

PREFIX.abo.tsv columns

Column Description
FID, IID Sample identifiers
ABO_group Phenotype: A, B, AB, or O. Unassigned is NA in the TSV
ABO_genotype Diplotype label (e.g. A/O), ambiguous, or NA
ABO_allele1, ABO_allele2 Sorted haplotype alleles (A < B < O)
haplotype1, haplotype2 Chromosome copies when phased; sorted alleles when unphased
method Inference method used
geno_mode, phase_mode Requested genotype mode; phased vs unphased
build Genome assembly
confidence high / medium / low / none
qc_status, qc_reason QC flags and explanation
possible_diplotypes Compatible diplotypes when ambiguous
ukb_haplotype UKB Field 23165 code (ukb method only)
isbt_alleles ISBT allele IDs (extended method only)

Example header row:

FID IID ABO_group   ABO_genotype    ABO_allele1 ABO_allele2 haplotype1  haplotype2  method  geno_mode   phase_mode  build   confidence  qc_status   qc_reason   possible_diplotypes ukb_haplotype   isbt_alleles

PREFIX.qc.tsv

Key-value metrics including n_samples, genome_build, input_format, method, per-marker call rates, group counts (n_A, n_B, …), and percentages.

PREFIX.summary.txt

Plain-text cohort summary with ABO group counts and marker availability — suitable for logs.

PREFIX.report.html

Self-contained HTML run report: ABO pie and run settings at the top, then results (sample-flow and ABO charts), output column dictionary, input settings, selected-method rules, citations, and limitations. Always written; --report only changes the path.

YAML registries

All coordinates and biological mappings live in src/genoabo/data/, loaded at runtime via importlib.resources:

File Used in Purpose
assemblies.yaml Steps 3–5 Build aliases, chromosome lengths (registry / unused caller signal), marker coordinates per assembly
markers.yaml Step 9 Biological states and REF/ALT → state normalization rules
methods.yaml Step 6 Method metadata, required markers, auto-selection hierarchy, report logic
alleles.yaml Step 10 ISBT allele patterns (extended method only)
citations.yaml CLI / report Full bibliographic records for --method-info and the HTML report
report.yaml HTML report Pipeline narrative, column dictionary, confidence table, limitations

Error handling and early exit

Condition Behavior
Ambiguous build with --build auto RuntimeError; CLI exits with code 1
--strict-method with missing required markers Error for a user-selected method, or for --method auto when no entry matches; no substitution of a smaller method
--inspect Pipeline succeeds after step 7; inspection printed; no .abo.tsv / .qc.tsv / .summary.txt / .report.html
Unreadable input format Error from open_reader()

When build detection conflicts (e.g. mixed GRCh37/GRCh38 signal), set --build hg19, --build hg38, or --build chm13 explicitly.

  • methods.md — formal decision tables per inference method
  • markers.md — coordinate provenance, biological states, and 1000 Genomes LD r²
  • assumptions.md — rare-allele limits and unresolved edge cases
  • Home — installation and quick start