Skip to content

Sample identity API

See sample identity checks for selecting inputs, interpreting diagnostics, and using the CLI. These checks compare supplied variant evidence; they do not assign a patient identity from a filename.

Configuration and inputs

varcode.SampleCheckConfig(min_depth: int = 10, min_gq: int = 20, require_quality: bool = False, min_shared_snps: int = 100, min_nonreference_snps: int = 20, min_homozygous_snps: int = 20, min_tumor_hom_reference_snps: int = 20, min_genomic_bins: int = 20, genomic_bin_size: int = 100000, max_snps: int = 50000, max_somatic_variants: int = 100000, compatible_concordance: float = 0.98, discordant_concordance: float = 0.9, max_compatible_ibs0: float = 0.01, min_discordant_ibs0: float = 0.05, min_somatic_variants: int = 10, min_shared_somatic: int = 5, min_somatic_overlap: float = 0.2, min_tumor_alt_reads: int = 3, min_tumor_vaf: float = 0.03, max_normal_alt_reads: int = 1, max_normal_vaf: float = 0.02) dataclass

Configurable, uncalibrated screening thresholds (all reported in output).

Missing DP/GQ are counted but accepted unless require_quality is true. SNPs use a deterministic, genotype-independent bottom-k locus sketch. The somatic limit raises an error instead of silently truncating evidence.

varcode.SampleSpec(sample: str, role: Optional[str] = None, label: Optional[str] = None, donor_id: Optional[str] = None, tumor_id: Optional[str] = None, normal_sample: Optional[str] = None) dataclass

Select a VCF column and optionally declare its role and expected identity.

PARAMETER DESCRIPTION
sample

Exact VCF column name. Names are never interpreted as biological roles.

TYPE: str

role

germline, normal or tumor. Ambiguous somatic/mixed inputs require roles here or in tumor_sample/normal_sample header metadata.

TYPE: str DEFAULT: None

label

Unique report identifier; defaults to absolute path plus sample name.

TYPE: str DEFAULT: None

donor_id

Expected identities used to flag contradictions, not scoring inputs.

TYPE: str DEFAULT: None

tumor_id

Expected identities used to flag contradictions, not scoring inputs.

TYPE: str DEFAULT: None

normal_sample

Matched normal column in the same VCF (may be unselected for output).

TYPE: str DEFAULT: None

varcode.SampleFingerprint(label: str, sample: str, path: str, sha256: str, assembly: str, kind: str, role: str, config: SampleCheckConfig, donor_id: Optional[str] = None, tumor_id: Optional[str] = None, normal_sample: Optional[str] = None, snps: dict = dict(), somatic: dict = dict(), qc: Counter = Counter()) dataclass

Loaded evidence with input provenance and exclusion counts.

Construct with :func:load_vcf_samples. snps maps (chromosome, position) to (reference base, sorted diploid base genotype), or None for a conflicting locus. somatic maps normalized allele keys to VAF or None. Report serialization omits these potentially large, identifying maps.

summary()

Return JSON-compatible metadata and QC, excluding genotypes.

Source code in varcode/sample_identity.py
def summary(self):
    """Return JSON-compatible metadata and QC, excluding genotypes."""
    result = {key: getattr(self, key) for key in (
        "label", "sample", "path", "sha256", "assembly", "kind", "role",
        "donor_id", "tumor_id", "normal_sample")}
    result.update(qc=dict(self.qc), retained_snps=sum(v is not None for v in self.snps.values()),
                  somatic_variants=len(self.somatic))
    return result

Loading and comparison

varcode.load_vcf_samples(path, *, kind='germline', assembly=None, samples=None, config=None)

Stream a local VCF/VCF.gz into selected sample fingerprints.

PARAMETER DESCRIPTION
path

Local VCF, optionally gzip compressed. No annotation data is needed.

TYPE: str or Path

kind

germline, somatic (caller-reported somatic records), or mixed. Mixed tumor calls require SOMATIC or an explicit matched-normal contrast.

TYPE: str DEFAULT: 'germline'

assembly

GRCh37/hg19/b37 or GRCh38/hg38. Required if the header is unrecognized. An explicit value may not contradict a recognized header reference.

TYPE: str DEFAULT: None

samples

Selection, roles and expectations. Default: all VCF sample columns.

TYPE: iterable of SampleSpec DEFAULT: None

config

Shared loading and scoring thresholds for the cohort.

TYPE: SampleCheckConfig DEFAULT: None

RETURNS DESCRIPTION
list of SampleFingerprint

One entry per selected column, including samples with no usable calls.

