Metadata-Version: 2.4
Name: triohap
Version: 0.4.0
Summary: Trio-aware matching of VCF and gVCF genotypes to regional pangenome haplotypes
Maintainer: comparativechrono
License-Expression: MIT
Project-URL: Homepage, https://github.com/comparativechrono/TrioHap
Project-URL: Documentation, https://github.com/comparativechrono/TrioHap/blob/main/README.md
Project-URL: Source, https://github.com/comparativechrono/TrioHap
Project-URL: Issues, https://github.com/comparativechrono/TrioHap/issues
Project-URL: Changelog, https://github.com/comparativechrono/TrioHap/blob/main/CHANGELOG.md
Keywords: bioinformatics,pangenome,haplotype,trio,VCF,gVCF
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: plots
Requires-Dist: numpy>=1.24; extra == "plots"
Requires-Dist: matplotlib>=3.7; extra == "plots"
Provides-Extra: dev
Requires-Dist: build>=1.2.2; extra == "dev"
Requires-Dist: twine>=6.1; extra == "dev"
Dynamic: license-file

# TrioHap

Rank assembly-derived regional haplotype matches for a child using the child,
mother and father's SNP genotypes. Show the maternal and paternal assignments
on a marker-similarity network, preserving ambiguous matches and extra variants.

