Genotypes and sample-aware queries¶
When you load a multi-sample VCF, Varcode keeps each sample's genotype
fields (GT, AD, DP, GQ, PS). You can read them as Genotype objects, or use
them to select the variants a particular sample carries.
The basics¶
from varcode import load_vcf
vc = load_vcf("tumor_normal.vcf", genome="GRCh38")
vc.samples
# ['normal', 'tumor']
vc.has_sample_data()
# True
One variant, one sample¶
variant = vc[0]
gt = vc.genotype(variant, "tumor")
# Genotype(raw_gt='0/1', alleles=(0, 1), phased=False, phase_set=None,
# allele_depths=(10, 5), total_depth=15, genotype_quality=99)
gt.is_called # True
gt.alleles # (0, 1)
gt.phased # False
gt.allele_depths # (10, 5) — (ref_depth, alt_depth)
gt.total_depth # 15
gt.depth_for_alt(1) # 5
Zygosity is relative to this variant's alt¶
from varcode import Zygosity
vc.zygosity(variant, "tumor")
# <Zygosity.HETEROZYGOUS: 'het'>
vc.zygosity(variant, "normal")
# <Zygosity.ABSENT: 'absent'> — normal is ref/ref at this site
Four states, relative to the alt of the Variant you query:
| State | Meaning |
|---|---|
HETEROZYGOUS |
Sample has at least one copy of this alt, and not all copies are this alt |
HOMOZYGOUS |
All called copies are this alt |
ABSENT |
Sample was called, but doesn't carry this alt (ref/ref, or a different alt at a multi-allelic site) |
MISSING |
Sample's call was ./. or the sample wasn't called |
Filtering¶
These return filtered VariantCollections:
# Variants where this sample carries the alt (het or hom).
vc.for_sample("tumor")
# Finer distinctions:
vc.heterozygous_in("tumor")
vc.homozygous_alt_in("tumor")
Typoed sample names fail fast:
vc.for_sample("typo")
# SampleNotFoundError: Sample 'typo' not found. Available samples: ['normal', 'tumor']
Cross-sample queries¶
Tumor/normal, trio, and cohort queries fall out of set operations on the primitives:
# Somatic candidates: in tumor, not in normal.
tumor = set(vc.for_sample("tumor"))
normal = set(vc.for_sample("normal"))
somatic = tumor - normal
# De novo candidates in a trio.
de_novo = (set(vc.for_sample("child"))
- set(vc.for_sample("mom"))
- set(vc.for_sample("dad")))
These are genotype comparisons, not somatic or de novo calling. A variant
counts as absent from the normal whenever the normal doesn't carry it,
including when the normal has no call at that site (MISSING). Check
vc.zygosity(variant, "normal") if that distinction matters. To check whether
samples are labelled with the right donor, see
sample identity checks.
Multi-allelic sites¶
VCF rows like REF=A ALT=T,G are split into two Variant objects
(one per alt). zygosity is computed relative to the specific alt of
the variant you query, so a sample with GT=1/2 is reported as
heterozygous for both A→T and A→G (one copy of each, with the other
copy being a different alt). A sample with GT=0/1 (one ref, one T)
is heterozygous for A→T and ABSENT for A→G.
This means vc.heterozygous_in("tumor") on a row where tumor is 1/2
yields two entries, one per alt — the correct biological
interpretation.
Beyond zygosity: phased and germline-aware effects¶
The Genotype API gives you the data; downstream effect prediction uses it when you explicitly provide a phase resolver or germline context:
- Phased effects of cis variants — when two variants share a
phase set, varcode builds a joint
HaplotypeEffectviaeffects(phase_resolver=...). See phasing. - Germline-aware somatic annotation — pass a
GermlineContexttoeffects(germline=...)and somatic variants are classified against the patient's germline-applied transcript. See Germline-aware annotation.
There are no dedicated helpers such as vc.de_novo_in(...) or
vc.somatic(...); use the set operations above.