Skip to content

Commit

Permalink
issue #1059 - all variants node
Browse files Browse the repository at this point in the history
  • Loading branch information
davmlaw authored and TheMadBug committed May 22, 2024
1 parent 7b728ae commit 72d1a9b
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 13 deletions.
3 changes: 2 additions & 1 deletion analysis/forms/forms_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ def __init__(self, analysis: Analysis, *args, **kwargs):
class AllVariantsNodeForm(BaseNodeForm):
class Meta:
model = AllVariantsNode
fields = ('max_variant', "gene_symbol", "reference",
fields = ('max_variant', "gene_symbol",
"reference", "snps", "indels", "structural_variants",
"min_het_or_hom_count", "max_het_or_hom_count",
"min_unk_count", "max_unk_count", "min_ref_count", "max_ref_count",
"min_hom_count", "max_hom_count", "min_het_count", "max_het_count")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Generated by Django 4.2.10 on 2024-05-10 07:54

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('analysis', '0084_remove_karyomappinggene_gene_and_more'),
]

operations = [
migrations.AddField(
model_name='allvariantsnode',
name='complex_subsitution',
field=models.BooleanField(blank=True, default=True),
),
migrations.AddField(
model_name='allvariantsnode',
name='indels',
field=models.BooleanField(blank=True, default=True),
),
migrations.AddField(
model_name='allvariantsnode',
name='snps',
field=models.BooleanField(blank=True, default=True),
),
migrations.AddField(
model_name='allvariantsnode',
name='structural_variants',
field=models.BooleanField(blank=True, default=True),
),
]
30 changes: 26 additions & 4 deletions analysis/models/nodes/sources/all_variants_node.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from functools import cached_property
import operator
from functools import cached_property, reduce
from typing import Optional

from django.db import models
Expand All @@ -15,6 +16,10 @@ class AllVariantsNode(AnalysisNode, AbstractZygosityCountNode):
max_variant = models.ForeignKey(Variant, null=True, on_delete=SET_NULL)
gene_symbol = models.ForeignKey(GeneSymbol, null=True, blank=True, on_delete=CASCADE)
reference = models.BooleanField(default=False, blank=True)
snps = models.BooleanField(default=True, blank=True)
indels = models.BooleanField(default=True, blank=True)
complex_subsitution = models.BooleanField(default=True, blank=True)
structural_variants = models.BooleanField(default=True, blank=True)
min_inputs = 0
max_inputs = 0

Expand Down Expand Up @@ -43,9 +48,26 @@ def _get_node_arg_q_dict(self) -> dict[Optional[str], dict[str, Q]]:
q_gene = Q(variantgeneoverlap__gene__in=genes)
q_dict[str(q_gene)] = q_gene

if not self.reference:
q_no_ref = Variant.get_no_reference_q()
q_dict[str(q_no_ref)] = q_no_ref
q_lookup = [
(self.reference, Variant.get_reference_q()),
(self.snps, Variant.get_snp_q()),
(self.indels, Variant.get_indel_q()),
(self.complex_subsitution, Variant.get_complex_subsitution_q()),
(self.structural_variants, Variant.get_symbolic_q()),
]

filters = []
all_true = True
for test, q in q_lookup:
all_true &= test
if test:
filters.append(q)

if not all_true:
if filters:
q_dict["variant_types"] = reduce(operator.or_, filters)
else:
q_dict["empty"] = Q(pk__isnull=False)

arg_q_dict = {None: q_dict}
self.merge_arg_q_dicts(arg_q_dict, self.get_zygosity_count_arg_q_dict())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,31 @@
<label for="{{ form.gene_symbol.id_for_label }}">Gene:</label>
{{ form.gene_symbol }}
</span>
<span class="fieldWrapper">
{{ form.reference.errors }}
<label for="{{ form.reference.id_for_label }}">Show reference variants:</label>
{{ form.reference }}
</span>
<div>
<span class="fieldWrapper">
{{ form.reference.errors }}
<label for="{{ form.reference.id_for_label }}">Reference variants:</label>
{{ form.reference }}
</span>
|
<span class="fieldWrapper">
{{ form.snps.errors }}
<label for="{{ form.snps.id_for_label }}">SNPs:</label>
{{ form.snps }}
</span>
|
<span class="fieldWrapper">
{{ form.indels.errors }}
<label for="{{ form.indels.id_for_label }}">indels:</label>
{{ form.indels }}
</span>
|
<span class="fieldWrapper">
{{ form.structural_variants.errors }}
<label for="{{ form.structural_variants.id_for_label }}">Structural Variants:</label>
{{ form.structural_variants }}
</span>
</div>

<table id="zygosity-table">
<tr>
Expand Down
33 changes: 30 additions & 3 deletions snpdb/models/models_variant.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,9 @@ class Variant(PreviewModelMixin, models.Model):
There is only 1 Variant for a given locus/alt per database (handled via insertion queues) """

REFERENCE_ALT = "="
_BASES = "GATC"
_REGEX_2_PLUS_BASES = f"^[GATC]{2,}$"

locus = models.ForeignKey(Locus, on_delete=CASCADE)
alt = models.ForeignKey(Sequence, on_delete=CASCADE)
# end is a calculated field, but we store as an optimisation for overlap queries (start = locus.position)
Expand All @@ -589,14 +592,38 @@ def get_contigs_q(genome_build: GenomeBuild) -> Q:
""" Restrict to contigs in a genome build """
return Q(locus__contig__genomebuildcontig__genome_build=genome_build)

@staticmethod
def get_reference_q() -> Q:
return Q(alt__seq=Variant.REFERENCE_ALT)

@staticmethod
def get_no_reference_q() -> Q:
return ~Q(alt__seq=Variant.REFERENCE_ALT)
return ~Variant.get_reference_q()

@staticmethod
def get_snp_q() -> Q:
bases = "GATC"
return Q(locus__ref__seq__in=bases) & Q(alt__seq__in=bases)
return Q(locus__ref__seq__in=Variant._BASES) & Q(alt__seq__in=Variant._BASES)

@staticmethod
def get_insertion_q() -> Q:
return Q(locus__ref__seq__in=Variant._BASES) & Q(alt__seq__regex=Variant._REGEX_2_PLUS_BASES)

@staticmethod
def get_deletion_q() -> Q:
return Q(locus__ref__seq__regex=Variant._REGEX_2_PLUS_BASES) & Q(alt__seq__in=Variant._BASES)

@staticmethod
def get_indel_q() -> Q:
return Variant.get_insertion_q() | Variant.get_deletion_q()

@staticmethod
def get_complex_subsitution_q() -> Q:
regex_2_plus_bases = f"^[GATC]{2,}$"
return Q(locus__ref__seq__regex=regex_2_plus_bases) & Q(alt__seq__regex=regex_2_plus_bases)

@staticmethod
def get_symbolic_q() -> Q:
return Q(locus__ref__seq__startswith="<") & Q(alt__seq__startswith="<")

@staticmethod
def annotate_variant_string(qs, name="variant_string", path_to_variant=""):
Expand Down

0 comments on commit 72d1a9b

Please sign in to comment.