Annotation Filters¶
Overview¶
AnnotationFilter lets you restrict variant queries by
annotation criteria — consequence, impact, allele frequency, predictive
scores, clinical significance, and more. Pass it via the annotations
parameter to any of these methods:
AND/OR semantics: different fields are AND’d together; multiple values
within a single field are OR’d. For example, if you set
consequence=[Consequence.MISSENSE_VARIANT, Consequence.STOP_GAINED] and
impact=[Impact.HIGH], Dnaerys returns variants that match (MISSENSE_VARIANT
OR STOP_GAINED) AND (HIGH impact).
All enum fields accept either enum members or case-insensitive strings:
from dnaerys import AnnotationFilter, Consequence
# These are equivalent:
ann = AnnotationFilter(consequence=[Consequence.MISSENSE_VARIANT])
ann = AnnotationFilter(consequence=["MISSENSE_VARIANT"])
ann = AnnotationFilter(consequence=["missense_variant"])
Variant consequences and impact (VEP)¶
The Consequence enum has 41 members corresponding to
Sequence Ontology consequence terms.
Each consequence is assigned an Impact level by VEP.
High impact consequences cause protein truncation or loss of function:
TRANSCRIPT_ABLATIONSPLICE_ACCEPTOR_VARIANT,SPLICE_DONOR_VARIANTSTOP_GAINED,STOP_LOST,START_LOSTFRAMESHIFT_VARIANTTRANSCRIPT_AMPLIFICATION
Moderate impact consequences alter the protein but do not truncate it:
MISSENSE_VARIANTINFRAME_INSERTION,INFRAME_DELETIONPROTEIN_ALTERING_VARIANT
Low impact consequences are unlikely to change protein behaviour:
SYNONYMOUS_VARIANTSPLICE_REGION_VARIANTSTART_RETAINED_VARIANT,STOP_RETAINED_VARIANT
Modifier consequences affect non-coding or intergenic regions:
INTRON_VARIANTUPSTREAM_GENE_VARIANT,DOWNSTREAM_GENE_VARIANTINTERGENIC_VARIANT
Filtering by individual consequences¶
from dnaerys import DnaerysClient, Region, AnnotationFilter, Consequence
with DnaerysClient("db.dnaerys.org:443") as client:
ann = AnnotationFilter(consequence=[
Consequence.STOP_GAINED,
Consequence.FRAMESHIFT_VARIANT,
Consequence.SPLICE_ACCEPTOR_VARIANT,
Consequence.SPLICE_DONOR_VARIANT,
])
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
):
print(v)
Using Impact as a shortcut¶
Instead of listing every high-impact consequence individually, use the
Impact enum:
from dnaerys import DnaerysClient, Region, AnnotationFilter, Impact
with DnaerysClient("db.dnaerys.org:443") as client:
ann = AnnotationFilter(impact=[Impact.HIGH])
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
):
print(v)
Combining consequence and impact¶
Fields are AND’d, so you can combine them for precision — for example, to select only missense variants that VEP classifies as moderate impact:
ann = AnnotationFilter(
consequence=[Consequence.MISSENSE_VARIANT],
impact=[Impact.MODERATE],
)
Variant types¶
The VariantType enum has 34 members covering short variants
and structural variants. Common short variant types:
SNV— single nucleotide variantINSERTION,DELETION,INDELSUBSTITUTION
See Ensembl variant classes for the full classification.
Filtering to SNVs only¶
from dnaerys import DnaerysClient, Region, AnnotationFilter, VariantType
with DnaerysClient("db.dnaerys.org:443") as client:
ann = AnnotationFilter(variant_type=[VariantType.SNV])
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
limit=10
):
print(v)
Clinical significance (ClinVar)¶
The ClinSignificance enum has 19 members corresponding to
ClinVar clinical significance categories. Common values:
PATHOGENICLIKELY_PATHOGENICUNCERTAIN_SIGNIFICANCELIKELY_BENIGNCLNSIG_BENIGNCONFLICTING_INTERPRETATIONS
Other values include DRUG_RESPONSE, RISK_FACTOR, PROTECTIVE,
PATHOGENIC_LOW_PENETRANCE, LIKELY_RISK_ALLELE, and more.
from dnaerys import DnaerysClient, Region, AnnotationFilter, ClinSignificance
with DnaerysClient("db.dnaerys.org:443") as client:
ann = AnnotationFilter(clin_significance=[
ClinSignificance.PATHOGENIC,
ClinSignificance.LIKELY_PATHOGENIC,
])
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
):
print(f"{v.start} {v.ref}>{v.alt}")
String aliases work the same way:
ann = AnnotationFilter(clin_significance=["PATHOGENIC", "LIKELY_PATHOGENIC"])
Predictive scores¶
AlphaMissense¶
AlphaMissense
predicts pathogenicity of missense variants. You can filter by either
categorical class or numeric score, but not both — combining them raises
ValueError because the server silently ignores am_class when score
bounds are present.
The AlphaMissense enum has three members:
AM_LIKELY_BENIGN— score < 0.34AM_AMBIGUOUS— score 0.34–0.564AM_LIKELY_PATHOGENIC— score > 0.564
Filtering by class:
from dnaerys import DnaerysClient, Region, AnnotationFilter, AlphaMissense
with DnaerysClient("db.dnaerys.org:443") as client:
ann = AnnotationFilter(am_class=[AlphaMissense.AM_LIKELY_PATHOGENIC])
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
):
print(f"{v.start} {v.ref}>{v.alt} AM={v.am_score}")
Filtering by score range:
# Variants with AlphaMissense score > 0.8
ann = AnnotationFilter(am_score_gt=0.8)
Mutual exclusivity — this raises ValueError:
# ValueError: am_score_lt/am_score_gt and am_class are mutually exclusive
ann = AnnotationFilter(
am_score_gt=0.5,
am_class=[AlphaMissense.AM_LIKELY_PATHOGENIC],
)
Note
The examples below using CADD, PolyPhen, and SIFT will not yield variants
against db.dnaerys.org:443 because the KGP dataset is not annotated
with these scores due to license restrictions.
CADD¶
CADD (Combined Annotation Dependent Depletion) scores are available in two forms:
Raw score (
cadd_raw_lt/cadd_raw_gt) — the untransformed score.Phred-scaled score (
cadd_phred_lt/cadd_phred_gt) — a rank-based score that is more interpretable:Phred > 10 → top 10% most deleterious
Phred > 20 → top 1% most deleterious
Phred > 30 → top 0.1% most deleterious
In practice, a CADD phred threshold of 20 or higher is a common filter for potentially deleterious variants.
from dnaerys import DnaerysClient, Region, AnnotationFilter
with DnaerysClient("db.dnaerys.org:443") as client:
# Variants in the top 1% most deleterious by CADD
ann = AnnotationFilter(cadd_phred_gt=20)
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
):
print(f"{v.start} {v.ref}>{v.alt} CADD={v.cadd_phred}")
# Using both bounds to define a range
ann = AnnotationFilter(cadd_phred_gt=20, cadd_phred_lt=30)
PolyPhen¶
The PolyPhen enum predicts the impact of amino acid
substitutions:
PROBABLY_DAMAGINGPOSSIBLY_DAMAGINGBENIGNUNKNOWN
from dnaerys import DnaerysClient, Region, AnnotationFilter, PolyPhen
with DnaerysClient("db.dnaerys.org:443") as client:
ann = AnnotationFilter(polyphen=[PolyPhen.PROBABLY_DAMAGING])
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
):
print(f"{v.start} {v.ref}>{v.alt}")
SIFT¶
The SIFT enum predicts whether an amino acid substitution
affects protein function:
DELETERIOUSTOLERATED
from dnaerys import DnaerysClient, Region, AnnotationFilter, SIFT
with DnaerysClient("db.dnaerys.org:443") as client:
ann = AnnotationFilter(sift=[SIFT.DELETERIOUS])
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
):
print(f"{v.start} {v.ref}>{v.alt}")
Population frequency filters¶
All frequency filters use strict inequality: af_lt means “AF < value”
and af_gt means “AF > value”. Setting a filter to None (the default)
disables it.
Dataset allele frequency¶
af_lt and af_gt filter by the allele frequency within the loaded
dataset itself:
from dnaerys import DnaerysClient, Region, AnnotationFilter
with DnaerysClient("db.dnaerys.org:443") as client:
# Rare variants: dataset AF < 1%
ann = AnnotationFilter(af_lt=0.01)
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
limit=100
):
print(f"{v.start} AF={v.af}")
gnomAD exomes¶
gnomad_exomes_af_lt and gnomad_exomes_af_gt filter by the allele
frequency in gnomAD exomes (proto field gnomADe):
# Variants with gnomAD exomes AF < 0.001 (very rare in gnomAD)
ann = AnnotationFilter(gnomad_exomes_af_lt=0.001)
gnomAD genomes¶
gnomad_genomes_af_lt and gnomad_genomes_af_gt filter by the allele
frequency in gnomAD genomes (proto field gnomADg):
# Variants absent from or very rare in gnomAD genomes
ann = AnnotationFilter(gnomad_genomes_af_lt=0.0001)
The 0.0 sentinel and gnomAD presence¶
Variants not annotated in gnomAD have an AF of 0.0. This means
gnomad_exomes_af_gt=0 selects only variants that are present in
gnomAD exomes (i.e. AF > 0.0):
# Only variants that exist in gnomAD exomes
ann = AnnotationFilter(gnomad_exomes_af_gt=0)
Conversely, there is no direct way to select variants absent from gnomAD using frequency filters alone.
Important: ``gnomad_exomes_af_lt`` with any positive threshold will NOT include unannotated variants (AF = 0.0).
Feature and biotype filters (VEP)¶
FeatureType¶
The FeatureType enum controls which VEP feature types are
included:
TRANSCRIPT— gene transcriptsREGULATORYFEATURE— regulatory elements from the Ensembl Regulatory BuildMOTIFFEATURE— transcription factor binding motifs
BioType¶
The BioType enum has 47 members covering transcript biotypes
and regulatory biotypes.
Common transcript biotypes:
PROTEIN_CODINGLNCRNA,LINCRNA,ANTISENSENONSENSE_MEDIATED_DECAYPSEUDOGENE,PROCESSED_PSEUDOGENEMIRNA,SNRNA,SNORNA,RRNA
Regulatory biotypes:
PROMOTER,PROMOTER_FLANKING_REGIONENHANCERCTCF_BINDING_SITEOPEN_CHROMATIN_REGION
See Ensembl biotypes for the full list.
Filtering to protein-coding transcripts¶
from dnaerys import DnaerysClient, Region, AnnotationFilter, BioType
with DnaerysClient("db.dnaerys.org:443") as client:
ann = AnnotationFilter(bio_type=[BioType.PROTEIN_CODING])
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
limit=100
):
print(f"{v.start} {v.ref}>{v.alt}")
Combining feature type and biotype¶
from dnaerys import AnnotationFilter, FeatureType, BioType
# Only variants affecting regulatory enhancers
ann = AnnotationFilter(
feature_type=[FeatureType.REGULATORYFEATURE],
bio_type=[BioType.ENHANCER],
)
Exclusion flags¶
biallelic_only / multiallelic_only¶
These boolean flags control whether to include only biallelic or only
multiallelic variant sites. They are mutually exclusive — setting both
to True raises ValueError.
from dnaerys import DnaerysClient, Region, AnnotationFilter
with DnaerysClient("db.dnaerys.org:443") as client:
# Only biallelic sites
ann = AnnotationFilter(biallelic_only=True)
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
):
print(f"{v.start} biallelic={v.biallelic}")
# Only multiallelic sites
ann = AnnotationFilter(multiallelic_only=True)
exclude_males / exclude_females¶
These flags exclude samples by sex. They are mutually exclusive —
setting both to True raises ValueError (the result set would be
empty).
from dnaerys import DnaerysClient, Region, AnnotationFilter
with DnaerysClient("db.dnaerys.org:443") as client:
# Exclude male samples
ann = AnnotationFilter(exclude_males=True)
count = client.count_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
)
print(f"Variants in females only: {count.count}")
Combining filters¶
Since different fields are AND’d, you can build complex queries that combine multiple filter categories. Here is an example that selects high impact heterozygous variants in transcripts in TP53:
from dnaerys import DnaerysClient, Region, AnnotationFilter, FeatureType, Impact
with DnaerysClient("db.dnaerys.org:443") as client:
ann = AnnotationFilter(
impact=[Impact.HIGH],
feature_type=[FeatureType.TRANSCRIPT],
)
for v in client.select_variants(
region=Region("chr17", 7661779, 7687546),
annotations=ann,
hom=False,
het=True,
):
print(v)
The same AnnotationFilter instance can be reused across
multiple queries or combined with sample-level parameters on methods like
select_variants_with_stats() and the
inheritance methods.
Validation rules summary¶
AnnotationFilter validates its fields at construction time.
The following table summarises which combinations raise ValueError versus
emit a warning:
Condition |
Result |
Reason |
|---|---|---|
|
|
Mutually exclusive |
|
|
Would produce an empty result set |
|
|
Server silently ignores |
|
|
Empty range — no value can satisfy both bounds |
|
|
Empty range |
|
|
Empty range |
|
|
Empty range |
|
|
Empty range |
|
|
Empty range |
Unrecognised enum string value |
|
Raised by enum resolution during construction |