This is a small, inspectable research prototype, not a clinically validated
genotyper. Development lives in
[comparativechrono/TrioHap](https://github.com/comparativechrono/TrioHap).
The matching engine uses Python's standard library. Plots require NumPy and
Matplotlib. The PyPI distribution is named **`triohap`**.

Version 0.4 automatically detects VCF and conventional gVCF input, including
mixed individual files. Both input modes feed the same trio inference model
and produce the same rankings for equivalent evidence. SCN5A catalogue import
preserves full haplotype identities and graph topology; see [SCN5A.md](https://github.com/comparativechrono/TrioHap/blob/main/SCN5A.md).
All trio testing so far is synthetic.

## Installation

Install with Python 3.10 or newer:

```bash
python -m pip install 'triohap[plots]'
triohap --version
triohap --help
```

For the standard-library matching engine without graph dependencies, install
`triohap` and pass `--no-plot`. Plotting is optional, but enabled by default in
the command, so the `[plots]` installation is recommended for normal use.

The package name, command, and Python import are all `triohap`. Older local
prototype wheels were called `triohap-prototype`; uninstall that distribution
before installing `triohap`, because both contain the same Python package.
The wheel contains the application. The source distribution also contains the
examples, tests, documentation, and SCN5A provenance fixtures; these are not
installed into Python's package directory. The source archive can be unpacked
to run the examples below, or use a repository checkout.

## Run the synthetic example

From this directory, with Python 3.10 or newer:

```bash
python -m pip install '.[plots]'
python -m triohap \
  --trio examples/trio.vcf --panel examples/panel.tsv \
  --child child --mother mother --father father \
  --region chr1:100-290 --build synthetic \
  --unfazed-vcf examples/unfazed.vcf \
  --title 'Synthetic example: two inherited backgrounds' \
  --out example-run
python -m unittest discover -s tests -v
python scripts/validate_synthetic.py
python scripts/validate_gvcf.py
```

The expected result is maternal **H1/H1_like** (indistinguishable on observed
SNPs), paternal **H2**, with an inherited mismatch at position 200. Position
220 is Mendelian-inconsistent and excluded from the matching score; the
separate synthetic Unfazed file places its alternate allele on the paternal
background. Position 240 is present only in the trio file. Position 260 is
present only in the panel and must not distinguish H1 from H1_like. Position
280 has a missing father genotype and is excluded.

## Inputs

1. A joint trio VCF/gVCF (`--trio`), or three individual files (`--child-vcf`,
   `--mother-vcf`, `--father-vcf`), with explicit diploid GTs. VCF versus gVCF
   is detected automatically from content; no type flag is required. Plain and
   gzip-compressed inputs are supported. Specify sample names through `--child`,
   `--mother` and `--father`. Genotype quality filtering is available with
   `--min-gq`; genotype likelihoods are not used.
2. A panel VCF with phased diploid or haploid samples, or a tab-separated allele
   matrix. Each panel column identifies an assembly haplotype. In a diploid VCF,
   the two phased sample chromosomes become separate panel entries.
3. One autosomal region, using `CHROM:START-END` (1-based, inclusive).
4. `--build` records the coordinate reference you assert the inputs use. It is
   provenance, **not** a liftover or reference-sequence validation procedure.

Panel TSV example:

```text
CHROM  POS  REF  assembly_A_hap1  assembly_B_hap2
chr1   100  A    G                A
chr1   120  C    C                T
```

Use real tabs, A/C/G/T alleles, and `.` for missing. The same locus/reference
coordinates must be used in both files. A VCF REF disagreement is an error.
Allele order may differ: actual nucleotides, not numeric ALT indices, are
compared. Duplicate positions must be reconciled upstream; this prototype
does not silently combine split multiallelic records.

Only shared usable SNP calls enter the matching calculation. Missing VCF
records are **unknown**, never automatically homozygous reference. For gVCFs,
explicit reference-confidence blocks can supply calls at the panel's SNP
positions and explicit trio SNP anchors. Blocks must pass the checks described
below; uncovered positions remain unknown.
The panel must supply complete calls at each used marker across all candidate
haplotypes; incomplete markers are dropped globally, with diagnostics.

### Three individual VCFs

```bash
python -m triohap \
  --child-vcf examples/individual/child.vcf \
  --mother-vcf examples/individual/mother.vcf \
  --father-vcf examples/individual/father.vcf \
  --child child --mother mother --father father \
  --panel examples/panel.tsv \
  --region chr1:100-290 --build synthetic \
  --out example-run-individual
```

Supply all three paths together; they cannot be mixed with `--trio`. Each
sample ID selects a column in its corresponding file. Files may contain
additional samples. The same sample name (for example `SAMPLE`) is allowed
in different files; the CLI role specifies which family member it represents.

The reader compares coordinates and REF alleles, decodes each file's ALT
indices independently, and preserves the child's GT order and PS values.
Different ALT ordering or different called alternate alleles do not require
a joint-genotyping step. Known build/contig-length conflicts or disagreeing
REF alleles are errors; no liftover or allele normalization is performed.

Only sites with usable evidence for **all three** people enter the
current model. A missing parent record, `./.`, a failed FILTER/FT, or a call
below the requested GQ threshold cannot be replaced by `0/0`. Exclusions are
reported. This means variant-only individual VCFs can provide much less
evidence than joint VCFs with reference calls. Supply gVCFs, explicit all-sites
VCFs, or targeted genotypes when reference evidence is needed. An explicit
failed or missing call takes precedence over a covering reference block.

The three-file mode preserves parental uncertainty in exactly the same way
as the joint mode. It does not infer parental phase from the order of alleles
in unphased GTs, and it does not equate phase-set numbers across family members.

### Automatic gVCF input

Use the same arguments for `.vcf`, `.g.vcf`, `.gvcf`, or their gzip-compressed
versions. The filename does not decide the input type. For example:

```bash
triohap \
  --child-vcf child.g.vcf.gz --mother-vcf mother.g.vcf.gz --father-vcf father.vcf.gz \
  --child CHILD --mother MOTHER --father FATHER \
  --panel scn5a-panel/catalogue.json \
  --region chr3:38649188-38652187 --build GRCh38 \
  --min-gq 20 --out family-scn5a
```

Conventional `INFO/END` blocks with `<NON_REF>`, `<*>`, or nonvariant `ALT=.`
are supported. Block calls require diploid `0/0`, usable FILTER/FT, and a
present positive quality meeting `--min-gq`. The most conservative available
GQ/RGQ/GQX is used for blocks. Known zero DP or MIN_DP excludes a block call;
missing depth is recorded but does not by itself override usable quality.
Explicit SNP records may contain an unused wildcard ALT without losing their
literal genotype calls. Calling the wildcard itself remains unresolved.

Blocks are queried only at relevant SNP positions, including blocks beginning
before the requested region. Interior reference bases come from the same-build
panel or explicit SNP records, not the block's first base. The report shows
detected formats and reference-call counts; JSON records each expanded call's
source. See [GVCF.md](https://github.com/comparativechrono/TrioHap/blob/main/GVCF.md) for the precise rules and supported encodings.

This consumes hard-called evidence; it does not perform joint genotyping or
use PL/GL likelihoods. Newer VCF 4.5 sample-specific `FORMAT/LEN` blocks are
currently rejected with an explicit error. Indel/SV genotypes remain outside
the matching model.

The prototype accepts neither raw unaligned haplotype FASTA nor a GFA graph.
First project assembly haplotypes to comparable SNP coordinates, retaining
their original assembly IDs. FASTA-to-panel preparation is a separate proposed
module; it must resolve orthology, coordinate mapping and paralog ambiguity.

## Inference

At each Mendelian-consistent SNP, enumerate possible maternal and paternal
transmitted alleles conditional on the trio GTs. Do not force origin when all
three are heterozygous. For each ordered pair of panel haplotypes, sum over
the possible transmissions using mismatch-tolerant emissions. A match has
weight `1-epsilon`; a different nucleotide has weight `epsilon/3`.

For externally phased child SNPs, marginalize two **whole-block** orientations.
Informative trio SNPs anchor a block to parental origin. The first GT allele
is not inherently maternal. Separate PS blocks orient independently. Following
VCF semantics, phased GTs without PS share an implicit phase set on a chromosome.
Contradictory Mendelian anchors in one phase block cause an explicit error;
`--ignore-phase` deliberately discards external phase when investigating it.
Parent GT phase blocks are not modeled in this first version.

Panel haplotypes identical at the observed, scored markers form one equivalence
class. Ranking gives each distinct observed class equal prior weight; adding
duplicate assemblies does not inflate support. Pair scores are normalized
across **all** ordered class pairs before the top-N rows are reported.

The resulting relative weights are conditional on the chosen panel, markers,
hard calls, phase and mismatch parameter. They are **not calibrated clinical
posterior probabilities**. SNPs in LD are not independent observations of an
ancestral history. The score does not establish unobserved SVs or prove identity
to an entire assembly sequence. There is no 'none of the above' model: inspect
absolute mismatches and marker coverage even when relative weight is high.

## Outputs

- `matches.json`: model, provenance, classes, top ordered pairs, marginal
  rankings, marker evidence and diagnostics. It records input mode and file
  provenance. Under result schema `0.2`, `sources.trio` is a path for joint
  input and a role/file/sample object for individual input.
- `ranked_pairs.tsv`: best maternal/paternal class combinations.
- `diagnostics.tsv`: omitted, unmatched and problematic records.
- `mismatches.tsv`: observed alleles differing from the first best-scoring pair.
- `haplotype_graph.svg` / `.png`: SNP similarity network and observed-allele
  comparison, with two virtual proband chromosome nodes.
- `report.html`: self-contained report containing the graph and results.

Graph edges between panel nodes show a deterministic minimum spanning tree
of Hamming distances over the scored marker signatures. Edge labels count
different marker alleles. This is a compact similarity network, not a
genealogy, recombination graph or sequence-level pangenome graph. Dashed colored
links show leading marginal placements of each proband chromosome, including
ties. For large panels the image displays a stated subset; the JSON retains
all classes and marginals. The first listed pair in a tie is not a unique call.

## Optional Unfazed integration

The PyPI package matching the discussion appears to be
[unfazed-bioinformatics](https://pypi.org/project/unfazed-bioinformatics/), the
maintained fork of Jonathan Belyeu's Unfazed. Its identity as the user's package
has not been independently confirmed. It phases de novo variants to parental
origin; it is not a general regional haplotype matching program.

`--unfazed-vcf` accepts its documented parent-ordered VCF output as **annotation**
of additional variants. A provenance header stating `1|0 is paternal, 0|1 is
maternal` is required. Only confident evidence types UET 0/1/2 with phased GTs
are assigned to a parental background. Ambiguous evidence is retained without
an assignment. Sex-chromosome autophasing is outside this prototype. UOPS is
reported as a count, not converted to probability. These annotations do not
alter the panel ranking, avoiding double-counting the same reads/markers.
Sample FT filters, obvious declared build conflicts, and disagreements with
overlapping trio REF/GT calls are checked. Where metadata or trio calls are
absent, annotation consistency cannot be established from this file alone.

## Scope and next development steps

The current model is diploid, autosomal, SNP-based and fixed to one panel
haplotype per parental chromosome across the selected region. It excludes
Mendelian-inconsistent sites rather than estimating de novo or genotyping-error
probabilities. Indels/SVs/CNVs, sex chromosomes, mosaicism, PL/GL integration,
within-region recombination, parent phase propagation and a sparse-panel
missingness model remain future work. FASTA/GFA panel preparation and indexed
BCF/VCF access are also future work. Large files are streamed but not region
indexed. The pair search scales quadratically in distinct haplotype classes. Deterministic
phase contributions are cached; ambiguous-block work is capped at 25 million
pair/block combinations in this prototype.

Before clinical use: test on independent trios with assembly/long-read truth;
leave entire families out of the panel; evaluate private variants, phase-switch
errors, ancestry representation and missingness; calibrate no-call/ambiguity
criteria and sensitivity to epsilon. Do not infer clinical correctness from
the synthetic unit tests.

## Development and reproducibility

Run `python -m unittest discover -s tests -v` and
`python scripts/validate_synthetic.py` from the repository root. The latter
constructs known inherited haplotypes and independently encodes equivalent
joint and individual VCFs, then checks truth recovery and matching equivalence.
It also checks deliberate missingness. These are software correctness checks,
not estimates of performance on clinical data.

GitHub Actions runs the test suite on Python 3.10–3.13 and exercises graph
generation separately. `demo-output/` and `demo-individual-output/` contain equivalent synthetic
reports from the two input modes;
`scn5a-panel/` contains the imported reference catalogue and its panel audit.
Source tables used to create that catalogue are retained under
`reference-data/scn5a-promoter-pangenome/`, with their supplied license and
provenance. See [CHANGELOG.md](https://github.com/comparativechrono/TrioHap/blob/main/CHANGELOG.md)
and [VALIDATION.txt](https://github.com/comparativechrono/TrioHap/blob/main/VALIDATION.txt).

Release preparation and the exact PyPI Trusted Publisher settings are in
[PUBLISHING.md](https://github.com/comparativechrono/TrioHap/blob/main/PUBLISHING.md).
Packaging CI builds a wheel from the source archive, checks PyPI metadata,
and tests the installed wheel outside the checkout, including graph generation.
The project version is maintained in `triohap/__init__.py`.

TrioHap is licensed under the
[MIT licence](https://github.com/comparativechrono/TrioHap/blob/main/LICENSE).
The supplied SCN5A reference-data subset retains its own licence and attribution
under `reference-data/scn5a-promoter-pangenome/`.

The gVCF examples are in `examples/gvcf/`, with a rendered report in
`demo-gvcf-output/`. Run `python scripts/validate_gvcf.py` to compare known
synthetic families across ordinary VCF, joint gVCF, individual gVCF, and mixed
inputs, including deliberate reference-block gaps. The saved summary is
`validation/gvcf_summary.json`.

## Related components and specifications

- [Osprey](https://github.com/broadinstitute/Osprey): phased SNP reference
  haplotype matching for CNV/VNTR imputation. Its documented matching uses SNPs
  outside the target interval; it does not supply this combined trio workflow.
- [trioPhaser](https://pmc.ncbi.nlm.nih.gov/articles/PMC8607709/): trio-based
  phasing using Mendelian rules plus statistical phasing.
- [VCF 4.5 specification](https://samtools.github.io/hts-specs/VCFv4.5.pdf): phase
  set and genotype semantics.
- [Unfazed paper](https://academic.oup.com/bioinformatics/article/37/24/4860/6306405)
  and the maintained PyPI distribution linked above.

No external tool's implementation is incorporated into the matching engine.
