about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--wqflask/wqflask/snp_browser/snp_browser.py97
-rw-r--r--wqflask/wqflask/static/new/css/snp_browser.css32
-rw-r--r--wqflask/wqflask/templates/snp_browser.html206
3 files changed, 264 insertions, 71 deletions
diff --git a/wqflask/wqflask/snp_browser/snp_browser.py b/wqflask/wqflask/snp_browser/snp_browser.py
index 0058070c..820551eb 100644
--- a/wqflask/wqflask/snp_browser/snp_browser.py
+++ b/wqflask/wqflask/snp_browser/snp_browser.py
@@ -15,24 +15,25 @@ from base import webqtlConfig
 
 class SnpBrowser(object):
 
-    MAXSNPRETURN = 5000
-
     def __init__(self, start_vars):
         self.strain_lists = get_browser_sample_lists()
         self.initialize_parameters(start_vars)
+        self.limit_number = 10000
 
         if self.first_run == "false":
-            if self.limit_strains == "true":
-                self.header_fields = get_header_list(self.variant_type, self.chosen_strains)
-            else:
-                self.header_fields = get_header_list(self.variant_type, self.strain_lists, self.species_name)
             self.filtered_results = self.get_browser_results()
 
-            if len(self.filtered_results) <= 5000:
+            if len(self.filtered_results) <= self.limit_number:
                 self.table_rows = self.get_table_rows()
             else:
+                self.empty_columns = None
                 self.table_rows = []
 
+            if self.limit_strains == "true":
+                self.header_fields, self.empty_field_count = get_header_list(variant_type = self.variant_type, strains = self.chosen_strains, empty_columns = self.empty_columns)
+            else:
+                self.header_fields, self.empty_field_count = get_header_list(variant_type = self.variant_type, strains = self.strain_lists, species = self.species_name, empty_columns = self.empty_columns)
+
     def initialize_parameters(self, start_vars):
         if 'first_run' in start_vars:
             self.first_run = "false"
@@ -109,7 +110,7 @@ class SnpBrowser(object):
                                      "WSB/EiJ",
                                      "PWK/PhJ",
                                      "CAST/EiJ"]
-        self.chosen_strains_rat = ["BN", "F344"]
+        self.chosen_strains_rat = ["BN", "F344", "WLI", "WMI"]
         if 'chosen_strains_mouse' in start_vars:
             self.chosen_strains_mouse = start_vars['chosen_strains_mouse'].split(",")
         if 'chosen_strains_rat' in start_vars:
@@ -165,9 +166,9 @@ class SnpBrowser(object):
                         query = "SELECT Id, Chromosome, Position, Position+0.000001 FROM SnpAll WHERE Rs = '%s'" % self.gene_name
                     else:
                         if self.species_id != 0:
-                            query = "SELECT Id, Chromosome, Position, Position+0.000001 ForM SnpAll where SpeciesId = %s AND SnpName = '%s'" % (self.species_id, self.gene_name)
+                            query = "SELECT Id, Chromosome, Position, Position+0.000001 FROM SnpAll where SpeciesId = %s AND SnpName = '%s'" % (self.species_id, self.gene_name)
                         else:
-                            query = "SELECT Id, Chromosome, Position, Position+0.000001 ForM SnpAll where SnpName = '%s'" % (self.gene_name)
+                            query = "SELECT Id, Chromosome, Position, Position+0.000001 FROM SnpAll where SnpName = '%s'" % (self.gene_name)
                     result_snp = g.db.execute(query).fetchall()
                     if result_snp:
                         self.snp_list = [item[0] for item in result_snp]
@@ -266,18 +267,18 @@ class SnpBrowser(object):
             if self.variant_type == "SNP":
                 display_strains = []
                 snp_id, species_id, snp_name, rs, chr, mb, mb_2016, alleles, snp_source, conservation_score = result[:10]
-                effect_list = result[10:26]
+                effect_list = result[10:28]
                 if self.species_id == 1:
-                    self.allele_list = result[27:]
+                    self.allele_list = result[30:]
                 elif self.species_id == 2:
-                    self.allele_list = result[28:]
+                    self.allele_list = result[31:]
 
                 if self.limit_strains == "true" and len(self.chosen_strains) > 0:
                     for index in strain_index_list:
                         if self.species_id == 1:
