diff options
-rw-r--r-- | wqflask/wqflask/snp_browser/snp_browser.py | 97 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/css/snp_browser.css | 32 | ||||
-rw-r--r-- | wqflask/wqflask/templates/snp_browser.html | 206 |
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': ' ', + 'processing': 'Loading...' + } }); {% endif %} |