Source code in varcode/sample_identity.py
def load_vcf_samples(path, *, kind="germline", assembly=None, samples=None, config=None):
    """Stream a local VCF/VCF.gz into selected sample fingerprints.

    Parameters
    ----------
    path : str or pathlib.Path
        Local VCF, optionally gzip compressed. No annotation data is needed.
    kind : str
        ``germline``, ``somatic`` (caller-reported somatic records), or ``mixed``.
        Mixed tumor calls require SOMATIC or an explicit matched-normal contrast.
    assembly : str, optional
        GRCh37/hg19/b37 or GRCh38/hg38. Required if the header is unrecognized.
        An explicit value may not contradict a recognized header reference.
    samples : iterable of SampleSpec, optional
        Selection, roles and expectations. Default: all VCF sample columns.
    config : SampleCheckConfig, optional
        Shared loading and scoring thresholds for the cohort.

    Returns
    -------
    list of SampleFingerprint
        One entry per selected column, including samples with no usable calls.
    """
    from ._sample_vcf import read_samples
    return read_samples(path, kind, assembly, samples, config or SampleCheckConfig())

varcode.compare_samples(a, b, *, config=None)

Return pairwise donor/tumor evidence and expectation flags as a dict.

Both fingerprints must have been loaded with the same config. Different assemblies yield inconclusive results. flags are review prompts; only expected_donor_mismatch sets identity_conflict to true.

Source code in varcode/sample_identity.py
def compare_samples(a, b, *, config=None):
    """Return pairwise donor/tumor evidence and expectation flags as a dict.

    Both fingerprints must have been loaded with the same config. Different
    assemblies yield inconclusive results. ``flags`` are review prompts;
    only ``expected_donor_mismatch`` sets ``identity_conflict`` to true.
    """
    config = config or a.config
    if a.config != config or b.config != config:
        raise ValueError("Load all samples with the comparison config")
    if a.assembly != b.assembly:
        germline = dict(status="inconclusive", reasons=["assembly_mismatch"])
        somatic = dict(status="inconclusive", reasons=["assembly_mismatch"])
    else:
        germline, somatic = _germline(a, b, config), _somatic(a, b, config)
    paired = a.path == b.path and (a.normal_sample == b.sample or b.normal_sample == a.sample)
    same_donor = a.donor_id == b.donor_id if a.donor_id and b.donor_id else None
    same_tumor = a.tumor_id == b.tumor_id if a.tumor_id and b.tumor_id else None
    flags = []
    if paired and same_donor is False:
        flags.append("paired_normal_has_different_donor_label")
    if same_tumor is True and same_donor is False:
        flags.append("same_tumor_has_different_donor_labels")
    if (same_donor is True or paired or same_tumor is True) and germline["status"] == "discordant":
        flags.append("expected_donor_mismatch")
    if same_donor is False and germline["status"] == "compatible":
        flags.append("unexpected_donor_compatibility")
    if same_tumor is True and somatic["status"] == "low_overlap":
        flags.append("expected_tumor_low_overlap")
    if same_tumor is False and somatic["status"] == "shared_somatic_support":
        flags.append("unexpected_tumor_overlap")
    return dict(sample_a=a.label, sample_b=b.label, expected_same_donor=same_donor,
                paired_tumor_normal=paired, expected_same_tumor=same_tumor,
                germline=germline, somatic=somatic, flags=flags,
                identity_conflict="expected_donor_mismatch" in flags)

varcode.check_sample_identity(samples, *, config=None)

Check every unordered pair and return a JSON-compatible cohort report.

At least two uniquely labelled samples are required. No automatic renaming or definitive swap assignment is performed. Config, sample QC, provenance, all pairs and heuristic limitations are included for reproducibility.

Source code in varcode/sample_identity.py
def check_sample_identity(samples, *, config=None):
    """Check every unordered pair and return a JSON-compatible cohort report.

    At least two uniquely labelled samples are required. No automatic renaming
    or definitive swap assignment is performed. Config, sample QC, provenance,
    all pairs and heuristic limitations are included for reproducibility.
    """
    from .version import __version__
    samples = list(samples)
    if len(samples) < 2:
        raise ValueError("At least two samples are required")
    if len({s.label for s in samples}) != len(samples):
        raise ValueError("Sample labels must be unique across the cohort")
    if len({(s.path, s.sample) for s in samples}) != len(samples):
        raise ValueError("The same VCF sample was supplied more than once")
    config = config or samples[0].config
    pairs = [compare_samples(a, b, config=config) for a, b in combinations(samples, 2)]
    return dict(schema_version=1, varcode_version=__version__, config=asdict(config),
                samples=[s.summary() for s in samples], pairs=pairs,
                identity_conflicts=sum(p["identity_conflict"] for p in pairs),
                limitations=["Uncalibrated screening heuristics, not identity probabilities or proof.",
                             "Absent variants are unknown, not reference calls.",
                             "Relatives, twins, LOH, contamination and assay differences can confound results.",
                             "Low somatic overlap does not establish a different donor or tumor."])