-                            display_strains.append(result[27+index])
+                            display_strains.append(result[29+index])
                         elif self.species_id == 2:
-                            display_strains.append(result[28+index])
+                            display_strains.append(result[31+index])
                     self.allele_list = display_strains
 
                 effect_info_dict = get_effect_info(effect_list)
@@ -369,8 +370,20 @@ class SnpBrowser(object):
             if len(gene_name_list) > 0:
                 gene_id_name_dict = get_gene_id_name_dict(self.species_id, gene_name_list)
 
+        #ZS: list of booleans representing which columns are entirely empty, so they aren't displayed on the page; only including ones that are sometimes empty (since there's always a location, etc)
+        self.empty_columns = {
+                    "snp_source": "false",
+                    "conservation_score": "false",
+                    "gene_name": "false",
+                    "transcript": "false",
+                    "exon": "false",
+                    "domain_2": "false",
+                    "function": "false", 
+                    "function_details": "false"
+            }
+
         the_rows = []
-        for result in self.filtered_results:
+        for i, result in enumerate(self.filtered_results):
             this_row = []
             if self.variant_type == "SNP":
                 snp_name, rs, chr, mb, alleles, gene, transcript, exon, domain, function, function_details, snp_source, conservation_score, snp_id = result[:14]
@@ -395,11 +408,14 @@ class SnpBrowser(object):
                     source_url_1 = "http://www.sanger.ac.uk/resources/mouse/genomes/"
                     source_url_2 = "http://mouse.cs.ucla.edu/mousehapmap/beta/wellcome.html"
                     source_urls = [source_url_1, source_url_2]
+                    self.empty_columns['snp_source'] = "true"
                 else:
                     source_urls = []
 
                 if not conservation_score:
                     conservation_score = ""
+                else:
+                    self.empty_columns['conservation_score'] = "true"
 
                 if gene:
                     gene_name = gene[1]
@@ -409,17 +425,21 @@ class SnpBrowser(object):
                         gene_link = webqtlConfig.NCBI_LOCUSID % gene_id
                     else:
                         gene_link = "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?CMD=search&DB=gene&term=%s" % gene_name
+
+                    self.empty_columns['gene_name'] = "true"
                 else:
                     gene_name = ""
                     gene_link = ""
 
                 if transcript:
                     transcript_link = webqtlConfig.ENSEMBLETRANSCRIPT_URL % (transcript)
+                    self.empty_columns['transcript'] = "true"
                 else:
                     transcript_link = ""
 
                 if exon:
                     exon = exon[1] # exon[0] is exon_id, exon[1] is exon_rank
+                    self.empty_columns['exon'] = "true"
                 else:
                     exon = ""
 
@@ -432,6 +452,12 @@ class SnpBrowser(object):
                         if domain_1 == "Exon":
                             domain_1 = domain_1 + " " + exon
 
+                    if domain_2 != "":
+                        self.empty_columns['domain_2'] = "true"
+
+                if function:
+                    self.empty_columns['function'] = "true"
+
                 function_list = []
                 if function_details:
                     function_list = string.split(string.strip(function_details), ",")
@@ -442,6 +468,8 @@ class SnpBrowser(object):
                     function_details = function_details.replace("/", " -> ")
                     if function_details == "Biotype: Protein Coding":
                         function_details = function_details + ", Coding Region Unknown"
+
+                    self.empty_columns['function_details'] = "true"
                     
                 #[snp_href, chr, mb_formatted, alleles, snp_source_cell, conservation_score, gene_name_cell, transcript_href, exon, domain_1, domain_2, function, function_details]
 
