Structural variant annotation¶
Load structural variants (SVs) with an explicit VCF option, then use the same
effects() interface as for small variants.
Basic usage¶
from varcode import load_vcf
variants = load_vcf(
"structural_variants.vcf",
genome=81, # GRCh38; use the annotation chosen for your input
parse_structural_variants=True,
)
effects = variants.effects()
for effect in effects:
if effect.variant.is_structural:
print(effect.variant.sv_type, effect.short_description)
print(effect.mutant_protein_sequence) # may be None
Without parse_structural_variants=True, symbolic alleles and breakends are
skipped with a warning. No separate annotator selection is needed.
Reference setup explains the genome argument.
Reading SV results¶
Effects include LargeDeletion, LargeDuplication, Inversion, GeneFusion,
and TranslocationToIntergenic. They may contain alternatives in .candidates;
see alternative outcomes.
A DNA rearrangement does not by itself establish a complete expressed fusion
protein. Sequence may be unknown or partial; None is not an unchanged protein.
Filtering by protein change¶
retained = effects.drop_silent_and_noncoding()
# Require a positive prediction of protein change, excluding unknowns:
resolved_changes = effects.drop_silent_and_noncoding(keep_unresolved=False)
SV effects report modifies_protein_sequence and modifies_coding_sequence as
True (changed), False (unchanged), or None (unresolved). A changed CDS can
still encode the same protein. Comparisons use the transcript being annotated;
for a fusion, the 5′ partner supplies the initiation site.
The flags cover the whole candidate set: any changed alternative makes the flag
True; otherwise an unresolved alternative makes it None. The filter retains
the original set, including provenance, rather than selecting one candidate.
Unresolved effects are kept by default. To test for a known unchanged SV, use
effect.modifies_protein_sequence is False, not not effect.modifies_protein_sequence.
These flags describe existing predictions; they do not establish expression.
Partial BND fragments and assemblies without a mapped ORF stay unresolved.
So do partial observations (protein_completeness other than start_to_stop)
unless a mapped, in-frame observed codon differs from the reference.
The filter does not construct missing proteins or change the effect class.
Selenocysteine (U in the Ensembl reference protein) is encoded by UGA,
which is decoded as Sec only with a SECIS element in the mRNA's 3′ UTR.
Ensembl doesn't annotate SECIS positions. A fusion's stored protein reads Sec
unless no selenoprotein 3′ UTR remains (transcript models).
For the flags, UGA is read as Sec where a model keeps
the transcript intact from that codon through its 3′ end, and as a stop where
no selenoprotein 3′ UTR remains. Otherwise the protein flag is reported only if
both readings agree, else None; for example, a partial 3′ UTR deletion leaves
the protein unresolved. The coding flag compares CDS bases, which don't depend
on how Sec is decoded.
A start codon other than ATG counts as the initiator methionine, even though
Ensembl writes CTG and TTG starts as L.
Fusion protein candidates¶
For an annotated effect, inspect every compatible partner isoform rather than only the protein on the first result:
from varcode.effects import GeneFusion
for candidate in effect.candidates:
fusion = candidate.effect
if isinstance(fusion, GeneFusion):
print(fusion.five_prime_transcript.id, fusion.three_prime_transcript.id)
print(fusion.mutant_protein_sequence) # None when unresolved
There is no candidate-count cap. Distinct transcript pairs remain separate even when their predicted proteins match. The first candidate follows annotation order, not measured likelihood. These are reference-isoform predictions, not every possible splice/phase combination or evidence that a fusion is expressed. See fusion rules and RNA imports.
Which transcripts get annotated¶
effects() produces one effect per overlapping transcript, as for any
variant. What "overlapping" means depends on the SV:
| Variant | Transcripts annotated |
|---|---|
Breakend record (BND) |
Those at its own breakpoint. The mate's transcripts are annotated from the mate's record. |
DEL, DUP, INV, INS, CNV |
Every transcript overlapping start..end. |
Two outcomes apply before any SV logic:
- No gene at the variant's position(s) → a single
Intergeniceffect. - A non-coding transcript →
NoncodingTranscript.
Pairing breakend records¶
pair_breakends joins the two records of a breakend pair:
- If both carry the same
SVTYPEofDEL,DUPorINVand their kept sides fit it, the result is that typed event, annotated over its whole span. See pairing rules and examples. - Otherwise the result is one
BNDanchored at the record whose VCF ID sorts first, and only that end's transcripts are annotated. If that end is intergenic the combined variant reports justIntergenic; the other end is still reachable throughcombined.source_variants.
Effect classes¶
| Class | Meaning |
|---|---|
GeneFusion |
The SV joins this transcript sense-to-sense with a coding transcript in another gene. |
TranslocationToIntergenic |
A breakend in this transcript that doesn't form a gene fusion. |
LargeDeletion |
A deletion (or <CN0>) removing one or more exons. |
LargeDuplication |
A duplication, insertion or CNV overlapping exons. |
Inversion |
An inversion overlapping exons. |
Intronic |
A span inside the transcript that overlaps no exon. |
Intergenic |
No gene at the variant's position. |
NoncodingTranscript |
The transcript isn't protein-coding. |
Limitations¶
- Partner isoforms are enumerated but not ranked by RNA support or likelihood.
- Chains of several SVs aren't assembled into one allele, and regulatory effects (promoter or enhancer hijacking) aren't modeled.
- Annotating multi-megabase spans can be slow (#407).