--- title: "Variant Annotation Guide" task: "" lineage_type: import upstream_source: https://github.com/mims-harvard/ToolUniverse/blob/e2520a96/skills/tooluniverse-variant-analysis/references/annotation_guide.md upstream_sha: e2520a96 imported_at: 2026-06-26 prompt_class: prompt upstream_changes: accepted author: upstream validated: false --- # Variant Annotation Guide Complete guide to annotating variants using ToolUniverse annotation tools. ## When to Use ToolUniverse Annotation Use ToolUniverse annotation tools when you need: 1. **Clinical significance**: ClinVar pathogenicity classifications 2. **Population frequencies**: gnomAD, ExAC, 1000 Genomes allele frequencies 3. **Pathogenicity scores**: CADD, SIFT, PolyPhen predictions 4. **Gene/transcript information**: Ensembl gene IDs, transcript IDs, protein changes 5. **Consequence prediction**: When VCF lacks annotation ## Annotation Tools Overview | Tool | Best For | Input Format | Response | |------|---------|--------------|----------| | `MyVariant_query_variants` | Batch annotation (recommended) | rsID or HGVS | ClinVar, dbSNP, gnomAD, CADD, SIFT, PolyPhen | | `MyVariant_get_variant_annotation` | Single variant detail | HGVS | Full annotation object | | `dbsnp_get_variant_by_rsid` | Population frequencies | rsID (rs12345) | Allele frequencies, clinical significance | | `gnomad_get_variant` | gnomAD-specific data | CHR-POS-REF-ALT | gnomAD variant metadata | | `EnsemblVEP_annotate_rsid` | Consequence prediction | rsID | Transcript consequences | | `ensembl_vep_region` | Regional annotation | chr:start-end | All variants in region | ## Annotation Workflow ### Step 1: Parse VCF and Extract rsIDs ```python from python_implementation import parse_vcf vcf_data = parse_vcf("variants.vcf") # Extract variants with rsIDs (most reliable for annotation) rsid_variants = [v for v in vcf_data.variants if v.vid and v.vid.startswith('rs')] print(f"Found {len(rsid_variants)} variants with rsIDs") ``` ### Step 2: Batch Annotate with MyVariant.info **MyVariant.info is recommended** because it aggregates multiple sources in one call. ```python from tooluniverse import ToolUniverse from python_implementation import batch_annotate_variants # Load ToolUniverse tu = ToolUniverse() tu.load_tools() # Annotate up to 100 variants annotations = batch_annotate_variants( tu, vcf_data.variants, max_annotate=100 # Respect rate limits ) # Process annotations for ann in annotations: print(f"{ann.variant_key} - {ann.gene_symbol}") print(f" ClinVar: {ann.clinvar_classification}") print(f" gnomAD AF: {ann.gnomad_af}") print(f" CADD: {ann.cadd_phred}") ``` ### Step 3: Query Specific Tools for Additional Data For specific use cases, query tools directly: ```python # Get detailed population frequencies from dbSNP dbsnp_result = tu.execute_tool("dbsnp_get_variant_by_rsid", rsid="rs699") # Get gnomAD-specific data gnomad_result = tu.execute_tool("gnomad_get_variant", variant_id="1-55039974-G-A") # Get VEP consequence prediction vep_result = tu.execute_tool("EnsemblVEP_annotate_rsid", variant_id="rs699") ``` ## MyVariant.info Annotation ### Query Variants (Batch) **Best for**: Annotating multiple variants at once ```python # Query by rsID result = tu.execute_tool("MyVariant_query_variants", query="rs699 rs334") # Query by HGVS result = tu.execute_tool("MyVariant_query_variants", query="chr7:g.140753336A>T") ``` **Response structure**: ```json { "data": { "hits": [ { "_id": "chr7:g.140753336A>T", "dbsnp": { "rsid": "rs113488022", "gene": {"symbol": "BRAF"} }, "clinvar": { "rcv": { "clinical_significance": "Pathogenic", "conditions": {"name": "Melanoma, malignant"} } }, "gnomad_genome": { "af": {"af": 0.000008} }, "cadd": { "phred": 34.0 } } ] } } ``` ### Get Variant Annotation (Single) **Best for**: Detailed information on one variant ```python result = tu.execute_tool("MyVariant_get_variant_annotation", variant_id="chr7:g.140753336A>T") ``` ### Extracted Fields From MyVariant.info response, we extract: | Field | Path | Description | |-------|------|-------------| | rsID | `dbsnp.rsid` | dbSNP identifier | | Gene symbol | `dbsnp.gene.symbol` | Gene name | | ClinVar classification | `clinvar.rcv.clinical_significance` | Pathogenicity | | ClinVar disease | `clinvar.rcv.conditions.name` | Associated condition | | gnomAD allele frequency | `gnomad_genome.af.af` | Population frequency | | CADD PHRED | `cadd.phred` | Deleteriousness score | | SIFT prediction | `cadd.sift.pred` | Functional prediction | | PolyPhen prediction | `cadd.polyphen.pred` | Functional prediction | | Protein change | `dbsnp.gene.hgvs_c` | HGVS protein notation | ## dbSNP Annotation ### Get Variant by rsID **Best for**: Detailed population frequencies ```python result = tu.execute_tool("dbsnp_get_variant_by_rsid", rsid="rs699") ``` **Response structure**: ```json { "status": "success", "data": { "rsid": "rs699", "chromosome": "1", "position": 230710048, "allele_frequencies": { "1000Genomes": {"G": 0.7432, "A": 0.2568}, "gnomAD_exome": {"G": 0.75, "A": 0.25}, "TOPMED": {"G": 0.76, "A": 0.24} }, "clinical_significance": ["benign"], "gene": "AGT", "hgvs": "NC_000001.11:g.230710048G>A" } } ``` ### Extracted Fields | Field | Description | |-------|-------------| | `allele_frequencies` | Frequencies from 1000G, gnomAD, ExAC, TOPMED | | `clinical_significance` | ClinVar classifications | | `gene` | Associated gene | | `hgvs` | HGVS notation | ## gnomAD Annotation ### Get Variant **Best for**: gnomAD-specific metadata ```python result = tu.execute_tool("gnomad_get_variant", variant_id="1-55039974-G-A") ``` **Note**: This tool returns basic metadata only. For allele frequencies, use MyVariant.info instead. **Response structure**: ```json { "status": "success", "data": { "data": { "variant": { "variant_id": "1-55039974-G-A", "chrom": "1", "pos": 55039974, "ref": "G", "alt": "A" } } } } ``` ## Ensembl VEP Annotation ### Annotate by rsID **Best for**: Consequence prediction ```python result = tu.execute_tool("EnsemblVEP_annotate_rsid", variant_id="rs699") ``` **Response format varies**: - May return list of consequences - May return `{data, metadata}` wrapper - May return `{error}` if variant not found **Handle all cases**: ```python if isinstance(result, dict): if 'error' in result: print("Variant not found") elif 'data' in result: consequences = result['data'] else: consequences = result ``` ### Annotate by Region **Best for**: Annotating all variants in a genomic region ```python result = tu.execute_tool( "ensembl_vep_region", region="7:140753336-140753336", species="human" ) ``` ## Practical Examples ### Example 1: Clinical Variant Screening Find all pathogenic/likely pathogenic variants: ```python from python_implementation import parse_vcf, batch_annotate_variants from tooluniverse import ToolUniverse # Parse VCF vcf_data = parse_vcf("patient.vcf") # Load ToolUniverse tu = ToolUniverse() tu.load_tools() # Annotate variants with rsIDs rsid_variants = [v for v in vcf_data.variants if v.vid and v.vid.startswith('rs')] annotations = batch_annotate_variants(tu, rsid_variants, max_annotate=100) # Find pathogenic variants pathogenic = [ a for a in annotations if a.clinvar_classification and 'pathogenic' in a.clinvar_classification.lower() ] print(f"Found {len(pathogenic)} pathogenic variants:") for a in pathogenic: print(f" {a.variant_key} - {a.gene_symbol}") print(f" Classification: {a.clinvar_classification}") print(f" gnomAD AF: {a.gnomad_af}") print(f" CADD: {a.cadd_phred}") ``` ### Example 2: Population Frequency Analysis Find rare variants (AF < 1%): ```python annotations = batch_annotate_variants(tu, vcf_data.variants, max_annotate=100) rare = [a for a in annotations if a.gnomad_af is not None and a.gnomad_af < 0.01] print(f"Found {len(rare)} rare variants (AF < 1%):") for a in rare: print(f" {a.variant_key} - {a.gene_symbol}") print(f" AF: {a.gnomad_af}") ``` ### Example 3: Pathogenicity Score Filtering Find high CADD score variants (top 1% most deleterious): ```python annotations = batch_annotate_variants(tu, vcf_data.variants, max_annotate=100) high_cadd = [a for a in annotations if a.cadd_phred is not None and a.cadd_phred >= 20] print(f"Found {len(high_cadd)} high CADD score variants (≥20):") for a in high_cadd: print(f" {a.variant_key} - {a.gene_symbol} - {a.mutation_type}") print(f" CADD: {a.cadd_phred}") ``` ### Example 4: Compare ClinVar with Population Frequency Find variants classified as pathogenic but common in population (potential reclassification candidates): ```python annotations = batch_annotate_variants(tu, vcf_data.variants, max_annotate=100) conflicting = [ a for a in annotations if a.clinvar_classification and 'pathogenic' in a.clinvar_classification.lower() and a.gnomad_af is not None and a.gnomad_af > 0.01 # Common (>1%) ] print(f"Found {len(conflicting)} variants with conflicting evidence:") for a in conflicting: print(f" {a.variant_key} - {a.gene_symbol}") print(f" ClinVar: {a.clinvar_classification}") print(f" gnomAD AF: {a.gnomad_af} (common)") ``` ## Annotation Report Generate a comprehensive annotation report: ```python from python_implementation import variant_analysis_pipeline report = variant_analysis_pipeline( vcf_path="variants.vcf", output_file="annotated_report.md", annotate=True, max_annotate=50 # Annotate top 50 variants ) ``` **Report includes**: 1. Variant Annotations table with: - Variant ID - Gene - Mutation type - ClinVar classification - gnomAD AF - CADD score 2. Clinical Significance distribution 3. Top mutated genes 4. Summary statistics ## Best Practices ### 1. Annotate Variants with rsIDs First rsIDs are the most reliable identifiers: ```python # Prioritize variants with rsIDs rsid_variants = [v for v in vcf_data.variants if v.vid and v.vid.startswith('rs')] annotations = batch_annotate_variants(tu, rsid_variants, max_annotate=100) ``` ### 2. Use MyVariant.info for Batch Annotation MyVariant.info aggregates multiple sources in one call: - ClinVar - dbSNP - gnomAD - CADD - SIFT - PolyPhen ### 3. Respect Rate Limits Limit batch annotation to 50-100 variants at a time: ```python annotations = batch_annotate_variants(tu, variants, max_annotate=100) ``` ### 4. Handle Missing Data Not all variants have all annotations: ```python for ann in annotations: if ann.clinvar_classification: print(f"ClinVar: {ann.clinvar_classification}") else: print("ClinVar: No data") if ann.gnomad_af is not None: print(f"gnomAD AF: {ann.gnomad_af}") else: print("gnomAD AF: Not available") ``` ### 5. Combine with Filtering Annotate only high-quality variants: ```python from python_implementation import filter_variants, FilterCriteria # Filter first criteria = FilterCriteria(min_depth=20, pass_only=True) passing, failing = filter_variants(vcf_data.variants, criteria) # Then annotate annotations = batch_annotate_variants(tu, passing, max_annotate=50) ``` ## Troubleshooting ### Issue: "No annotation found" **Cause**: Variant not in database or wrong identifier format **Solution**: - Verify rsID is correct (rs12345) - Try HGVS format (chr7:g.140753336A>T) - Check if variant is in dbSNP/ClinVar ### Issue: Empty ClinVar classification **Cause**: Variant has no ClinVar submission **Solution**: This is normal. Not all variants have clinical significance data. ### Issue: Missing gnomAD allele frequency **Cause**: Variant not in gnomAD (very rare or not covered) **Solution**: Consider as potentially rare/novel variant ### Issue: Rate limiting errors **Cause**: Too many API requests **Solution**: Reduce `max_annotate` parameter or add delays between batches ## Advanced: Custom Annotation Pipeline Build a custom annotation pipeline: ```python from tooluniverse import ToolUniverse tu = ToolUniverse() tu.load_tools() def annotate_variant_full(variant): """Get comprehensive annotation from multiple sources""" annotation = { 'variant_id': variant.vid, 'chrom': variant.chrom, 'pos': variant.pos, 'ref': variant.ref, 'alt': variant.alt } # MyVariant.info (primary) if variant.vid and variant.vid.startswith('rs'): myvariant = tu.execute_tool("MyVariant_query_variants", query=variant.vid) if myvariant.get('data', {}).get('hits'): hit = myvariant['data']['hits'][0] annotation['clinvar'] = hit.get('clinvar', {}) annotation['gnomad'] = hit.get('gnomad_genome', {}) annotation['cadd'] = hit.get('cadd', {}) # dbSNP (supplemental) if variant.vid and variant.vid.startswith('rs'): dbsnp = tu.execute_tool("dbsnp_get_variant_by_rsid", rsid=variant.vid) if dbsnp.get('status') == 'success': annotation['allele_frequencies'] = dbsnp['data'].get('allele_frequencies', {}) return annotation # Use on variants for variant in vcf_data.variants[:10]: full_annotation = annotate_variant_full(variant) print(full_annotation) ```