@@ -459,6 +487,7 @@ class SnpBrowser(object):
                     the_bases.append(this_base)
 
                 this_row = {
+                    "index": i + 1,
                     "rs": rs,
                     "snp_url": snp_url,
                     "snp_name": snp_name,
@@ -483,6 +512,7 @@ class SnpBrowser(object):
             elif self.variant_type == "InDel":
                 indel_name, indel_chr, indel_mb_s, indel_mb_e, indel_strand, indel_type, indel_size, indel_sequence, source_name = result
                 this_row = {
+                    "index": i,
                     "indel_name": indel_name,
                     "indel_chr": indel_chr,
                     "indel_mb_s": indel_mb_s,
@@ -637,7 +667,7 @@ def get_browser_sample_lists(species_id=1):
 
     return strain_lists
 
-def get_header_list(variant_type, strains, species = None):
+def get_header_list(variant_type, strains, species = None, empty_columns = None):
     if species == "Mouse":
         strain_list = strains['mouse']
     elif species == "Rat":
@@ -645,14 +675,43 @@ def get_header_list(variant_type, strains, species = None):
     else:
         strain_list = strains
 
+    empty_field_count = 0 #ZS: This is an awkward way of letting the javascript know the index where the allele value columns start; there's probably a better way of doing this
+
     header_fields = []
     if variant_type == "SNP":
         header_fields.append(['Index', 'SNP ID', 'Chr', 'Mb', 'Alleles', 'Source', 'ConScore', 'Gene', 'Transcript', 'Exon', 'Domain 1', 'Domain 2', 'Function', 'Details'])
         header_fields.append(strain_list)
+
+        if empty_columns != None:
+            if empty_columns['snp_source'] == "false":
+                empty_field_count += 1
+                header_fields[0].remove('Source')
+            if empty_columns['conservation_score'] == "false":
+                empty_field_count += 1
+                header_fields[0].remove('ConScore')
+            if empty_columns['gene_name'] == "false":
+                empty_field_count += 1
+                header_fields[0].remove('Gene')
+            if empty_columns['transcript'] == "false":
+                empty_field_count += 1
+                header_fields[0].remove('Transcript')
+            if empty_columns['exon'] == "false":
+                empty_field_count += 1
+                header_fields[0].remove('Exon')
+            if empty_columns['domain_2'] == "false":
+                empty_field_count += 1
+                header_fields[0].remove('Domain 2')
+            if empty_columns['function'] == "false":
+                empty_field_count += 1
+                header_fields[0].remove('Function')
+            if empty_columns['function_details'] == "false":
+                empty_field_count += 1
+                header_fields[0].remove('Details')
+
     elif variant_type == "InDel":
         header_fields = ['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start', 'Mb End', 'Strand', 'Size', 'Sequence', 'Source']
 
-    return header_fields
+    return header_fields, empty_field_count
 
 def get_effect_details_by_category(effect_name = None, effect_value = None):
     gene_list = []
@@ -709,7 +768,7 @@ def get_effect_info(effect_list):
     effect_info_dict = {}
 
     prime3_utr, prime5_utr, upstream, downstream, intron, nonsplice_site, splice_site, intergenic = effect_list[:8]
-    exon, non_synonymous_coding, synonymous_coding, start_gained, start_lost, stop_gained, stop_lost, unknown_effect_in_exon = effect_list[8:]
+    exon, non_synonymous_coding, synonymous_coding, start_gained, start_lost, stop_gained, stop_lost, unknown_effect_in_exon = effect_list[8:16]
 
     if intergenic:
         domain = "Intergenic"
diff --git a/wqflask/wqflask/static/new/css/snp_browser.css b/wqflask/wqflask/static/new/css/snp_browser.css
index c1adaf20..30fe9a59 100644
--- a/wqflask/wqflask/static/new/css/snp_browser.css
+++ b/wqflask/wqflask/static/new/css/snp_browser.css
@@ -19,4 +19,36 @@ table.dataTable thead th{
   border-right: 1px solid white;
   color: white;
   background-color: royalblue;
+}
+
+table.dataTable tbody td {
+  padding: 4px 20px 2px 10px;
+}
+
+td.A_allele_color {
+  background-color: #C33232
+}
+td.C_allele_color {
+  background-color: #1569C7
+}
+td.T_allele_color {
+  background-color: #CFCF32
+}
+td.G_allele_color {
+  background-color: #32C332
+}
+td.t_allele_color {
+  background-color: #FF6
+}
+td.c_allele_color {
+  background-color: #5CB3FF
+}
+td.a_allele_color {
+  background-color: #F66
+}
+td.g_allele_color {
+  background-color: #CF9
+}
+td.default_allele_color {
+  background-color: #FFFFFF
 }
\ No newline at end of file
diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index cbca9d22..8ae763fa 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -182,7 +182,7 @@
 
     <div style="margin-top: 20px;">
     {% if filtered_results is defined %}
-    {% if filtered_results|length > 5000 %}
+    {% if filtered_results|length > limit_number %}
     There are more than 5000 results. Consider limiting your search to a smaller range.
     {% else %}
     <table class="dataTable cell-border nowrap" id="results_table" style="float: left;">
@@ -204,44 +204,7 @@
         </tr>
       </thead>
       <tbody>
-        {% for row in table_rows %}
-        {% if variant_type == "SNP" %}
-        <tr>
-          <td><input type="checkbox" name="trait_check"></td>
-          <td align="right">{{ loop.index }}</td>
-          <td>{% if row.rs != "" %}<b><a href="{{ row.snp_url }}">{{ row.snp_name }}</a></b>{% else %}<a href="{{ row.snp_url }}">{{ row.snp_name }}</a>{% endif %}</td>
-          <td>{{ row.chr }}</td>
-          <td>{{ row.mb_formatted }}</td>
-          <td>{{ row.alleles }}</td>
-          <td>{% if row.snp_source == "Sanger/UCLA" %}<a href="{{ row.source_urls[0] }}">Sanger</a>/<a href="{{ row.source_urls[1] }}">UCLA</a>{% else %}{{ row.snp_source }}{% endif %}</td>
-          <td>{{ row.conservation_score }}</td>
-          <td>{% if row.gene_name != "" %}<i>{{ row.gene_name }}</i><br><a href="{{ row.gene_link }}">NCBI</a>{% else %}{% endif %}</td>
-          <td><a href="{{ row.transcript_link }}">{{ row.transcript }}</a></td>
-          <td>{{ row.exon }}</td>
-          <td>{{ row.domain_1 }}</td>
-          <td>{{ row.domain_2 }}</td>
-          <td>{{ row.function }}</td>
-          <td>{{ row.function_details }}</td>
-          {% for item in row.allele_value_list %}
-          <td style="background-color: {{ item[1] }};">{{ item[0] }}</td>
-          {% endfor %}
-        </tr>
-        {% else %}
-        <tr>
-          <td><input type="checkbox" name="trait_check"></td>
-          <td align="right">{{ loop.index }}</td>
-          <td>{{ row.indel_name }}</td>
-          <td>{{ row.indel_type }}</td>
-          <td>{{ row.indel_chr }}</td>
-          <td>{{ row.indel_mb_s }}</td>
-          <td>{{ row.indel_mb_e }}</td>
-          <td>{{ row.indel_strand }}</td>
-          <td>{{ row.indel_size }}</td>
-          <td>{{ row.indel_sequence }}</td>
-          <td>{{ row.source_name }}</td>
-        </tr>
-        {% endif %}
-        {% endfor %}
+      <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td>
       </tbody>
     </table>
     {% endif %}
@@ -253,26 +216,165 @@
 {% block js %}
   <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.js"></script>
   <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.naturalSort.js"></script>
+
+  <script type='text/javascript'>
+      var json_rows = {{ table_rows|safe }};
+      var empty_columns = {{ empty_columns|safe }};
+  </script>
+
   <script language="javascript">
 
     {% if filtered_results is defined %}
     $("#results_table").DataTable( {
+      'data': json_rows,
       {% if variant_type == "SNP" %}
-      "columnDefs": [ {
-        "targets": [0, {% for n in range(15, 15 + allele_list|length) %}, {{ n }}{% endfor %}],
-        "orderable": false
-       } ],
+      'columns': [
+        {
+          'data': null,
+          'orderable': false,
+          'render': function(data, type, row, meta) {
+            return '<input type="checkbox" name="trait_check">'
+          }
+        }, {
+          'data': 'index'
+        }, {
+          'data': null,
+          'render': function(data, type, row, meta) {
+            if (data.rs != "") {
+              return '<b><a href="' + data.snp_url + '">' + data.snp_name + '</a></b>'
+            } else {
+              return '<a href="' + data.snp_url + '">' + data.snp_name + '</a>'
+            }
+          }
+        }, {
+          'data': 'chr'
+        }, {
+          'data': 'mb_formatted'
+        }, {
+          'data': 'alleles'
+        }, {% if empty_columns['snp_source'] == "true" %}{
+          'data': null,
+          'render': function(data, type, row, meta) {
+            if (data.snp_source == "Sanger/UCLA") {
+              return '<a href="' + data.source_urls[0] + '">Sanger</a><a href="' + data.source_urls[1] + '">UCLA</a>'
+            } else {
+              return data.snp_source
+            }
+          }
+        }, {% endif %} {% if empty_columns['conservation_score'] == "true" %}{
+          'data': 'conservation_score'
+        }, {% endif %} {% if empty_columns['gene_name'] == "true" %}{
+          'data': null,
+          'render': function(data, type, row, meta) {
+            if (data.gene_name != "") {
+              return '<i>' + data.gene_name + '</i><br><a href="' + data.gene_link + '">NCBI</a>'
+            } else {
+              return data.gene_name
+            }
+          }
+        }, {% endif %} {% if empty_columns['transcript'] == "true" %}{
+          'data': null,
+          'render': function(data, type, row, meta) {
+            if (data.transcript != "") {
+              return '<a href="' + data.transcript_link + '">' + data.transcript + '</a>'
+            } else {
+              return data.transcript
+            }
+          }
+        }, {% endif %} {% if empty_columns['exon'] == "true" %}{
+          'data': 'exon'
+        }, {% endif %}{
+          'data': 'domain_1'
+        }, {% if empty_columns['domain_2'] == "true" %}{
+          'data': 'domain_2'
+        }, {% endif %} {% if empty_columns['function'] == "true" %}{
+          'data': 'function'
+        }, {% endif %} {% if empty_columns['function_details'] == "true" %}{
+          'data': 'function_details'
+        }, {% endif %} {% for item in allele_list %} {
+          'data': null,
+          'orderable': false,
+          'render': function(data, type, row, meta) {
+            if (typeof data.allele_value_list[{{ loop.index - 1 }}][0] !== "undefined") {
+              return data.allele_value_list[{{ loop.index - 1 }}][0]
+            } else {
+              return ''
+            }
+          }
+        }{% if loop.index < allele_list|length %},{% endif %}{% endfor %}
+      ],
+      'createdRow': function( row, data, dataIndex) {
+        $('td', row).eq(0).attr("style", "text-align: center; padding: 4px 10px 2px 10px;");
+        $('td', row).eq(1).attr("align", "right");
+        for (i = {{ 15 - empty_field_count }}; i < ({{ 15 - empty_field_count }} + {{ allele_list|length }}); i++) {
+          var this_allele = $('td', row).eq(i).text();
+          $('td', row).eq(i).attr("style", "text-align: center; padding: 4px 10px 2px 10px;");
+          switch (this_allele) {
+            case "A":
+              $('td', row).eq(i).addClass('A_allele_color');
+              break;
+            case "C":
+              $('td', row).eq(i).addClass('C_allele_color');
+              break;
+            case "T":
+              $('td', row).eq(i).addClass('T_allele_color');
+              break;
+            case "G":
+              $('td', row).eq(i).addClass('G_allele_color');
+              break;
+            case "t":
+              $('td', row).eq(i).addClass('t_allele_color');
+              break;
+            case "c":
+              $('td', row).eq(i).addClass('c_allele_color');
+              break;
+            case "a":
+              $('td', row).eq(i).addClass('a_allele_color');
+              break;
+            case "g":
+              $('td', row).eq(i).addClass('g_allele_color');
+              break;
+            default:
+              $('td', row).eq(i).addClass('default_allele_color');
+          }
+        }
+      },
       {% else %}
-      "columnDefs": [ {
-        "targets": 0,
-        "orderable": false
-       } ],
+      'columns': [
+        {
+          'data': null,
+          'render': function(data, type, row, meta) {
+            return '<input type="checkbox" name="trait_check">'
+          }
+        }, {
+          'data': 'indel_name'
+        }, {
+          'data': 'indel_type'
+        }, {
+          'data': 'indel_chr'
+        }, {
+          'data': 'indel_mb_s'
+        }, {
+          'data': 'indel_mb_e'
+        }, {
+          'data': 'strand'
+        }, {
+          'data': 'size'
+        }, {
+          'data': 'sequence'
+        }, {
+          'data': 'source_name'
+        }
+      ],
       {% endif %}
-      "order": [[1, "asc" ]],
-      "sDom": "tir",
-      "iDisplayLength": -1,
-      "autoWidth": true,
-      "paging": false
+      'order': [[1, "asc" ]],
+      'sDom': "rti",
+      'iDisplayLength': -1,
+      'processing': true,
+      'language': {
+        'loadingRecords': '&nbsp;',
+        'processing': 'Loading...'
+      }
     });
     {% endif %}