From ef38724c31567b56214026999a944f9088fe30b8 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 28 Jun 2020 11:23:27 -0500
Subject: make stains headers names horizontal

---
 wqflask/wqflask/templates/snp_browser.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index fb564b28..7019e943 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -195,7 +195,7 @@
           <th data-export="{{ header }}">{{ header }}</th>
           {% endfor %}
           {% for strain in header_fields[1] %}
-          <th data-export="{{ strain }}" style="align: center; text-align: center; line-height: 15px;">{% for letter in strain %}<div style="transform: rotate(90deg);">{{ letter }}</div>{% endfor %}</th>
+          <th data-export="{{ strain }}" style="align: center; text-align: center; line-height: 15px;">{{ strain }}</th>
           {% endfor %}
           {% else %}
           {% for header in header_fields %}
-- 
cgit v1.2.3


From 88715630c4d18d962a7473dcac7e34b1b9c098a0 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 28 Jun 2020 11:24:12 -0500
Subject: add DataTables pagination

---
 wqflask/wqflask/templates/snp_browser.html | 1 -
 1 file changed, 1 deletion(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 7019e943..3b97963c 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -407,7 +407,6 @@
       {% endif %}
       'order': [[1, "asc" ]],
       'sDom': "rtip",
-      'iDisplayLength': 500,
       'processing': true,
       'language': {
         'loadingRecords': '&nbsp;',
-- 
cgit v1.2.3


From 73e3f354b0bf6accfd884f0fab8ef93f03be7945 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 28 Jun 2020 11:28:28 -0500
Subject: fix typo in check_if_in_gene function while querying for species_id =
 0

---
 wqflask/wqflask/snp_browser/snp_browser.py | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/wqflask/wqflask/snp_browser/snp_browser.py b/wqflask/wqflask/snp_browser/snp_browser.py
index 6c3fcf53..a2fb7195 100644
--- a/wqflask/wqflask/snp_browser/snp_browser.py
+++ b/wqflask/wqflask/snp_browser/snp_browser.py
@@ -526,7 +526,6 @@ class SnpBrowser(object):
             the_rows.append(this_row)
 
         return the_rows
-                
 
     def include_record(self, domain, function, snp_source, conservation_score):
         """ Decide whether to add this record """
@@ -868,8 +867,6 @@ def get_gene_id_name_dict(species_id, gene_name_list):
     if len(results) > 0:
         for item in results:
             gene_id_name_dict[item[1]] = item[0]
-    else:
-        pass
 
     return gene_id_name_dict
 
@@ -883,7 +880,7 @@ def check_if_in_gene(species_id, chr, mb):
         query = """SELECT geneId,geneSymbol
                    FROM GeneList
                    WHERE chromosome = '{0}' AND
-                        (txStart < {1} AND txEnd > {1}); """.format(species_id, chr, mb)
+                        (txStart < {1} AND txEnd > {1}); """.format(chr, mb)
 
     result = g.db.execute(query).fetchone()
 
-- 
cgit v1.2.3


From 429aff0920b1fddf71e4547c35a726b11e6713a0 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Tue, 30 Jun 2020 14:14:53 -0500
Subject: 500 rows per page for DataTables

---
 wqflask/wqflask/templates/snp_browser.html | 1 +
 1 file changed, 1 insertion(+)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 3b97963c..7019e943 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -407,6 +407,7 @@
       {% endif %}
       'order': [[1, "asc" ]],
       'sDom': "rtip",
+      'iDisplayLength': 500,
       'processing': true,
       'language': {
         'loadingRecords': '&nbsp;',
-- 
cgit v1.2.3


From 776ccfbb2fc5a6e85c7a41efd92b33b0e27de68a Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Tue, 30 Jun 2020 14:56:22 -0500
Subject: reduce gap between first and second column in form

---
 wqflask/wqflask/templates/snp_browser.html | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 7019e943..73359835 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -15,7 +15,7 @@
         <input type="hidden" name="first_run" value="{{ first_run }}">
         <input type="hidden" name="chosen_strains_mouse" value="{{ chosen_strains_mouse|join(",") }}">
         <input type="hidden" name="chosen_strains_rat" value="{{ chosen_strains_rat|join(",") }}">
-        <div class="col-xs-4" style="padding-left: 0px;">
+        <div class="col-xs-4" style="width: 260px; padding-left: 30px; padding-right: 0px;">
           <div class="form-group row" style="margin-bottom: 5px;">
             <label for="snp_or_indel" style="text-align: right;" class="col-xs-4 col-form-label"><b>Type:</b></label>
             <div class="col-xs-8">
@@ -74,7 +74,7 @@
             </div>
           </div>
         </div>
-        <div class="col-xs-4" style="padding-left: 0px;">
+        <div class="col-xs-4" style="width: 310px; padding-left: 0px; padding-right: 20px;">
           <div class="form-group row" style="margin-bottom: 10px;">
             <label for="strains" style="text-align: right;" class="col-xs-4 col-form-label"><b>Strains:</b></label>
             <div class="col-xs-8">
@@ -108,7 +108,7 @@
             </div>
           </div>
         </div>
-        <div class="col-xs-4" style="padding-left: 20px;">
+        <div class="col-xs-4" style="width: 310px; padding-left: 20px;">
           <div class="form-group row" style="margin-bottom: 5px;">
             <label for="domain" style="text-align: right;" class="col-xs-4 col-form-label"><b>Domain:</b></label>
             <div class="col-xs-8">
-- 
cgit v1.2.3


From 3a792dbe74ab181d2fa9582f67c99b68ffad0c10 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Tue, 30 Jun 2020 15:38:04 -0500
Subject: align numeric data values to right, categorial values to center

---
 wqflask/wqflask/templates/snp_browser.html | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 73359835..816d5f0f 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -272,7 +272,8 @@
             return '<input type="checkbox" name="trait_check">'
           }
         }, {
-          'data': 'index'
+          'data': 'index',
+          'className': 'dt-body-right'
         }, {
           'data': null,
           'render': function(data, type, row, meta) {
@@ -283,9 +284,11 @@
             }
           }
         }, {
-          'data': 'chr'
+          'data': 'chr',
+          'className': 'dt-body-center'
         }, {
-          'data': 'mb_formatted'
+          'data': 'mb_formatted',
+          'className': 'dt-body-right'
         }, {
           'data': 'alleles'
         }, {% if empty_columns['snp_source'] == "true" %}{
@@ -298,7 +301,8 @@
             }
           }
         }, {% endif %} {% if empty_columns['conservation_score'] == "true" %}{
-          'data': 'conservation_score'
+          'data': 'conservation_score',
+          'className': 'dt-body-right'
         }, {% endif %} {% if empty_columns['gene_name'] == "true" %}{
           'data': null,
           'render': function(data, type, row, meta) {
@@ -383,21 +387,26 @@
             return '<input type="checkbox" name="trait_check">'
           }
         }, {
-          'data': 'index'
+          'data': 'index',
+          'className': 'dt-body-right'
         }, {
           'data': 'indel_name'
         }, {
           'data': 'indel_type'
         }, {
-          'data': 'indel_chr'
+          'data': 'indel_chr',
+          'className': 'dt-body-center'
         }, {
-          'data': 'indel_mb_s'
+          'data': 'indel_mb_s',
+          'className': 'dt-body-right'
         }, {
-          'data': 'indel_mb_e'
+          'data': 'indel_mb_e',
+          'className': 'dt-body-right'
         }, {
           'data': 'indel_strand'
         }, {
-          'data': 'indel_size'
+          'data': 'indel_size',
+          'className': 'dt-body-right'
         }, {
           'data': 'indel_sequence'
         }, {
-- 
cgit v1.2.3


From f7b7950533f52e418c2be569cca409ae1fb3faf0 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Tue, 30 Jun 2020 16:48:02 -0500
Subject: rotate strain headers 270 deg

---
 wqflask/wqflask/templates/snp_browser.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 816d5f0f..36f893bc 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -195,7 +195,7 @@
           <th data-export="{{ header }}">{{ header }}</th>
           {% endfor %}
           {% for strain in header_fields[1] %}
-          <th data-export="{{ strain }}" style="align: center; text-align: center; line-height: 15px;">{{ strain }}</th>
+          <th data-export="{{ strain }}" style="align: center; text-align: center; line-height: 12px;">{% for letter in strain|reverse %}<div style="transform: rotate(270deg);">{{ letter }}</div>{% endfor %}</th>
           {% endfor %}
           {% else %}
           {% for header in header_fields %}
-- 
cgit v1.2.3


From 7a4068d6d46d923c30316887e1d20f2fa6caa859 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Fri, 10 Jul 2020 10:15:22 -0500
Subject: add export to CSV button to export current page

---
 wqflask/wqflask/templates/snp_browser.html | 43 +++++++++++++++++++++++++++---
 1 file changed, 40 insertions(+), 3 deletions(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 36f893bc..284b55c5 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -107,6 +107,12 @@
               </div>
             </div>
           </div>
+          <div class="form-group row">
+            <label class="col-xs-4 col-form-label"></label>
+            <div class="col-xs-8" style="margin-top: 65px;">
+              <input class="btn btn-primary" type="button" name="export_csv" value="Export to CSV">
+            </div>
+          </div>
         </div>
         <div class="col-xs-4" style="width: 310px; padding-left: 20px;">
           <div class="form-group row" style="margin-bottom: 5px;">
@@ -192,14 +198,14 @@
           <th></th>
           {% if header_fields|length == 2 %}
           {% for header in header_fields[0] %}
-          <th data-export="{{ header }}">{{ header }}</th>
+          <th data-export="{{ header }}" name="{{ header }}">{{ header }}</th>
           {% endfor %}
           {% for strain in header_fields[1] %}
-          <th data-export="{{ strain }}" style="align: center; text-align: center; line-height: 12px;">{% for letter in strain|reverse %}<div style="transform: rotate(270deg);">{{ letter }}</div>{% endfor %}</th>
+          <th data-export="{{ strain }}" name="{{ strain }}" style="align: center; text-align: center; line-height: 12px;">{% for letter in strain|reverse %}<div style="transform: rotate(270deg);">{{ letter }}</div>{% endfor %}</th>
           {% endfor %}
           {% else %}
           {% for header in header_fields %}
-          <th data-export="{{ header }}">{{ header }}</th>
+          <th data-export="{{ header }}" name="{{ header }}">{{ header }}</th>
           {% endfor %}
           {% endif %}
         </tr>
@@ -518,6 +524,37 @@
       });
       $("input[name=chosen_strains]").val(strain_list.join(","));
     });
+
+    $("input[name=export_csv]").click(function() {
+      var csv = [];
+      var rows = document.querySelectorAll("table tr");
+
+      var headers = [];
+      var col_header = rows[0].querySelectorAll("th");
+      console.log(col_header.length);
+      for(var i = 1; i < col_header.length; i++) {
+        console.log(col_header[i].getAttribute("name"));
+        headers.push(col_header[i].getAttribute("name"));
+      }
+      csv.push(headers.join(","));
+
+      for (var i = 1; i < rows.length; i++) {
+        var row = [], cols = rows[i].querySelectorAll("td");
+
+        for (var j = 1; j < cols.length; j++)
+          row.push(cols[j].innerText);
+
+        csv.push(row.join(","));
+      }
+
+      var csvFile = new Blob([csv.join("\n")], {type: "text/csv"});
+      var downloadLink = document.createElement("a");
+      downloadLink.download = "hello.csv";
+      downloadLink.href = window.URL.createObjectURL(csvFile);
+      downloadLink.style.display = "none";
+      document.body.appendChild(downloadLink);
+      downloadLink.click();
+    });
   </script>
 {% endblock %}
 
-- 
cgit v1.2.3


From f99b69155d35900a75c000fbb79f6bcfb3fa6ff1 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Fri, 10 Jul 2020 10:30:04 -0500
Subject: export only checked rows to csv; update csv file name

---
 wqflask/wqflask/templates/snp_browser.html | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 284b55c5..83606804 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -531,25 +531,27 @@
 
       var headers = [];
       var col_header = rows[0].querySelectorAll("th");
-      console.log(col_header.length);
       for(var i = 1; i < col_header.length; i++) {
-        console.log(col_header[i].getAttribute("name"));
         headers.push(col_header[i].getAttribute("name"));
       }
       csv.push(headers.join(","));
 
       for (var i = 1; i < rows.length; i++) {
         var row = [], cols = rows[i].querySelectorAll("td");
+        var checkBox = rows[i].querySelector("input");
+        console.log(checkBox);
 
-        for (var j = 1; j < cols.length; j++)
-          row.push(cols[j].innerText);
+        if(checkBox.checked == true) {
+          for (var j = 1; j < cols.length; j++)
+            row.push(cols[j].innerText);
 
-        csv.push(row.join(","));
+            csv.push(row.join(","));
+        }
       }
 
       var csvFile = new Blob([csv.join("\n")], {type: "text/csv"});
       var downloadLink = document.createElement("a");
-      downloadLink.download = "hello.csv";
+      downloadLink.download = "variant_data.csv";
       downloadLink.href = window.URL.createObjectURL(csvFile);
       downloadLink.style.display = "none";
       document.body.appendChild(downloadLink);
-- 
cgit v1.2.3


From 349b395375703e727465a1f05f4a5e2d4fc64d2a Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 19 Jul 2020 17:21:15 -0500
Subject: add server side processing due to large tables in DataTables; work on
 server-side processing API pending for sorting, paging etc

---
 wqflask/wqflask/snp_browser/snp_browser.py | 39 ++++++++++++++++++++++--------
 wqflask/wqflask/templates/snp_browser.html | 26 +++++++++++++++-----
 wqflask/wqflask/views.py                   | 10 ++++++++
 3 files changed, 59 insertions(+), 16 deletions(-)

diff --git a/wqflask/wqflask/snp_browser/snp_browser.py b/wqflask/wqflask/snp_browser/snp_browser.py
index a2fb7195..9ae8892b 100644
--- a/wqflask/wqflask/snp_browser/snp_browser.py
+++ b/wqflask/wqflask/snp_browser/snp_browser.py
@@ -4,7 +4,7 @@ import string
 from PIL import (Image)
 
 from utility.logger import getLogger
-logger = getLogger(__name__ )
+logger = getLogger(__name__)
 
 from base import species
 from base import webqtlConfig
@@ -14,16 +14,16 @@ class SnpBrowser(object):
     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":
             self.filtered_results = self.get_browser_results()
+            self.table_rows = self.get_table_rows()
+            self.rows_count = len(self.table_rows)
 
-            if len(self.filtered_results) <= self.limit_number:
-                self.table_rows = self.get_table_rows()
-            else:
-                self.empty_columns = None
-                self.table_rows = []
+            del self.filtered_results
+
+            if 'sEcho' not in start_vars:
+                self.table_rows = self.table_rows[:500]
 
             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)
@@ -380,7 +380,7 @@ class SnpBrowser(object):
 
         the_rows = []
         for i, result in enumerate(self.filtered_results):
-            this_row = []
+            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]
                 allele_value_list = result[14:]
@@ -520,8 +520,6 @@ class SnpBrowser(object):
                     "source_name": str(source_name)
                 }
                 #this_row = [indel_name, indel_chr, indel_mb_s, indel_mb_e, indel_strand, indel_type, indel_size, indel_sequence, source_name]
-            else:
-                this_row = {}
 
             the_rows.append(this_row)
 
@@ -643,6 +641,27 @@ class SnpBrowser(object):
         #for i in range(n_click):
         #    href = url_for('snp_browser', first_run="false", chosen_strains_mouse=self.chosen_strains_mouse, chosen_strains_rat=self.chosen_strains_rat, variant=self.variant_type, species=self.species_name, gene_name=self.gene_name, chr=self.chr, start_mb=self.start_mb, end_mb=self.end_mb, limit_strains=self.limit_strains, domain=self.domain, function=self.function, criteria=self.criteria, score=self.score, diff_alleles=self.diff_alleles)
 
+class SnpPage(object):
+
+    def __init__(self, start_vars):
+        self.snp_browser = SnpBrowser(start_vars)
+        # self.table_rows = self.filter_rows()
+        self.rows_count = self.snp_browser.rows_count
+        self.sEcho = start_vars['sEcho']
+
+    def filter_rows(self):
+        pass
+
+    def get_page(self):
+        output = {}
+        output['sEcho'] = str(self.sEcho)
+        output['iTotalRecords'] = str(self.rows_count)
+        output['iTotalDisplayRecords'] = str(100)
+        # logger.info(len(self.table_rows), type(self.table_rows), self.table_rows[0])
+        logger.info(self.snp_browser.rows_count, len(self.snp_browser.table_rows))
+        output['data'] = self.snp_browser.table_rows[:100]
+        return output
+
 def get_browser_sample_lists(species_id=1):
     strain_lists = {}
     mouse_strain_list = []
diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 83606804..f3e928af 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -188,10 +188,7 @@
     </div>
 
     <div style="margin-top: 20px;">
-    {% if filtered_results is defined %}
-    {% if filtered_results|length > limit_number %}
-    There are more than 10000 results. Consider limiting your search to a smaller range.
-    {% else %}
+    {% if table_rows is defined %}
     <table class="dataTable cell-border nowrap" id="results_table" style="float: left;">
       <thead>
         <tr>
@@ -214,7 +211,6 @@
       <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td>
       </tbody>
     </table>
-    {% endif %}
     {% endif %}     
     </div>
   </div>
@@ -229,11 +225,23 @@
 
   <script type='text/javascript'>
       var json_rows = {{ table_rows|safe }};
+      var json_rows_count = {{ rows_count|safe }};
       var empty_columns = {{ empty_columns|safe }};
   </script>
 
   <script language="javascript">
 
+    var getParams = function(url) {
+      var parser = document.createElement('a');
+      parser.href = url;
+      var params = parser.search.substring(1);
+      console.log(params);
+      if(params.length > 0) {
+        return ('?'+params);
+      }
+      return params;
+    };
+
     var substringMatcher = function(strs) {
       return function findMatches(q, cb) {
         var matches, substringRegex;
@@ -266,7 +274,7 @@
       source: substringMatcher(rat_genes)
     });
 
-    {% if filtered_results is defined %}
+    {% if table_rows is defined %}
     $("#results_table").DataTable( {
       'data': json_rows,
       {% if variant_type == "SNP" %}
@@ -423,6 +431,10 @@
       'order': [[1, "asc" ]],
       'sDom': "rtip",
       'iDisplayLength': 500,
+      'bServerSide': true,
+      'bProcessing': true,
+      'sAjaxSource': '/snp_browser_table'+getParams(window.location.href),
+      'deferLoading': json_rows_count,
       'processing': true,
       'language': {
         'loadingRecords': '&nbsp;',
@@ -525,6 +537,8 @@
       $("input[name=chosen_strains]").val(strain_list.join(","));
     });
 
+    
+
     $("input[name=export_csv]").click(function() {
       var csv = [];
       var rows = document.querySelectorAll("table tr");
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 08673f79..a2c66d53 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -897,6 +897,7 @@ def corr_scatter_plot_page():
 def snp_browser_page():
     logger.info(request.url)
     template_vars = snp_browser.SnpBrowser(request.args)
+    logger.info(template_vars.__dict__.keys())
 
     return render_template("snp_browser.html", **template_vars.__dict__)
 
@@ -906,6 +907,15 @@ def db_info_page():
 
     return render_template("info_page.html", **template_vars.__dict__)
 
+@app.route("/snp_browser_table", methods=('GET',))
+def snp_browser_table():
+    logger.info(request.url)
+    logger.info(request.args)
+    
+    current_page = snp_browser.SnpPage(request.args).get_page()
+
+    return flask.jsonify(current_page)
+
 @app.route("/tutorial/WebQTLTour", methods=('GET',))
 def tutorial_page():
     #ZS: Currently just links to GN1
-- 
cgit v1.2.3


From bad336d0d2282f6eaadbcd0fe21afaaaf5342890 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Thu, 23 Jul 2020 06:34:07 -0500
Subject: server side processing working for snp browser

---
 wqflask/wqflask/snp_browser/snp_browser.py | 92 ++++++++++++++++++++++++------
 wqflask/wqflask/templates/snp_browser.html |  7 +--
 wqflask/wqflask/views.py                   |  4 +-
 3 files changed, 80 insertions(+), 23 deletions(-)

diff --git a/wqflask/wqflask/snp_browser/snp_browser.py b/wqflask/wqflask/snp_browser/snp_browser.py
index 9ae8892b..116da149 100644
--- a/wqflask/wqflask/snp_browser/snp_browser.py
+++ b/wqflask/wqflask/snp_browser/snp_browser.py
@@ -23,12 +23,12 @@ class SnpBrowser(object):
             del self.filtered_results
 
             if 'sEcho' not in start_vars:
-                self.table_rows = self.table_rows[:500]
+                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)
+                self.header_fields, self.empty_field_count, self.header_data_names = 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)
+                self.header_fields, self.empty_field_count, self.header_data_names = 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:
@@ -643,23 +643,75 @@ class SnpBrowser(object):
 
 class SnpPage(object):
 
-    def __init__(self, start_vars):
-        self.snp_browser = SnpBrowser(start_vars)
-        # self.table_rows = self.filter_rows()
-        self.rows_count = self.snp_browser.rows_count
-        self.sEcho = start_vars['sEcho']
+    def __init__(self, request):
+        self.request_values = request
+        self.sEcho = self.request_values['sEcho']
 
-    def filter_rows(self):
-        pass
+        self.snp_browser = SnpBrowser(request)
+        self.rows_count = self.snp_browser.rows_count
+        self.table_rows = self.snp_browser.table_rows
+        self.header_data_names = self.snp_browser.header_data_names
+
+        logger.info(self.table_rows[0])
+        
+        self.sort_rows()
+        self.paginate_rows()
+
+    def sort_rows(self):
+        '''
+        Sorts the rows taking in to account the column (or columns) that the
+        user has selected.
+        '''
+        def is_reverse(str_direction):
+            ''' Maps the 'desc' and 'asc' words to True or False. '''
+            return True if str_direction == 'desc' else False
+
+        if (self.request_values['iSortCol_0'] != "") and (int(self.request_values['iSortingCols']) > 0):
+            for i in range(0, int(self.request_values['iSortingCols'])):
+                column_number = int(self.request_values['iSortCol_' + str(i)])
+                column_name = self.header_data_names[column_number - 1]
+                sort_direction = self.request_values['sSortDir_' + str(i)]
+                self.table_rows = sorted(self.table_rows,
+                              key=lambda x: x[column_name],
+                              reverse=is_reverse(sort_direction))
+
+    def paginate_rows(self):
+        '''
+        Selects a subset of the filtered and sorted data based on if the table
+        has pagination, the current page and the size of each page.
+        '''
+        def requires_pagination():
+            ''' Check if the table is going to be paginated '''
+            if self.request_values['iDisplayStart'] != "":
+                if int(self.request_values['iDisplayLength']) != -1:
+                    return True
+            return False
+
+        if not requires_pagination():
+            return
+
+        start = int(self.request_values['iDisplayStart'])
+        length = int(self.request_values['iDisplayLength'])
+
+        # if search returns only one page
+        if len(self.table_rows) <= length:
+            # display only one page
+            self.table_rows = self.table_rows[start:]
+        else:
+            limit = -len(self.table_rows) + start + length
+            if limit < 0:
+                # display pagination
+                self.table_rows = self.table_rows[start:limit]
+            else:
+                # display last page of pagination
+                self.table_rows = self.table_rows[start:]
 
     def get_page(self):
         output = {}
         output['sEcho'] = str(self.sEcho)
-        output['iTotalRecords'] = str(self.rows_count)
-        output['iTotalDisplayRecords'] = str(100)
-        # logger.info(len(self.table_rows), type(self.table_rows), self.table_rows[0])
-        logger.info(self.snp_browser.rows_count, len(self.snp_browser.table_rows))
-        output['data'] = self.snp_browser.table_rows[:100]
+        output['iTotalRecords'] = str(float('Nan'))
+        output['iTotalDisplayRecords'] = str(self.rows_count)
+        output['data'] = self.table_rows
         return output
 
 def get_browser_sample_lists(species_id=1):
@@ -692,9 +744,13 @@ def get_header_list(variant_type, strains, species = None, empty_columns = None)
     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 = []
+    header_data_names = []
     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_data_names = ['index', 'snp_name', 'chr', 'mb_formatted', 'alleles', 'snp_source', 'conservation_score', 'gene_name', 'transcript', 'exon', 'domain_1', 'domain_2', 'function', 'function_details']
+
         header_fields.append(strain_list)
+        header_data_names += strain_list
 
         if empty_columns != None:
             if empty_columns['snp_source'] == "false":
@@ -721,11 +777,15 @@ def get_header_list(variant_type, strains, species = None, empty_columns = None)
             if empty_columns['function_details'] == "false":
                 empty_field_count += 1
                 header_fields[0].remove('Details')
+        
+        for col in empty_columns:
+            header_data_names.remove(col)
 
     elif variant_type == "InDel":
         header_fields = ['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start', 'Mb End', 'Strand', 'Size', 'Sequence', 'Source']
+        header_data_names = ['index', 'indel_name', 'indel_type', 'indel_chr', 'indel_mb_s', 'indel_mb_e', 'indel_strand', 'indel_size', 'indel_sequence', 'source_name']
 
-    return header_fields, empty_field_count
+    return header_fields, empty_field_count, header_data_names
 
 def get_effect_details_by_category(effect_name = None, effect_value = None):
     gene_list = []
diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index f3e928af..cbc12e06 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -276,7 +276,6 @@
 
     {% if table_rows is defined %}
     $("#results_table").DataTable( {
-      'data': json_rows,
       {% if variant_type == "SNP" %}
       'columns': [
         {
@@ -432,10 +431,10 @@
       'sDom': "rtip",
       'iDisplayLength': 500,
       'bServerSide': true,
-      'bProcessing': true,
       'sAjaxSource': '/snp_browser_table'+getParams(window.location.href),
-      'deferLoading': json_rows_count,
-      'processing': true,
+      'infoCallback': function(settings, start, end, max, total, pre) {
+        return "Showing " + start + " to " + (start + this.api().data().length - 1) + " of " + total + " entries";
+      },
       'language': {
         'loadingRecords': '&nbsp;',
         'processing': 'Loading...'
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index a2c66d53..8e7f6ec3 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -909,9 +909,7 @@ def db_info_page():
 
 @app.route("/snp_browser_table", methods=('GET',))
 def snp_browser_table():
-    logger.info(request.url)
-    logger.info(request.args)
-    
+    logger.info(request.url)    
     current_page = snp_browser.SnpPage(request.args).get_page()
 
     return flask.jsonify(current_page)
-- 
cgit v1.2.3


From 29902d1c60b338c1c06289f9ea1cae5a61e28d4b Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Thu, 6 Aug 2020 08:48:53 -0500
Subject: fix issue with column sort; put 'Gene' column data in one line

---
 wqflask/wqflask/snp_browser/snp_browser.py | 25 ++++++++++++-------------
 wqflask/wqflask/templates/snp_browser.html |  6 +-----
 wqflask/wqflask/views.py                   |  3 +--
 3 files changed, 14 insertions(+), 20 deletions(-)

diff --git a/wqflask/wqflask/snp_browser/snp_browser.py b/wqflask/wqflask/snp_browser/snp_browser.py
index 116da149..58c90f11 100644
--- a/wqflask/wqflask/snp_browser/snp_browser.py
+++ b/wqflask/wqflask/snp_browser/snp_browser.py
@@ -368,15 +368,15 @@ class SnpBrowser(object):
 
         #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"
-            }
+            "snp_source": "false",
+            "conservation_score": "false",
+            "gene_name": "false",
+            "transcript": "false",
+            "exon": "false",
+            "domain_2": "false",
+            "function": "false",
+            "function_details": "false"
+        }
 
         the_rows = []
         for i, result in enumerate(self.filtered_results):
@@ -651,8 +651,6 @@ class SnpPage(object):
         self.rows_count = self.snp_browser.rows_count
         self.table_rows = self.snp_browser.table_rows
         self.header_data_names = self.snp_browser.header_data_names
-
-        logger.info(self.table_rows[0])
         
         self.sort_rows()
         self.paginate_rows()
@@ -778,8 +776,9 @@ def get_header_list(variant_type, strains, species = None, empty_columns = None)
                 empty_field_count += 1
                 header_fields[0].remove('Details')
         
-        for col in empty_columns:
-            header_data_names.remove(col)
+        for col in empty_columns.keys():
+            if empty_columns[col] == "false":
+                header_data_names.remove(col)
 
     elif variant_type == "InDel":
         header_fields = ['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start', 'Mb End', 'Strand', 'Size', 'Sequence', 'Source']
diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index cbc12e06..96cd7247 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -320,7 +320,7 @@
           '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>'
+              return '<i>' + data.gene_name + '</i>, <a href="' + data.gene_link + '">NCBI</a>'
             } else {
               return data.gene_name
             }
@@ -434,10 +434,6 @@
       'sAjaxSource': '/snp_browser_table'+getParams(window.location.href),
       'infoCallback': function(settings, start, end, max, total, pre) {
         return "Showing " + start + " to " + (start + this.api().data().length - 1) + " of " + total + " entries";
-      },
-      'language': {
-        'loadingRecords': '&nbsp;',
-        'processing': 'Loading...'
       }
     });
     {% endif %}
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 8e7f6ec3..12ebf595 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -897,7 +897,6 @@ def corr_scatter_plot_page():
 def snp_browser_page():
     logger.info(request.url)
     template_vars = snp_browser.SnpBrowser(request.args)
-    logger.info(template_vars.__dict__.keys())
 
     return render_template("snp_browser.html", **template_vars.__dict__)
 
@@ -909,7 +908,7 @@ def db_info_page():
 
 @app.route("/snp_browser_table", methods=('GET',))
 def snp_browser_table():
-    logger.info(request.url)    
+    logger.info(request.url)
     current_page = snp_browser.SnpPage(request.args).get_page()
 
     return flask.jsonify(current_page)
-- 
cgit v1.2.3


From ace7b2d323c4f157f4d0e770dd948189562fa76b Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 16 Aug 2020 16:03:24 -0500
Subject: remove createdRow callback and move color rendering to column defs to
 speedup rendering

---
 wqflask/wqflask/templates/snp_browser.html | 76 +++++++++++++++---------------
 1 file changed, 38 insertions(+), 38 deletions(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 96cd7247..dad86459 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -227,10 +227,44 @@
       var json_rows = {{ table_rows|safe }};
       var json_rows_count = {{ rows_count|safe }};
       var empty_columns = {{ empty_columns|safe }};
+
+      var remain_field_count = {{ 15 - empty_field_count }};
+      var total_field_count = {{ 15 - empty_field_count }} + {{ allele_list|length }};
   </script>
 
   <script language="javascript">
 
+    var getColor = function(allele) {
+      switch (allele) {
+        case "A":
+          return ('A_allele_color');
+          break;
+        case "C":
+          return ('C_allele_color');
+          break;
+        case "T":
+          return ('T_allele_color');
+          break;
+        case "G":
+          return ('G_allele_color');
+          break;
+        case "t":
+          return ('t_allele_color');
+          break;
+        case "c":
+          return ('c_allele_color');
+          break;
+        case "a":
+          return ('a_allele_color');
+          break;
+        case "g":
+          return ('g_allele_color');
+          break;
+        default:
+          return ('default_allele_color');
+      }
+    }
+
     var getParams = function(url) {
       var parser = document.createElement('a');
       parser.href = url;
@@ -280,6 +314,7 @@
       'columns': [
         {
           'data': null,
+          'className': 'dt-body-center',
           'orderable': false,
           'render': function(data, type, row, meta) {
             return '<input type="checkbox" name="trait_check">'
@@ -308,7 +343,7 @@
           '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>'
+              return '<a href="' + data.source_urls[0] + '">Sanger</a>, <a href="' + data.source_urls[1] + '">UCLA</a>'
             } else {
               return data.snp_source
             }
@@ -347,6 +382,7 @@
         }, {% endif %} {% for item in allele_list %} {
           'data': null,
           'orderable': false,
+          'className': 'dt-body-center ' + getColor('{{ item }}'),
           '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]
@@ -356,42 +392,6 @@
           }
         }{% 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 %}
       'columns': [
         {
@@ -429,7 +429,7 @@
       {% endif %}
       'order': [[1, "asc" ]],
       'sDom': "rtip",
-      'iDisplayLength': 500,
+      'iDisplayLength': 100,
       'bServerSide': true,
       'sAjaxSource': '/snp_browser_table'+getParams(window.location.href),
       'infoCallback': function(settings, start, end, max, total, pre) {
-- 
cgit v1.2.3


From 1caac2a2337d1300e197892cf2a260867998e88e Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 16 Aug 2020 16:04:55 -0500
Subject: remove debug log

---
 wqflask/wqflask/templates/snp_browser.html | 2 --
 1 file changed, 2 deletions(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index dad86459..1a2da20f 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -269,7 +269,6 @@
       var parser = document.createElement('a');
       parser.href = url;
       var params = parser.search.substring(1);
-      console.log(params);
       if(params.length > 0) {
         return ('?'+params);
       }
@@ -548,7 +547,6 @@
       for (var i = 1; i < rows.length; i++) {
         var row = [], cols = rows[i].querySelectorAll("td");
         var checkBox = rows[i].querySelector("input");
-        console.log(checkBox);
 
         if(checkBox.checked == true) {
           for (var j = 1; j < cols.length; j++)
-- 
cgit v1.2.3


From 876b95a8e1ad5944105b8d23ae362415011239b5 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 16 Aug 2020 16:15:02 -0500
Subject: cell rendering cannot be in columnDef, optimised createdRow

---
 wqflask/wqflask/templates/snp_browser.html | 68 +++++++++++++++---------------
 1 file changed, 34 insertions(+), 34 deletions(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 1a2da20f..c7923be6 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -224,8 +224,6 @@
   <script language="javascript" type="text/javascript" src="/static/new/javascript/typeahead_rn6.json"></script>
 
   <script type='text/javascript'>
-      var json_rows = {{ table_rows|safe }};
-      var json_rows_count = {{ rows_count|safe }};
       var empty_columns = {{ empty_columns|safe }};
 
       var remain_field_count = {{ 15 - empty_field_count }};
@@ -234,37 +232,6 @@
 
   <script language="javascript">
 
-    var getColor = function(allele) {
-      switch (allele) {
-        case "A":
-          return ('A_allele_color');
-          break;
-        case "C":
-          return ('C_allele_color');
-          break;
-        case "T":
-          return ('T_allele_color');
-          break;
-        case "G":
-          return ('G_allele_color');
-          break;
-        case "t":
-          return ('t_allele_color');
-          break;
-        case "c":
-          return ('c_allele_color');
-          break;
-        case "a":
-          return ('a_allele_color');
-          break;
-        case "g":
-          return ('g_allele_color');
-          break;
-        default:
-          return ('default_allele_color');
-      }
-    }
-
     var getParams = function(url) {
       var parser = document.createElement('a');
       parser.href = url;
@@ -381,7 +348,7 @@
         }, {% endif %} {% for item in allele_list %} {
           'data': null,
           'orderable': false,
-          'className': 'dt-body-center ' + getColor('{{ item }}'),
+          'className': 'dt-body-center',
           '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]
@@ -391,6 +358,39 @@
           }
         }{% if loop.index < allele_list|length %},{% endif %}{% endfor %}
       ],
+      'createdRow': function(row, data, dataIndex) {
+        for (i = remain_field_count; i < total_field_count; i++) {
+          var this_allele = $('td', row).eq(i).text();
+          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 %}
       'columns': [
         {
-- 
cgit v1.2.3


From f52499653858512320ae17a2ff48671d82fc31fb Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 16 Aug 2020 17:11:03 -0500
Subject: move SnpPage to a generic class ServerSide

---
 wqflask/wqflask/server_side.py             | 74 ++++++++++++++++++++++++++++++
 wqflask/wqflask/snp_browser/snp_browser.py | 71 ----------------------------
 wqflask/wqflask/views.py                   | 17 ++++++-
 3 files changed, 89 insertions(+), 73 deletions(-)
 create mode 100644 wqflask/wqflask/server_side.py

diff --git a/wqflask/wqflask/server_side.py b/wqflask/wqflask/server_side.py
new file mode 100644
index 00000000..090720ec
--- /dev/null
+++ b/wqflask/wqflask/server_side.py
@@ -0,0 +1,74 @@
+# handles server side table processing
+
+
+
+class ServerSide(object):
+
+    def __init__(self, table_data, request_values):
+        self.request_values = request_values
+        self.sEcho = self.request_values['sEcho']
+
+        self.table_data = table_data
+        self.rows_count = self.table_data.rows_count
+        self.table_rows = self.table_data.table_rows
+        self.header_data_names = self.table_data.header_data_names
+        
+        self.sort_rows()
+        self.paginate_rows()
+
+    def sort_rows(self):
+        '''
+        Sorts the rows taking in to account the column (or columns) that the
+        user has selected.
+        '''
+        def is_reverse(str_direction):
+            ''' Maps the 'desc' and 'asc' words to True or False. '''
+            return True if str_direction == 'desc' else False
+
+        if (self.request_values['iSortCol_0'] != "") and (int(self.request_values['iSortingCols']) > 0):
+            for i in range(0, int(self.request_values['iSortingCols'])):
+                column_number = int(self.request_values['iSortCol_' + str(i)])
+                column_name = self.header_data_names[column_number - 1]
+                sort_direction = self.request_values['sSortDir_' + str(i)]
+                self.table_rows = sorted(self.table_rows,
+                              key=lambda x: x[column_name],
+                              reverse=is_reverse(sort_direction))
+
+    def paginate_rows(self):
+        '''
+        Selects a subset of the filtered and sorted data based on if the table
+        has pagination, the current page and the size of each page.
+        '''
+        def requires_pagination():
+            ''' Check if the table is going to be paginated '''
+            if self.request_values['iDisplayStart'] != "":
+                if int(self.request_values['iDisplayLength']) != -1:
+                    return True
+            return False
+
+        if not requires_pagination():
+            return
+
+        start = int(self.request_values['iDisplayStart'])
+        length = int(self.request_values['iDisplayLength'])
+
+        # if search returns only one page
+        if len(self.table_rows) <= length:
+            # display only one page
+            self.table_rows = self.table_rows[start:]
+        else:
+            limit = -len(self.table_rows) + start + length
+            if limit < 0:
+                # display pagination
+                self.table_rows = self.table_rows[start:limit]
+            else:
+                # display last page of pagination
+                self.table_rows = self.table_rows[start:]
+
+    def get_page(self):
+        output = {}
+        output['sEcho'] = str(self.sEcho)
+        output['iTotalRecords'] = str(float('Nan'))
+        output['iTotalDisplayRecords'] = str(self.rows_count)
+        output['data'] = self.table_rows
+        return output
diff --git a/wqflask/wqflask/snp_browser/snp_browser.py b/wqflask/wqflask/snp_browser/snp_browser.py
index 58c90f11..a52399a2 100644
--- a/wqflask/wqflask/snp_browser/snp_browser.py
+++ b/wqflask/wqflask/snp_browser/snp_browser.py
@@ -641,77 +641,6 @@ class SnpBrowser(object):
         #for i in range(n_click):
         #    href = url_for('snp_browser', first_run="false", chosen_strains_mouse=self.chosen_strains_mouse, chosen_strains_rat=self.chosen_strains_rat, variant=self.variant_type, species=self.species_name, gene_name=self.gene_name, chr=self.chr, start_mb=self.start_mb, end_mb=self.end_mb, limit_strains=self.limit_strains, domain=self.domain, function=self.function, criteria=self.criteria, score=self.score, diff_alleles=self.diff_alleles)
 
-class SnpPage(object):
-
-    def __init__(self, request):
-        self.request_values = request
-        self.sEcho = self.request_values['sEcho']
-
-        self.snp_browser = SnpBrowser(request)
-        self.rows_count = self.snp_browser.rows_count
-        self.table_rows = self.snp_browser.table_rows
-        self.header_data_names = self.snp_browser.header_data_names
-        
-        self.sort_rows()
-        self.paginate_rows()
-
-    def sort_rows(self):
-        '''
-        Sorts the rows taking in to account the column (or columns) that the
-        user has selected.
-        '''
-        def is_reverse(str_direction):
-            ''' Maps the 'desc' and 'asc' words to True or False. '''
-            return True if str_direction == 'desc' else False
-
-        if (self.request_values['iSortCol_0'] != "") and (int(self.request_values['iSortingCols']) > 0):
-            for i in range(0, int(self.request_values['iSortingCols'])):
-                column_number = int(self.request_values['iSortCol_' + str(i)])
-                column_name = self.header_data_names[column_number - 1]
-                sort_direction = self.request_values['sSortDir_' + str(i)]
-                self.table_rows = sorted(self.table_rows,
-                              key=lambda x: x[column_name],
-                              reverse=is_reverse(sort_direction))
-
-    def paginate_rows(self):
-        '''
-        Selects a subset of the filtered and sorted data based on if the table
-        has pagination, the current page and the size of each page.
-        '''
-        def requires_pagination():
-            ''' Check if the table is going to be paginated '''
-            if self.request_values['iDisplayStart'] != "":
-                if int(self.request_values['iDisplayLength']) != -1:
-                    return True
-            return False
-
-        if not requires_pagination():
-            return
-
-        start = int(self.request_values['iDisplayStart'])
-        length = int(self.request_values['iDisplayLength'])
-
-        # if search returns only one page
-        if len(self.table_rows) <= length:
-            # display only one page
-            self.table_rows = self.table_rows[start:]
-        else:
-            limit = -len(self.table_rows) + start + length
-            if limit < 0:
-                # display pagination
-                self.table_rows = self.table_rows[start:limit]
-            else:
-                # display last page of pagination
-                self.table_rows = self.table_rows[start:]
-
-    def get_page(self):
-        output = {}
-        output['sEcho'] = str(self.sEcho)
-        output['iTotalRecords'] = str(float('Nan'))
-        output['iTotalDisplayRecords'] = str(self.rows_count)
-        output['data'] = self.table_rows
-        return output
-
 def get_browser_sample_lists(species_id=1):
     strain_lists = {}
     mouse_strain_list = []
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 12ebf595..185517d3 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -27,7 +27,19 @@ import array
 import sqlalchemy
 from wqflask import app
 from flask import g, Response, request, make_response, render_template, send_from_directory, jsonify, redirect, url_for, send_file
-
+<<<<<<< HEAD
+
+=======
+from wqflask import group_manager
+from wqflask import resource_manager
+from wqflask import search_results
+from wqflask import export_traits
+from wqflask import gsearch
+from wqflask import update_search_results
+from wqflask import docs
+from wqflask import news
+from wqflask import server_side
+>>>>>>> ed2afa4a (move SnpPage to a generic class ServerSide)
 from wqflask.submit_bnw import get_bnw_input
 from base.data_set import create_dataset, DataSet    # Used by YAML in marker_regression
 from wqflask.show_trait import show_trait
@@ -909,7 +921,8 @@ def db_info_page():
 @app.route("/snp_browser_table", methods=('GET',))
 def snp_browser_table():
     logger.info(request.url)
-    current_page = snp_browser.SnpPage(request.args).get_page()
+    snp_table_data = snp_browser.SnpBrowser(request.args)
+    current_page = server_side.ServerSide(snp_table_data, request.args).get_page()
 
     return flask.jsonify(current_page)
 
-- 
cgit v1.2.3


From c6e4083da1c78c923ba94b3057e1fe5e09f5b603 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 16 Aug 2020 17:14:00 -0500
Subject: fix issue when empty_filed_count is not claculated

---
 wqflask/wqflask/templates/snp_browser.html | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index c7923be6..284a371a 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -226,8 +226,8 @@
   <script type='text/javascript'>
       var empty_columns = {{ empty_columns|safe }};
 
-      var remain_field_count = {{ 15 - empty_field_count }};
-      var total_field_count = {{ 15 - empty_field_count }} + {{ allele_list|length }};
+      var remain_field_count = 15 - {{ empty_field_count|safe }};
+      var total_field_count = 15 - {{ empty_field_count|safe }} + {{ allele_list|safe|length }};
   </script>
 
   <script language="javascript">
-- 
cgit v1.2.3


From 6b7dfb6ad280aa247c106f155fef81a03bd71c65 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 16 Aug 2020 17:30:13 -0500
Subject: make the page more color consistent

---
 wqflask/wqflask/static/new/css/snp_browser.css | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/static/new/css/snp_browser.css b/wqflask/wqflask/static/new/css/snp_browser.css
index 30fe9a59..1dd332cb 100644
--- a/wqflask/wqflask/static/new/css/snp_browser.css
+++ b/wqflask/wqflask/static/new/css/snp_browser.css
@@ -18,7 +18,7 @@ table.dataTable thead .sorting_desc_disabled {
 table.dataTable thead th{
   border-right: 1px solid white;
   color: white;
-  background-color: royalblue;
+  background-color: #369;
 }
 
 table.dataTable tbody td {
-- 
cgit v1.2.3


From 0952e43989be3f24321932c3dd33fdc697c5703a Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 23 Aug 2020 14:47:39 -0500
Subject: replace var to let for variables in loops

---
 wqflask/wqflask/templates/snp_browser.html | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 284a371a..435a521c 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -539,17 +539,17 @@
 
       var headers = [];
       var col_header = rows[0].querySelectorAll("th");
-      for(var i = 1; i < col_header.length; i++) {
+      for(let i = 1; i < col_header.length; i++) {
         headers.push(col_header[i].getAttribute("name"));
       }
       csv.push(headers.join(","));
 
-      for (var i = 1; i < rows.length; i++) {
+      for (let i = 1; i < rows.length; i++) {
         var row = [], cols = rows[i].querySelectorAll("td");
         var checkBox = rows[i].querySelector("input");
 
         if(checkBox.checked == true) {
-          for (var j = 1; j < cols.length; j++)
+          for (let j = 1; j < cols.length; j++)
             row.push(cols[j].innerText);
 
             csv.push(row.join(","));
-- 
cgit v1.2.3


From dfdff4934e423e2f4f626625a8bd1f45a64187b4 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 23 Aug 2020 16:13:11 -0500
Subject: update class name to ServerSideTable and add docstring

---
 wqflask/wqflask/server_side.py | 22 +++++++++++++++++++++-
 wqflask/wqflask/views.py       |  2 +-
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/wqflask/wqflask/server_side.py b/wqflask/wqflask/server_side.py
index 090720ec..d044d411 100644
--- a/wqflask/wqflask/server_side.py
+++ b/wqflask/wqflask/server_side.py
@@ -2,7 +2,27 @@
 
 
 
-class ServerSide(object):
+class ServerSideTable(object):
+    '''
+        This class is used to do server-side processing
+        on the DataTables table such as paginating, sorting,
+        filtering(not implemented) etc. This takes the load off
+        the client-side and reduces the size of data interchanged.
+
+        Usage:
+            ServerSideTable(table_data, request_values)
+        where,
+            `table_data` must have data members
+            `rows_count` as number of rows in the table,
+            `table_rows` as data rows of the table,
+            `header_data_names` as headers names of the table.
+
+            `request_values` must have request arguments values
+            including the DataTables server-side processing arguments.
+
+        Have a look at snp_browser_table() function in 
+        wqflask/wqflask/views.py for reference use.
+    '''
 
     def __init__(self, table_data, request_values):
         self.request_values = request_values
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 185517d3..f0b78188 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -922,7 +922,7 @@ def db_info_page():
 def snp_browser_table():
     logger.info(request.url)
     snp_table_data = snp_browser.SnpBrowser(request.args)
-    current_page = server_side.ServerSide(snp_table_data, request.args).get_page()
+    current_page = server_side.ServerSideTable(snp_table_data, request.args).get_page()
 
     return flask.jsonify(current_page)
 
-- 
cgit v1.2.3


From aa2d7a45fca8c6503a5de6cec7ce58d248144b9d Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 6 Sep 2020 10:38:19 -0500
Subject: add row highlight on checkbox checked state

---
 wqflask/wqflask/static/new/css/snp_browser.css |  4 ++++
 wqflask/wqflask/templates/snp_browser.html     | 17 +++++++++++++++--
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/wqflask/wqflask/static/new/css/snp_browser.css b/wqflask/wqflask/static/new/css/snp_browser.css
index 1dd332cb..a7942d2a 100644
--- a/wqflask/wqflask/static/new/css/snp_browser.css
+++ b/wqflask/wqflask/static/new/css/snp_browser.css
@@ -6,6 +6,10 @@ table.dataTable thead th {
   vertical-align: bottom;
 }
 
+table.dataTable tbody tr.selected {
+  background-color: #ffee99;
+}
+
 table.dataTable thead .sorting,
 table.dataTable thead .sorting_asc,
 table.dataTable thead .sorting_desc,
diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index 435a521c..c312aee8 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -283,7 +283,7 @@
           'className': 'dt-body-center',
           'orderable': false,
           'render': function(data, type, row, meta) {
-            return '<input type="checkbox" name="trait_check">'
+            return '<input type="checkbox" class="checkbox" id="variant_checkbox" onchange="onVarinatCheck(this)" name="trait_check">'
           }
         }, {
           'data': 'index',
@@ -396,7 +396,7 @@
         {
           'data': null,
           'render': function(data, type, row, meta) {
-            return '<input type="checkbox" name="trait_check">'
+            return '<input type="checkbox" class="checkbox" id="variant_checkbox" onchange="onVarinatCheck(this)" name="trait_check">'
           }
         }, {
           'data': 'index',
@@ -437,6 +437,19 @@
     });
     {% endif %}
 
+    function onVarinatCheck(checkboxElem) {
+        if (checkboxElem.checked) {
+            if (!checkboxElem.parentElement.parentElement.classList.contains('selected')) {
+                checkboxElem.parentElement.parentElement.classList.add('selected')
+            }
+        }
+        else {
+            if (checkboxElem.parentElement.parentElement.classList.contains('selected')) {
+                checkboxElem.parentElement.parentElement.classList.remove('selected')
+            }
+        }
+    }
+
     $("#species_select").change(function() {
         this_species = $(this).val();
         $("#strain_select").empty()
-- 
cgit v1.2.3


From f3351f698c7961aa28578b90fa0c73a2e14f864d Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 6 Sep 2020 15:52:08 -0500
Subject: change arguments for ServerSideTable class

---
 wqflask/wqflask/server_side.py | 9 ++++-----
 wqflask/wqflask/views.py       | 7 ++++++-
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/wqflask/wqflask/server_side.py b/wqflask/wqflask/server_side.py
index d044d411..824b00aa 100644
--- a/wqflask/wqflask/server_side.py
+++ b/wqflask/wqflask/server_side.py
@@ -24,14 +24,13 @@ class ServerSideTable(object):
         wqflask/wqflask/views.py for reference use.
     '''
 
-    def __init__(self, table_data, request_values):
+    def __init__(self, rows_count, table_rows, header_data_names, request_values):
         self.request_values = request_values
         self.sEcho = self.request_values['sEcho']
 
-        self.table_data = table_data
-        self.rows_count = self.table_data.rows_count
-        self.table_rows = self.table_data.table_rows
-        self.header_data_names = self.table_data.header_data_names
+        self.rows_count = rows_count
+        self.table_rows = table_rows
+        self.header_data_names = header_data_names
         
         self.sort_rows()
         self.paginate_rows()
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index f0b78188..63570815 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -922,7 +922,12 @@ def db_info_page():
 def snp_browser_table():
     logger.info(request.url)
     snp_table_data = snp_browser.SnpBrowser(request.args)
-    current_page = server_side.ServerSideTable(snp_table_data, request.args).get_page()
+    current_page = server_side.ServerSideTable(
+        snp_table_data.rows_count,
+        snp_table_data.table_rows,
+        snp_table_data.header_data_names,
+        request.args,
+    ).get_page()
 
     return flask.jsonify(current_page)
 
-- 
cgit v1.2.3


From 59e611827bf0621b2613cc29b3f4ba730ef3631e Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 13 Sep 2020 13:55:33 -0500
Subject: add server side processing to search table (/search and
 search_result_page.html)

---
 wqflask/wqflask/search_results.py                 | 16 +++++++++++-----
 wqflask/wqflask/templates/search_result_page.html | 21 ++++++++++++++++-----
 wqflask/wqflask/views.py                          | 20 ++++++++++++++++++++
 3 files changed, 47 insertions(+), 10 deletions(-)

diff --git a/wqflask/wqflask/search_results.py b/wqflask/wqflask/search_results.py
index ce836ce2..8a5a7a80 100644
--- a/wqflask/wqflask/search_results.py
+++ b/wqflask/wqflask/search_results.py
@@ -28,9 +28,9 @@ class SearchResultPage(object):
     #maxReturn = 3000
 
     def __init__(self, kw):
-        """This class gets invoked after hitting submit on the main menu (in
-views.py).
-
+        """
+            This class gets invoked after hitting submit on the main menu (in
+            views.py).
         """
 
         ###########################################
@@ -86,7 +86,6 @@ views.py).
             else:
                 self.gen_search_result()
 
-
     def gen_search_result(self):
         """
         Get the info displayed in the search result table from the set of results computed in
@@ -155,7 +154,14 @@ views.py).
                         trait_dict[key] = trait_dict[key].decode('utf-8')
                 trait_list.append(trait_dict)
 
-        self.trait_list = json.dumps(trait_list)
+        self.trait_list = trait_list
+
+        if this_trait.dataset.type == "ProbeSet":
+            self.header_data_names = ['index', 'display_name', 'symbol', 'description', 'location', 'mean', 'lrs_score', 'lrs_location', 'additive']
+        elif this_trait.dataset.type == "Publish":
+            self.header_data_names = ['index', 'display_name', 'description', 'mean', 'authors', 'pubmed_text', 'lrs_score', 'lrs_location', 'additive']
+        elif this_trait.dataset.type == "Geno":
+            self.header_data_names = ['index', 'display_name', 'location']
 
     def search(self):
         """
diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index 2318bfb8..7d36d32e 100644
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -174,6 +174,16 @@
 
     <script type="text/javascript" charset="utf-8">
         $(document).ready( function () {
+
+            var getParams = function(url) {
+                var parser = document.createElement('a');
+                parser.href = url;
+                var params = parser.search.substring(1);
+                if(params.length > 0) {
+                    return ('?'+params);
+                }
+                return params;
+            };
             
             $('#trait_table tr').click(function(event) {
                 if (event.target.type !== 'checkbox') {
@@ -260,7 +270,7 @@
                       'data': null,
                       'width': "25px",
                       'orderDataType': "dom-checkbox",
-                      'orderSequence': [ "desc", "asc"],
+                      'orderable': false,
                       'render': function(data, type, row, meta) {
                         return '<input type="checkbox" name="searchResult" class="checkbox trait_checkbox" value="' + data.hmac + '">'
                       }
@@ -426,14 +436,15 @@
                 {% else %}
                 'sDom': "pitirp",
                 {% endif %}
-                'iDisplayLength': 500,
+                'iDisplayLength': 10,
                 'deferRender': true,
                 'paging': true,
                 'orderClasses': true,
                 'processing': true,
-                'language': {
-                  'loadingRecords': '&nbsp;',
-                  'processing': 'Loading...'
+                'bServerSide': true,
+                'sAjaxSource': '/search_table'+getParams(window.location.href),
+                'infoCallback': function(settings, start, end, max, total, pre) {
+                  return "Showing " + start + " to " + (start + this.api().data().length - 1) + " of " + total + " entries";
                 }
             } );
 
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 63570815..2c1fa94b 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -234,6 +234,26 @@ def search_page():
     else:
         return render_template("search_error.html")
 
+@app.route("/search_table", methods=('GET',))
+def search_page_table():
+    logger.info("in search_page table")
+    logger.info(request.url)
+
+    logger.info("request.args is", request.args)
+    the_search = search_results.SearchResultPage(request.args)
+
+    logger.info(type(the_search.trait_list))
+    logger.info(the_search.trait_list)
+    
+    current_page = server_side.ServerSideTable(
+        len(the_search.trait_list),
+        the_search.trait_list,
+        the_search.header_data_names,
+        request.args,
+    ).get_page()
+
+    return flask.jsonify(current_page)
+
 @app.route("/gsearch", methods=('GET',))
 def gsearchact():
     logger.info(request.url)
-- 
cgit v1.2.3


From e83bcab9f01ad1aa279f15e8a19700b802320f8b Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 13 Sep 2020 15:19:51 -0500
Subject: add pagination to show_trait tables and reduce css post processing
 for faster table loading

---
 wqflask/wqflask/templates/search_result_page.html | 2 +-
 wqflask/wqflask/views.py                          | 3 ---
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index 7d36d32e..0bcbd492 100644
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -436,7 +436,7 @@
                 {% else %}
                 'sDom': "pitirp",
                 {% endif %}
-                'iDisplayLength': 10,
+                'iDisplayLength': 100,
                 'deferRender': true,
                 'paging': true,
                 'orderClasses': true,
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 2c1fa94b..2df7113e 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -27,9 +27,7 @@ import array
 import sqlalchemy
 from wqflask import app
 from flask import g, Response, request, make_response, render_template, send_from_directory, jsonify, redirect, url_for, send_file
-<<<<<<< HEAD
 
-=======
 from wqflask import group_manager
 from wqflask import resource_manager
 from wqflask import search_results
@@ -39,7 +37,6 @@ from wqflask import update_search_results
 from wqflask import docs
 from wqflask import news
 from wqflask import server_side
->>>>>>> ed2afa4a (move SnpPage to a generic class ServerSide)
 from wqflask.submit_bnw import get_bnw_input
 from base.data_set import create_dataset, DataSet    # Used by YAML in marker_regression
 from wqflask.show_trait import show_trait
-- 
cgit v1.2.3


From e106f5888cb4d761a6dcb71dc0273e461ef3c71a Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 13 Sep 2020 15:24:06 -0500
Subject: replace var with let in getParams() local variables

---
 wqflask/wqflask/templates/search_result_page.html | 4 ++--
 wqflask/wqflask/templates/snp_browser.html        | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index 0bcbd492..6fe44d1a 100644
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -176,9 +176,9 @@
         $(document).ready( function () {
 
             var getParams = function(url) {
-                var parser = document.createElement('a');
+                let parser = document.createElement('a');
                 parser.href = url;
-                var params = parser.search.substring(1);
+                let params = parser.search.substring(1);
                 if(params.length > 0) {
                     return ('?'+params);
                 }
diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index c312aee8..129d03c2 100644
--- a/wqflask/wqflask/templates/snp_browser.html
+++ b/wqflask/wqflask/templates/snp_browser.html
@@ -233,9 +233,9 @@
   <script language="javascript">
 
     var getParams = function(url) {
-      var parser = document.createElement('a');
+      let parser = document.createElement('a');
       parser.href = url;
-      var params = parser.search.substring(1);
+      let params = parser.search.substring(1);
       if(params.length > 0) {
         return ('?'+params);
       }
-- 
cgit v1.2.3


From 30e8aaad9672151c4b6bc43ea386d0d39ca131a7 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Wed, 9 Dec 2020 16:18:07 -0600
Subject: Exchanged metadata and legend positions and made some changes to Y
 positioning for the metadata

---
 .../marker_regression/display_mapping_results.py   | 39 +++++++++++++---------
 1 file changed, 24 insertions(+), 15 deletions(-)

diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py
index 08c2d750..9f778160 100644
--- a/wqflask/wqflask/marker_regression/display_mapping_results.py
+++ b/wqflask/wqflask/marker_regression/display_mapping_results.py
@@ -644,8 +644,10 @@ class DisplayMappingResults(object):
             yTopOffset = max(90, yTopOffset)
         else:
             if self.legendChecked:
-                if self.covariates != "" and self.controlLocus and self.doControl != "false":
-                    yTopOffset = max(120, yTopOffset)
+                if (self.mapping_method == "gemma" or self.mapping_method == "rqtl_geno") and self.covariates != "":
+                    yTopOffset = max(115, yTopOffset)
+                elif self.mapping_method == "rqtl_geno" and self.controlLocus and self.doControl != "false" and self.covariates != "":
+                    yTopOffset = max(130, yTopOffset)
                 else:
                     yTopOffset = max(100, yTopOffset)
             else:
@@ -859,13 +861,12 @@ class DisplayMappingResults(object):
 
         if self.legendChecked:
             startPosY = 30
-            nCol = 2
             smallLabelFont = ImageFont.truetype(font=TREBUC_FILE, size=12*fontZoom)
-            leftOffset = xLeftOffset+(nCol-1)*200
+            leftOffset = canvas.size[0] - xRightOffset - 190
             im_drawer.rectangle(
                 xy=((leftOffset, startPosY-6), (leftOffset+12, startPosY+6)),
                 fill=YELLOW, outline=BLACK)
-            im_drawer.text(xy=(leftOffset+ 20, startPosY+TEXT_Y_DISPLACEMENT),
+            im_drawer.text(xy=(canvas.size[0] - xRightOffset - 170, startPosY+TEXT_Y_DISPLACEMENT),
                            text='Frequency of the Peak LRS',
                            font=smallLabelFont, fill=BLACK)
 
@@ -1069,7 +1070,7 @@ class DisplayMappingResults(object):
             startPosY += stepPosY
 
         if self.additiveChecked:
-            startPosX = xLeftOffset
+            startPosX = canvas.size[0] - xRightOffset - 400
             im_drawer.line(
                 xy=((startPosX, startPosY), (startPosX+17, startPosY)),
                 fill=self.ADDITIVE_COLOR_POSITIVE, width=2)
@@ -1081,7 +1082,7 @@ class DisplayMappingResults(object):
                 font=labelFont, fill=BLACK)
 
         if self.genotype.type == 'intercross' and self.dominanceChecked:
-            startPosX = xLeftOffset
+            startPosX = canvas.size[0] - xRightOffset - 400
             startPosY += stepPosY
             im_drawer.line(
                 xy=((startPosX, startPosY), (startPosX+17, startPosY)),
@@ -1095,7 +1096,7 @@ class DisplayMappingResults(object):
 
         if self.haplotypeAnalystChecked:
             startPosY += stepPosY
-            startPosX = xLeftOffset
+            startPosX = canvas.size[0] - xRightOffset - 400
             im_drawer.line(
                 xy=((startPosX, startPosY), (startPosX+17, startPosY)),
                 fill=self.HAPLOTYPE_POSITIVE, width=4)
@@ -1114,7 +1115,10 @@ class DisplayMappingResults(object):
 
         if self.permChecked and self.nperm > 0:
             startPosY += stepPosY
-            startPosX = xLeftOffset
+            if self.bootChecked and not self.multipleInterval:
+                startPosX = canvas.size[0] - xRightOffset - 400
+            else:
+                startPosX = canvas.size[0] - xRightOffset - 190
             im_drawer.line(
                 xy=((startPosX, startPosY), ( startPosX + 32, startPosY)),
                 fill=self.SIGNIFICANT_COLOR, width=self.SIGNIFICANT_WIDTH)
@@ -1123,10 +1127,10 @@ class DisplayMappingResults(object):
                 fill=self.SUGGESTIVE_COLOR, width=self.SUGGESTIVE_WIDTH)
             im_drawer.text(
                 text='Significant %s = %2.2f' % (self.LRS_LOD, self.significant),
-                xy=(xLeftOffset+42, startPosY+TEXT_Y_DISPLACEMENT), font=labelFont, fill=BLACK)
+                xy=(startPosX+42, startPosY+TEXT_Y_DISPLACEMENT), font=labelFont, fill=BLACK)
             im_drawer.text(
                 text='Suggestive %s = %2.2f' % (self.LRS_LOD, self.suggestive),
-                xy=(xLeftOffset+42, startPosY + TEXT_Y_DISPLACEMENT +stepPosY), font=labelFont,
+                xy=(startPosX+42, startPosY + TEXT_Y_DISPLACEMENT +stepPosY), font=labelFont,
                 fill=BLACK)
 
         labelFont = ImageFont.truetype(font=VERDANA_FILE, size=12*fontZoom)
@@ -1197,22 +1201,26 @@ class DisplayMappingResults(object):
                 im_drawer.textsize(string2, font=labelFont)[0])
             im_drawer.text(
                 text=identification,
-                xy=(canvas.size[0] - xRightOffset-d, 20*fontZoom), font=labelFont,
+                xy=(xLeftOffset, 20*fontZoom), font=labelFont,
                 fill=labelColor)
         else:
             d = 4+ max(
                 im_drawer.textsize(string1, font=labelFont)[0],
                 im_drawer.textsize(string2, font=labelFont)[0])
         im_drawer.text(
-            text=string1, xy=(canvas.size[0] - xRightOffset-d, 35*fontZoom),
+            text=string1, xy=(xLeftOffset, 35*fontZoom),
             font=labelFont, fill=labelColor)
         im_drawer.text(
-            text=string2, xy=(canvas.size[0] - xRightOffset-d, 50*fontZoom),
+            text=string2, xy=(xLeftOffset, 50*fontZoom),
             font=labelFont, fill=labelColor)
         if string3 != '':
             im_drawer.text(
-                text=string3, xy=(canvas.size[0] - xRightOffset-d, 65*fontZoom),
+                text=string3, xy=(xLeftOffset, 65*fontZoom),
                 font=labelFont, fill=labelColor)
+            if string4 != '':
+                im_drawer.text(
+                    text=string4, xy=(xLeftOffset, 80*fontZoom),
+                    font=labelFont, fill=labelColor)
 
 
     def drawGeneBand(self, canvas, gifmap, plotXScale, offset= (40, 120, 80, 10), zoom = 1, startMb = None, endMb = None):
@@ -2244,6 +2252,7 @@ class DisplayMappingResults(object):
                 )
                 sugg_coords = "%d, %d, %d, %d" % (start_pos_x, suggestiveY-2, rightEdge + 2*zoom, suggestiveY+2)
                 sig_coords = "%d, %d, %d, %d" % (start_pos_x, significantY-2, rightEdge + 2*zoom, significantY+2)
+
                 if self.LRS_LOD == 'LRS':
                     sugg_title = "Suggestive LRS = %0.2f" % self.suggestive
                     sig_title = "Significant LRS = %0.2f" % self.significant
-- 
cgit v1.2.3


From 295805eeb01aceb2651f79662c1462f06e1591cf Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 10 Dec 2020 12:27:48 -0600
Subject: Replacing the Scroller import with the CDN until we figure out why
 the new import doesn't work

---
 wqflask/wqflask/templates/show_trait.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html
index b02f8140..c95a0522 100644
--- a/wqflask/wqflask/templates/show_trait.html
+++ b/wqflask/wqflask/templates/show_trait.html
@@ -146,7 +146,7 @@
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTables/js/jquery.dataTables.js') }}"></script>
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/plugins/sorting/scientific.js') }}"></script>
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/plugins/sorting/natural.js') }}"></script>
-    <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/scroller/js/scroller.dataTables.min.js') }}"></script>
+    <script language="javascript" type="text/javascript" src="https://cdn.datatables.net/scroller/2.0.3/js/dataTables.scroller.min.js"></script>
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='nouislider/nouislider.js') }}"></script>
     <script type="text/javascript" src="/static/new/javascript/initialize_show_trait_tables.js"></script>
     <script type="text/javascript" src="/static/new/javascript/show_trait_mapping_tools.js"></script>
-- 
cgit v1.2.3


From 4760b390f7e87ea16152a7ecf5422abfb4125176 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Tue, 15 Dec 2020 14:36:12 -0600
Subject: Fixed typo in mapping results table

---
 wqflask/wqflask/templates/mapping_results.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html
index 86aa74b0..1a76ef7a 100644
--- a/wqflask/wqflask/templates/mapping_results.html
+++ b/wqflask/wqflask/templates/mapping_results.html
@@ -389,7 +389,7 @@
                     "orderable": false
                 } ],
                 "language": {
-                  "info": "Showing1 from _START_ to _END_ of " + js_data.total_markers + " records",
+                  "info": "Showing from _START_ to _END_ of " + js_data.total_markers + " records",
                 },
                 "order": [[1, "asc" ]],
                 "sDom": "iRZtir",
-- 
cgit v1.2.3


From 13ae2b093720a04b63f50a77b92e3b8e480b5ae1 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Tue, 15 Dec 2020 14:38:42 -0600
Subject: Added additive effect to GEMMA results + removed an unused function

---
 wqflask/wqflask/marker_regression/gemma_mapping.py | 46 ++++------------------
 1 file changed, 8 insertions(+), 38 deletions(-)

diff --git a/wqflask/wqflask/marker_regression/gemma_mapping.py b/wqflask/wqflask/marker_regression/gemma_mapping.py
index 61e4897c..630a3afa 100644
--- a/wqflask/wqflask/marker_regression/gemma_mapping.py
+++ b/wqflask/wqflask/marker_regression/gemma_mapping.py
@@ -80,7 +80,7 @@ def run_gemma(this_trait, this_dataset, samples, vals, covariates, use_loco, maf
 
           os.system(generate_k_command)
 
-          gemma_command = GEMMA_WRAPPER_COMMAND + ' --json --input %s/gn2/%s.json -- ' % (TEMPDIR, k_output_filename) + GEMMAOPTS + ' -a %s/%s_snps.txt -lmm 2 -g %s/%s_geno.txt -p %s/gn2/%s.txt' % (flat_files('genotype/bimbam'),
+          gemma_command = GEMMA_WRAPPER_COMMAND + ' --json --input %s/gn2/%s.json -- ' % (TEMPDIR, k_output_filename) + GEMMAOPTS + ' -a %s/%s_snps.txt -lmm 9 -g %s/%s_geno.txt -p %s/gn2/%s.txt' % (flat_files('genotype/bimbam'),
                                                                                          genofile_name,
                                                                                          flat_files('genotype/bimbam'),
                                                                                          genofile_name,
@@ -101,7 +101,7 @@ def run_gemma(this_trait, this_dataset, samples, vals, covariates, use_loco, maf
         marker_obs = parse_loco_output(this_dataset, gwa_output_filename)
         return marker_obs, gwa_output_filename
     else:
-        marker_obs = parse_loco_output(this_dataset, gwa_output_filename)
+        marker_obs = parse_loco_output(this_dataset, gwa_output_filename, use_loco)
         return marker_obs, gwa_output_filename
 
 def gen_pheno_txt_file(this_dataset, genofile_name, vals, trait_filename):
@@ -145,41 +145,7 @@ def gen_covariates_file(this_dataset, covariates, samples):
                 outfile.write(str(this_covariate[i]) + "\t")
             outfile.write("\n")
 
-def parse_gemma_output(genofile_name):
-    included_markers = []
-    p_values = []
-    marker_obs = []
-
-    with open("{}{}_output.assoc.txt".format(webqtlConfig.GENERATED_IMAGE_DIR, genofile_name)) as output_file:
-        for line in output_file:
-            if line.startswith("chr\t"):
-                continue
-            else:
-                marker = {}
-                marker['name'] = line.split("\t")[1]
-                if line.split("\t")[0] != "X" and line.split("\t")[0] != "X/Y":
-                    if "chr" in line.split("\t")[0]:
-                        marker['chr'] = int(line.split("\t")[0][3:])
-                    else:
-                        marker['chr'] = int(line.split("\t")[0])
-                else:
-                    marker['chr'] = line.split("\t")[0]
-                marker['Mb'] = float(line.split("\t")[2]) / 1000000
-                marker['p_value'] = float(line.split("\t")[9])
-                if math.isnan(marker['p_value']) or (marker['p_value'] <= 0):
-                    marker['lod_score'] = 0
-                    #marker['lrs_value'] = 0
-                else:
-                    marker['lod_score'] = -math.log10(marker['p_value'])
-                    #marker['lrs_value'] = -math.log10(marker['p_value']) * 4.61
-                marker_obs.append(marker)
-
-                included_markers.append(line.split("\t")[1])
-                p_values.append(float(line.split("\t")[9]))
-
-    return marker_obs
-
-def parse_loco_output(this_dataset, gwa_output_filename):
+def parse_loco_output(this_dataset, gwa_output_filename, loco="True"):
 
     output_filelist = []
     with open("{}/gn2/".format(TEMPDIR) + gwa_output_filename + ".json") as data_file:
@@ -218,7 +184,11 @@ def parse_loco_output(this_dataset, gwa_output_filename):
                     else:
                         marker['chr'] = line.split("\t")[0]
                     marker['Mb'] = float(line.split("\t")[2]) / 1000000
-                    marker['p_value'] = float(line.split("\t")[9])
+                    if loco == "True":
+                        marker['p_value'] = float(line.split("\t")[9])
+                    else:
+                        marker['p_value'] = float(line.split("\t")[10])
+                        marker['additive'] = float(line.split("\t")[7])
                     if math.isnan(marker['p_value']) or (marker['p_value'] <= 0):
                         marker['lod_score'] = 0
                         #marker['lrs_value'] = 0
-- 
cgit v1.2.3


From 87fdfc19009acda8b58729d0ffbdccbdf6a85a1e Mon Sep 17 00:00:00 2001
From: zsloan
Date: Wed, 16 Dec 2020 11:27:39 -0600
Subject: Set all attribute names to lower-case for sorting in order to keep
 order consistent

---
 wqflask/wqflask/show_trait/SampleList.py                              | 4 ++--
 wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js | 2 +-
 wqflask/wqflask/static/new/javascript/show_trait.js                   | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/wqflask/wqflask/show_trait/SampleList.py b/wqflask/wqflask/show_trait/SampleList.py
index 00495377..ece485ae 100644
--- a/wqflask/wqflask/show_trait/SampleList.py
+++ b/wqflask/wqflask/show_trait/SampleList.py
@@ -108,7 +108,7 @@ class SampleList(object):
                         FROM CaseAttribute, CaseAttributeXRefNew
                         WHERE CaseAttributeXRefNew.CaseAttributeId = CaseAttribute.Id
                         AND CaseAttributeXRefNew.InbredSetId = %s
-                        ORDER BY CaseAttribute.Name''', (str(self.dataset.group.id),))
+                        ORDER BY lower(CaseAttribute.Name)''', (str(self.dataset.group.id),))
 
         self.attributes = {}
         for attr, values in itertools.groupby(results.fetchall(), lambda row: (row.Id, row.Name)):
@@ -157,7 +157,7 @@ class SampleList(object):
                     except ValueError:
                         pass
 
-                    attribute_values[self.attributes[item.Id].name] = attribute_value
+                    attribute_values[self.attributes[item.Id].name.lower()] = attribute_value
                 self.sample_attribute_values[sample_name] = attribute_values
 
     def get_first_attr_col(self):
diff --git a/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js b/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js
index 5a4f151c..4362a75e 100644
--- a/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js
+++ b/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js
@@ -93,7 +93,7 @@ build_columns = function() {
     );
   }
 
-  attr_keys = Object.keys(js_data.attributes).sort((a, b) => (js_data.attributes[a].name > js_data.attributes[b].name) ? 1 : -1)
+  attr_keys = Object.keys(js_data.attributes).sort((a, b) => (js_data.attributes[a].name.toLowerCase() > js_data.attributes[b].name.toLowerCase()) ? 1 : -1)
   for (i = 0; i < attr_keys.length; i++){
     column_list.push(
       {
diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 5dc9e456..98f90f7d 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -571,7 +571,7 @@ populate_sample_attributes_values_dropdown = function() {
   sample_attributes = [];
 
   var attributes_as_list = Object.keys(js_data.attributes).map(function(key) {
-    return [key, js_data.attributes[key].name];
+    return [key, js_data.attributes[key].name.toLowerCase()];
   });
 
   attributes_as_list.sort(function(first, second) {
-- 
cgit v1.2.3


From 124bc16cdc67b6ba31a281e619dcf15f181ba131 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Wed, 16 Dec 2020 11:33:10 -0600
Subject: Removed ID/Sample/Value from Show/Hide Columns in trait page and only
 show the option if columns other than those exist

---
 wqflask/wqflask/templates/show_trait_edit_data.html | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/wqflask/wqflask/templates/show_trait_edit_data.html b/wqflask/wqflask/templates/show_trait_edit_data.html
index 4ad11a5e..0d34bebc 100644
--- a/wqflask/wqflask/templates/show_trait_edit_data.html
+++ b/wqflask/wqflask/templates/show_trait_edit_data.html
@@ -1,12 +1,9 @@
 <div>
     {% for sample_type in sample_groups %}
       <div class="sample-table-container">
-        {% if loop.index == 1 %}
+        {% if loop.index == 1 and (sample_groups[0].se_exists or has_num_cases or sample_groups[0].attributes|length > 0) %}
         <b>Show/Hide Columns:</b>
         <br>
-        <button class="toggle-vis" data-column="1">ID</button>
-        <button class="toggle-vis" data-column="2">Sample</button>
-        <button class="toggle-vis" data-column="3">Value</button>
         {% if sample_groups[0].se_exists %}
         <button class="toggle-vis" data-column="4,5">SE</button>
         {% if has_num_cases %}
-- 
cgit v1.2.3


From ec1e37331e320ed674f184b738b9917753b6071f Mon Sep 17 00:00:00 2001
From: zsloan
Date: Wed, 16 Dec 2020 15:45:53 -0600
Subject: Made change to the way sample table width is calculated to account
 for sample name width

---
 wqflask/wqflask/show_trait/show_trait.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/wqflask/wqflask/show_trait/show_trait.py b/wqflask/wqflask/show_trait/show_trait.py
index 0c6ae198..4c6dd005 100644
--- a/wqflask/wqflask/show_trait/show_trait.py
+++ b/wqflask/wqflask/show_trait/show_trait.py
@@ -186,8 +186,6 @@ class ShowTrait(object):
 
         self.has_num_cases = has_num_cases(self.this_trait)
 
-        self.stats_table_width, self.trait_table_width = get_table_widths(self.sample_groups, self.has_num_cases)
-
         #ZS: Needed to know whether to display bar chart + get max sample name length in order to set table column width
         self.num_values = 0
         self.binary = "true" #ZS: So it knows whether to display the Binary R/qtl mapping method, which doesn't work unless all values are 0 or 1
@@ -206,6 +204,8 @@ class ShowTrait(object):
 
         sample_column_width = max_samplename_width * 8
 
+        self.stats_table_width, self.trait_table_width = get_table_widths(self.sample_groups, sample_column_width, self.has_num_cases)
+
         if self.num_values >= 5000:
             self.maf = 0.01
         else:
@@ -547,12 +547,12 @@ def get_nearest_marker(this_trait, this_db):
         return result[0][0]
 
 
-def get_table_widths(sample_groups, has_num_cases=False):
+def get_table_widths(sample_groups, sample_column_width, has_num_cases=False):
     stats_table_width = 250
     if len(sample_groups) > 1:
         stats_table_width = 450
 
-    trait_table_width = 380
+    trait_table_width = 300 + sample_column_width
     if sample_groups[0].se_exists:
         trait_table_width += 80
     if has_num_cases:
-- 
cgit v1.2.3


From fbec8e8bb919cb866d70db9f93a942f4554395fb Mon Sep 17 00:00:00 2001
From: zsloan
Date: Wed, 16 Dec 2020 15:53:59 -0600
Subject: Removed unused JS and fixed mapping covariate selection to work for
 both R/qtl and GEMMA

---
 wqflask/wqflask/static/new/javascript/show_trait.js     | 10 +---------
 wqflask/wqflask/templates/show_trait_mapping_tools.html |  8 ++++----
 2 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 98f90f7d..9cd79687 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -100,15 +100,7 @@ d3.select("#select_compare_trait").on("click", (function(_this) {
     return open_trait_selection();
   };
 })(this));
-d3.select("#select_covariates").on("click", (function(_this) {
-  return function() {
-    return open_covariate_selection();
-  };
-})(this));
-$("#remove_covariates").click(function () {
-    $("input[name=covariates]").val("")
-    $(".selected-covariates").val("")
-});
+
 $(".select_covariates").click(function () {
   open_covariate_selection();
 });
diff --git a/wqflask/wqflask/templates/show_trait_mapping_tools.html b/wqflask/wqflask/templates/show_trait_mapping_tools.html
index eca436c6..c42fe4aa 100755
--- a/wqflask/wqflask/templates/show_trait_mapping_tools.html
+++ b/wqflask/wqflask/templates/show_trait_mapping_tools.html
@@ -74,8 +74,8 @@
                               No collections available. Please add traits to a collection to use them as covariates.
                               {% else %}
                               <div class="select-covar-div">
-                                <button type="button" id="select_covariates" class="btn btn-default select-covar-button">Select</button>
-                                <button type="button" id="remove_covariates" class="btn btn-default select-covar-button">Remove</button>
+                                <button type="button" class="btn btn-default select-covar-button select_covariates">Select</button>
+                                <button type="button" class="btn btn-default select-covar-button remove_covariates">Remove</button>
                               </div>
                               <textarea rows="3" cols="50" readonly placeholder="No covariates selected" class="selected-covariates"></textarea>
                               {% endif %}
@@ -317,8 +317,8 @@
                             No collections available. Please add traits to a collection to use them as covariates.
                             {% else %}
                             <div class="select-covar-div">
-                              <button type="button" id="select_covariates" class="btn btn-default select-covar-button">Select</button>
-                              <button type="button" id="remove_covariates" class="btn btn-default select-covar-button">Remove</button>
+                              <button type="button" class="btn btn-default select-covar-button select_covariates">Select</button>
+                              <button type="button" class="btn btn-default select-covar-button remove_covariates">Remove</button>
                             </div>
                             <textarea rows="3" cols="50" readonly placeholder="No covariates selected" class="selected-covariates"></textarea>
                             {% endif %}
-- 
cgit v1.2.3


From d080436fa5640522c45b1d8bb90e9ca20ba06d5d Mon Sep 17 00:00:00 2001
From: Alexander Kabui
Date: Thu, 17 Dec 2020 01:26:47 +0300
Subject: remove  test for parse_gemma_output  and modify run_gemma tests
 (#533)

---
 .../marker_regression/test_gemma_mapping.py        | 32 ++--------------------
 1 file changed, 2 insertions(+), 30 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py
index b8c13ab4..eab6afe6 100644
--- a/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py
+++ b/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py
@@ -5,7 +5,6 @@ from unittest import mock
 from wqflask.marker_regression.gemma_mapping import run_gemma
 from wqflask.marker_regression.gemma_mapping import gen_pheno_txt_file
 from wqflask.marker_regression.gemma_mapping import gen_covariates_file
-from wqflask.marker_regression.gemma_mapping import parse_gemma_output
 from wqflask.marker_regression.gemma_mapping import parse_loco_output
 
 
@@ -69,11 +68,9 @@ class TestGemmaMapping(unittest.TestCase):
         mock_parse_loco.return_value = []
         results = run_gemma(this_trait=trait, this_dataset=dataset, samples=[
         ], vals=[], covariates="", use_loco=True)
-        system_calls = [mock.call('ghc --json -- -debug -g /home/genotype/bimbam/file_geno.txt -p /home/user/data//gn2/trait1_dataset1_name_pheno.txt -a /home/genotype/bimbam/file_snps.txt -gk > /home/user/data//gn2/GP1_K_RRRRRR.json'),
-                        mock.call('ghc --json --input /home/user/data//gn2/GP1_K_RRRRRR.json -- -debug -a /home/genotype/bimbam/file_snps.txt -lmm 2 -g /home/genotype/bimbam/file_geno.txt -p /home/user/data//gn2/trait1_dataset1_name_pheno.txt > /home/user/data//gn2/GP1_GWA_RRRRRR.json')]
-        mock_os.system.assert_has_calls(system_calls)
+        self.assertEqual(mock_os.system.call_count,2)
         mock_gen_pheno_txt.assert_called_once()
-        mock_parse_loco.assert_called_once_with(dataset, "GP1_GWA_RRRRRR")
+        mock_parse_loco.assert_called_once_with(dataset, "GP1_GWA_RRRRRR",True)
         mock_os.path.isfile.assert_called_once_with(
             ('/home/user/imgfile_output.assoc.txt'))
         self.assertEqual(mock_flat_files.call_count, 4)
@@ -138,31 +135,6 @@ class TestGemmaMapping(unittest.TestCase):
             filehandler.write.assert_has_calls([mock.call(
                 '-9\t'), mock.call('-9\t'), mock.call('-9\t'), mock.call('-9\t'), mock.call('\n')])
 
-    @mock.patch("wqflask.marker_regression.gemma_mapping.webqtlConfig.GENERATED_IMAGE_DIR", "/home/user/img/")
-    def test_parse_gemma_output(self):
-        """add test for generating gemma output with obj returned"""
-        file = """X/Y\t gn2\t21\tQ\tE\tA\tP\tMMB\tCDE\t0.5
-X/Y\tgn2\t21322\tQ\tE\tA\tP\tMMB\tCDE\t0.5
-chr\tgn1\t12312\tQ\tE\tA\tP\tMMB\tCDE\t0.7
-X\tgn7\t2324424\tQ\tE\tA\tP\tMMB\tCDE\t0.4
-125\tgn9\t433575\tQ\tE\tA\tP\tMMB\tCDE\t0.67
-"""
-        with mock.patch("builtins.open", mock.mock_open(read_data=file)) as mock_open:
-            results = parse_gemma_output(genofile_name="gema_file")
-            expected = [{'name': ' gn2', 'chr': 'X/Y', 'Mb': 2.1e-05, 'p_value': 0.5, 'lod_score': 0.3010299956639812}, {'name': 'gn2', 'chr': 'X/Y', 'Mb': 0.021322, 'p_value': 0.5, 'lod_score': 0.3010299956639812},
-                        {'name': 'gn7', 'chr': 'X', 'Mb': 2.324424, 'p_value': 0.4, 'lod_score': 0.3979400086720376}, {'name': 'gn9', 'chr': 125, 'Mb': 0.433575, 'p_value': 0.67, 'lod_score': 0.17392519729917352}]
-            mock_open.assert_called_once_with(
-                "/home/user/img/gema_file_output.assoc.txt")
-            self.assertEqual(results, expected)
-
-    @mock.patch("wqflask.marker_regression.gemma_mapping.webqtlConfig.GENERATED_IMAGE_DIR", "/home/user/img")
-    def test_parse_gemma_output_with_empty_return(self):
-        """add tests for parse gemma output where nothing returned"""
-        output_file_results = """chr\t today"""
-        with mock.patch("builtins.open", mock.mock_open(read_data=output_file_results)) as mock_open:
-            results = parse_gemma_output(genofile_name="gema_file")
-            self.assertEqual(results, [])
-
     @mock.patch("wqflask.marker_regression.gemma_mapping.TEMPDIR", "/home/tmp")
     @mock.patch("wqflask.marker_regression.gemma_mapping.os")
     @mock.patch("wqflask.marker_regression.gemma_mapping.json")
-- 
cgit v1.2.3


From e44f149fb6f6ca7d948c95f30faba4f4c2dc2ddd Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 17 Dec 2020 13:47:16 -0600
Subject: Correlation Min Expr and Location filters display depending upon the
 selected target dataset now, instead of the trait's dataset

---
 .../wqflask/static/new/javascript/show_trait.js    | 18 ++++++++++++++++
 .../show_trait_calculate_correlations.html         | 24 ++++++++++++----------
 2 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 9cd79687..e9c7cce1 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -516,6 +516,24 @@ on_corr_method_change = function() {
 };
 $('select[name=corr_type]').change(on_corr_method_change);
 
+on_dataset_change = function() {
+  let dataset_type = $('select[name=corr_dataset] option:selected').data('type');
+
+  if (dataset_type == "mrna_assay"){
+    $('#min_expr_filter').show();
+    $('#location_filter').show();
+  }
+  else if (dataset_type == "pheno"){
+    $('#min_expr_filter').show();
+    $('#location_filter').hide();
+  }
+  else {
+    $('#min_expr_filter').hide();
+    $('#location_filter').show();
+  }
+}
+$('select[name=corr_dataset]').change(on_dataset_change);
+
 submit_special = function(url) {
   get_table_contents_for_form_submit("trait_data_form");
   $("#trait_data_form").attr("action", url);
diff --git a/wqflask/wqflask/templates/show_trait_calculate_correlations.html b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
index ba72ff27..12294efb 100644
--- a/wqflask/wqflask/templates/show_trait_calculate_correlations.html
+++ b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
@@ -19,18 +19,18 @@
                   <select name="corr_dataset" class="form-control">
                       {% for tissue in corr_tools.dataset_menu %}
                           {% if tissue.tissue %}
-                              <optgroup label="{{ tissue.tissue }} ------">
+                            <optgroup label="{{ tissue.tissue }} ------">
                           {% endif %}
                           {% for dataset in tissue.datasets %}
-                              <option value="{{ dataset[1] }}"
-                              {% if corr_tools.dataset_menu_selected == dataset[1] %}
-                                  selected
-                              {% endif %}>
-                                {{ dataset[0] }}
-                              </option>
+                            <option data-type="{% if tissue.tissue %}mrna_assay{% elif dataset[1][-4:] == 'Geno' %}geno{% else %}pheno{% endif %}" value="{{ dataset[1] }}"
+                            {% if corr_tools.dataset_menu_selected == dataset[1] %}
+                                selected
+                            {% endif %}>
+                            {{ dataset[0] }}
+                            </option>
                           {% endfor %}
                           {% if tissue.tissue %}
-                              </optgroup>
+                            </optgroup>
                           {% endif %}
                       {% endfor %}
                   </select>
@@ -74,14 +74,16 @@
                   </select>
               </div>
           </div>
-          {% if dataset.type != "Publish" %}
-          <div class="form-group">
+          {% if dataset.type != "Geno" %}
+          <div id="min_expr_filter" class="form-group">
               <label class="col-xs-2 control-label">Min Expr</label>
               <div class="col-xs-4 controls">
                   <input name="min_expr" value="" type="text" class="form-control min-expr-field">
               </div>
           </div>
-          <div class="form-group">
+          {% endif %}
+          {% if dataset.type != "Pheno" %}
+          <div id="location_filter" class="form-group">
               <label class="col-xs-2 control-label">Location</label>
               <div class="col-xs-6 controls">
                   <span>
-- 
cgit v1.2.3


From 561dfe5e1dedbf9c31d45023b895a2b9bb003869 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 17 Dec 2020 13:51:59 -0600
Subject: Replaced Pheno with Publish for identifying dataset type in corr
 options

---
 wqflask/wqflask/templates/show_trait_calculate_correlations.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/templates/show_trait_calculate_correlations.html b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
index 12294efb..6f124943 100644
--- a/wqflask/wqflask/templates/show_trait_calculate_correlations.html
+++ b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
@@ -82,7 +82,7 @@
               </div>
           </div>
           {% endif %}
-          {% if dataset.type != "Pheno" %}
+          {% if dataset.type != "Publish" %}
           <div id="location_filter" class="form-group">
               <label class="col-xs-2 control-label">Location</label>
               <div class="col-xs-6 controls">
-- 
cgit v1.2.3


From f851ea02b94b98f1537060a7189e25086fc991e9 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 17 Dec 2020 14:48:55 -0600
Subject: Fixed a couple logic issues and changed indentation in
 show_trait_calculate_correlations.html

---
 .../show_trait_calculate_correlations.html         | 154 ++++++++++-----------
 1 file changed, 75 insertions(+), 79 deletions(-)

diff --git a/wqflask/wqflask/templates/show_trait_calculate_correlations.html b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
index 6f124943..eaa0c308 100644
--- a/wqflask/wqflask/templates/show_trait_calculate_correlations.html
+++ b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
@@ -2,88 +2,85 @@
     <div class="col-xs-3 correlation-options">
       <div class="form-horizontal section-form-div">
 
-          <div class="form-group">
-              <label for="corr_type" class="col-xs-2 control-label">Method</label>
-              <div class="col-xs-3 controls">
-                  <select name="corr_type" class="form-control">
-                      <option value="sample">Sample r</option>
-                      <option value="lit">Literature r</option>
-                      <option value="tissue">Tissue r</option>
-                  </select>
-              </div>
-          </div>
+        <div class="form-group">
+            <label for="corr_type" class="col-xs-2 control-label">Method</label>
+            <div class="col-xs-3 controls">
+                <select name="corr_type" class="form-control">
+                    <option value="sample">Sample r</option>
+                    <option value="lit">Literature r</option>
+                    <option value="tissue">Tissue r</option>
+                </select>
+            </div>
+        </div>
 
-          <div class="form-group">
-              <label for="corr_dataset" class="col-xs-2 control-label">Database</label>
-              <div class="col-xs-10 controls">
-                  <select name="corr_dataset" class="form-control">
-                      {% for tissue in corr_tools.dataset_menu %}
-                          {% if tissue.tissue %}
-                            <optgroup label="{{ tissue.tissue }} ------">
-                          {% endif %}
-                          {% for dataset in tissue.datasets %}
-                            <option data-type="{% if tissue.tissue %}mrna_assay{% elif dataset[1][-4:] == 'Geno' %}geno{% else %}pheno{% endif %}" value="{{ dataset[1] }}"
-                            {% if corr_tools.dataset_menu_selected == dataset[1] %}
-                                selected
-                            {% endif %}>
-                            {{ dataset[0] }}
-                            </option>
-                          {% endfor %}
-                          {% if tissue.tissue %}
-                            </optgroup>
-                          {% endif %}
-                      {% endfor %}
-                  </select>
-              </div>
-          </div>
+        <div class="form-group">
+            <label for="corr_dataset" class="col-xs-2 control-label">Database</label>
+            <div class="col-xs-10 controls">
+                <select name="corr_dataset" class="form-control">
+                    {% for tissue in corr_tools.dataset_menu %}
+                        {% if tissue.tissue %}
+                        <optgroup label="{{ tissue.tissue }} ------">
+                        {% endif %}
+                        {% for dataset in tissue.datasets %}
+                        <option data-type="{% if tissue.tissue %}mrna_assay{% elif dataset[1][-4:] == 'Geno' %}geno{% else %}pheno{% endif %}" value="{{ dataset[1] }}"
+                        {% if corr_tools.dataset_menu_selected == dataset[1] %}
+                            selected
+                        {% endif %}>
+                        {{ dataset[0] }}
+                        </option>
+                        {% endfor %}
+                        {% if tissue.tissue %}
+                        </optgroup>
+                        {% endif %}
+                    {% endfor %}
+                </select>
+            </div>
+        </div>
 
-          <div class="form-group">
-              <label for="corr_return_results" class="col-xs-2 control-label">Limit to</label>
-              <div class="col-xs-4 controls">
-                  <select name="corr_return_results" class="form-control">
-                      {% for return_result in corr_tools.return_results_menu %}
-                          <option value="{{ return_result }}"
-                          {% if corr_tools.return_results_menu_selected == return_result %}
-                              selected
-                          {% endif %}>
-                          Top {{ return_result }}
-                          </option>
-                      {% endfor %}
-                  </select>
-              </div>
-          </div>
+        <div class="form-group">
+            <label for="corr_return_results" class="col-xs-2 control-label">Limit to</label>
+            <div class="col-xs-4 controls">
+                <select name="corr_return_results" class="form-control">
+                    {% for return_result in corr_tools.return_results_menu %}
+                        <option value="{{ return_result }}"
+                        {% if corr_tools.return_results_menu_selected == return_result %}
+                            selected
+                        {% endif %}>
+                        Top {{ return_result }}
+                        </option>
+                    {% endfor %}
+                </select>
+            </div>
+        </div>
 
-          <div class="form-group">
-              <label for="corr_samples_group" class="col-xs-2 control-label">Samples</label>
-              <div class="col-xs-4 controls">
-                  <select name="corr_samples_group" class="form-control">
-                      {% for group, pretty_group in sample_group_types.items() %}
-                          <option value="{{ group }}">{{ pretty_group }}</option>
-                      {% endfor %}
-                  </select>
-              </div>
-          </div>
+        <div class="form-group">
+            <label for="corr_samples_group" class="col-xs-2 control-label">Samples</label>
+            <div class="col-xs-4 controls">
+                <select name="corr_samples_group" class="form-control">
+                    {% for group, pretty_group in sample_group_types.items() %}
+                        <option value="{{ group }}">{{ pretty_group }}</option>
+                    {% endfor %}
+                </select>
+            </div>
+        </div>
 
-          <div id="corr_sample_method" class="form-group">
-              <label for="corr_sample_method" class="col-xs-2 control-label">Type</label>
-              <div class="col-xs-4 controls">
-                  <select name="corr_sample_method" class="form-control">
-                      <option value="pearson">Pearson</option>
-                      <option value="spearman">Spearman Rank</option>
-                      <option value="bicor">Biweight Midcorrelation</option>
-                  </select>
-              </div>
-          </div>
-          {% if dataset.type != "Geno" %}
-          <div id="min_expr_filter" class="form-group">
-              <label class="col-xs-2 control-label">Min Expr</label>
-              <div class="col-xs-4 controls">
-                  <input name="min_expr" value="" type="text" class="form-control min-expr-field">
-              </div>
-          </div>
-          {% endif %}
-          {% if dataset.type != "Publish" %}
-          <div id="location_filter" class="form-group">
+        <div id="corr_sample_method" class="form-group">
+            <label for="corr_sample_method" class="col-xs-2 control-label">Type</label>
+            <div class="col-xs-4 controls">
+                <select name="corr_sample_method" class="form-control">
+                    <option value="pearson">Pearson</option>
+                    <option value="spearman">Spearman Rank</option>
+                    <option value="bicor">Biweight Midcorrelation</option>
+                </select>
+            </div>
+        </div>
+        <div id="min_expr_filter" class="form-group" style="display: {% if dataset.type != 'Geno' %}block{% else %}none{% endif %};">
+            <label class="col-xs-2 control-label">Min Expr</label>
+            <div class="col-xs-4 controls">
+                <input name="min_expr" value="" type="text" class="form-control min-expr-field">
+            </div>
+        </div>
+        <div id="location_filter" class="form-group" style="display: {% if dataset.type != 'Publish' %}block{% else %}none{% endif %};">
               <label class="col-xs-2 control-label">Location</label>
               <div class="col-xs-6 controls">
                   <span>
@@ -93,7 +90,6 @@
                   <br>
               </div>
           </div>
-          {% endif %}
           <div class="form-group">
               <label class="col-xs-2 control-label">Range</label>
               <div class="col-xs-5 controls">
-- 
cgit v1.2.3


From be1c1c1c48d75875f03b7ff4e91654f390571b58 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 17 Dec 2020 14:49:26 -0600
Subject: Added Mean (mean expression) column to phenotype correlation results
 table

---
 wqflask/wqflask/templates/correlation_page.html | 26 +++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/wqflask/wqflask/templates/correlation_page.html b/wqflask/wqflask/templates/correlation_page.html
index 8e2a23fd..6188c0e7 100644
--- a/wqflask/wqflask/templates/correlation_page.html
+++ b/wqflask/wqflask/templates/correlation_page.html
@@ -95,14 +95,15 @@
           {% elif target_dataset.type == 'Publish' %}
           <button class="toggle-vis" data-column="3">Abbreviation</button>
           <button class="toggle-vis" data-column="4">Description</button>
-          <button class="toggle-vis" data-column="5">Authors</button>
-          <button class="toggle-vis" data-column="6">Year</button>
-          <button class="toggle-vis" data-column="7">Sample {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}</button>
-          <button class="toggle-vis" data-column="8">N</button>
-          <button class="toggle-vis" data-column="9">Sample p({% if corr_method == 'pearson' %}r{% else %}rho{% endif %})</button>
-          <button class="toggle-vis" data-column="10">Peak LOD</button>
-          <button class="toggle-vis" data-column="11">Peak Location</button>
-          <button class="toggle-vis" data-column="12">Effect Size</button>
+          <button class="toggle-vis" data-column="5">Mean</button>
+          <button class="toggle-vis" data-column="6">Authors</button>
+          <button class="toggle-vis" data-column="7">Year</button>
+          <button class="toggle-vis" data-column="8">Sample {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}</button>
+          <button class="toggle-vis" data-column="9">N</button>
+          <button class="toggle-vis" data-column="10">Sample p({% if corr_method == 'pearson' %}r{% else %}rho{% endif %})</button>
+          <button class="toggle-vis" data-column="11">Peak LOD</button>
+          <button class="toggle-vis" data-column="12">Peak Location</button>
+          <button class="toggle-vis" data-column="13">Effect Size</button>
           {% else %}
           <button class="toggle-vis" data-column="3">Location</button>
           <button class="toggle-vis" data-column="4">Sample {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}</button>
@@ -398,6 +399,13 @@
                         }
                       }
                     },
+                    {
+                      'title': "Mean",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "mean",
+                      'orderSequence': [ "desc", "asc"]
+                    },
                     {
                       'title': "Authors",
                       'type': "natural",
@@ -514,6 +522,8 @@
                 } ],
                 {% if target_dataset.type == 'Geno' %}
                 "order": [[6, "asc" ]],
+                {% elif target_dataset.type == 'Publish' %}
+                "order": [[10, "asc" ]],
                 {% else %}
                 "order": [[9, "asc" ]],
                 {% endif %}
-- 
cgit v1.2.3


From 03de3751bd003117dce2bc4bf085092bd8f9a0fe Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 17 Dec 2020 14:50:34 -0600
Subject: Fixed some logic to work correctly with the changes to the way
 correlation filters work + changed correlation python code to include Mean
 (mean expression) for phenotype results

---
 wqflask/wqflask/correlation/show_corr_results.py | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/wqflask/wqflask/correlation/show_corr_results.py b/wqflask/wqflask/correlation/show_corr_results.py
index 7d3b9b9f..298a3559 100644
--- a/wqflask/wqflask/correlation/show_corr_results.py
+++ b/wqflask/wqflask/correlation/show_corr_results.py
@@ -71,7 +71,6 @@ class CorrelationResults(object):
         assert('corr_sample_method' in start_vars)
         assert('corr_samples_group' in start_vars)
         assert('corr_dataset' in start_vars)
-        #assert('min_expr' in start_vars)
         assert('corr_return_results' in start_vars)
         if 'loc_chr' in start_vars:
             assert('min_loc_mb' in start_vars)
@@ -197,15 +196,15 @@ class CorrelationResults(object):
                 if (float(self.correlation_data[trait][0]) >= self.p_range_lower and
                     float(self.correlation_data[trait][0]) <= self.p_range_upper):
 
-                    if self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Geno":
-
+                    if (self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Publish") and bool(trait_object.mean):
                         if (self.min_expr != None) and (float(trait_object.mean) < self.min_expr):
                             continue
-                        elif range_chr_as_int != None and (chr_as_int != range_chr_as_int):
+                    if self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Geno":
+                        if range_chr_as_int != None and (chr_as_int != range_chr_as_int):
                             continue
-                        elif (self.min_location_mb != None) and (float(trait_object.mb) < float(self.min_location_mb)):
+                        if (self.min_location_mb != None) and (float(trait_object.mb) < float(self.min_location_mb)):
                             continue
-                        elif (self.max_location_mb != None) and (float(trait_object.mb) > float(self.max_location_mb)):
+                        if (self.max_location_mb != None) and (float(trait_object.mb) > float(self.max_location_mb)):
                             continue
 
                     (trait_object.sample_r,
@@ -519,6 +518,7 @@ def generate_corr_json(corr_results, this_trait, dataset, target_dataset, for_ap
         elif target_dataset.type == "Publish":
             results_dict['abbreviation_display'] = "N/A"
             results_dict['description'] = "N/A"
+            results_dict['mean'] = "N/A"
             results_dict['authors_display'] = "N/A"
             results_dict['additive'] = "N/A"
             if for_api:
@@ -532,6 +532,8 @@ def generate_corr_json(corr_results, this_trait, dataset, target_dataset, for_ap
                 results_dict['abbreviation_display'] = trait.abbreviation
             if bool(trait.description_display):
                 results_dict['description'] = trait.description_display
+            if bool(trait.mean):
+                results_dict['mean'] = f"{float(trait.mean):.3f}"
             if bool(trait.authors):
                 authors_list = trait.authors.split(',')
                 if len(authors_list) > 6:
@@ -605,6 +607,7 @@ def get_header_fields(data_type, corr_method):
                             'Record',
                             'Abbreviation',
                             'Description',
+                            'Mean',
                             'Authors',
                             'Year',
                             'Sample rho',
@@ -618,6 +621,7 @@ def get_header_fields(data_type, corr_method):
                             'Record',
                             'Abbreviation',
                             'Description',
+                            'Mean',
                             'Authors',
                             'Year',
                             'Sample r',
-- 
cgit v1.2.3


From 47c15cdbd8d54afca05bf939dec8d7d461cff5a5 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 14:30:13 -0600
Subject: Added function that fetches sample data and converts it to JSON to
 show_trait.js

---
 .../wqflask/static/new/javascript/show_trait.js    | 23 ++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 98f90f7d..b71a9dd8 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -427,6 +427,25 @@ process_id = function() {
   }
   return processed;
 };
+
+fetch_sample_values = function() {
+  // This is meant to fetch all sample values using DataTables API, since they can't all be submitted with the form when using Scroller (and this should also be faster)
+  sample_val_dict = {};
+
+  table = 'samples_primary';
+  if ($('#' + table).length){
+    table_api = $('#' + table).DataTable();
+    val_nodes = table_api.column(3).nodes().to$();
+    for (_j = 0; _j < val_nodes.length; _j++){
+      sample_name = val_nodes[_j].childNodes[0].name.split(":")[1]
+      sample_val = val_nodes[_j].childNodes[0].value
+      sample_val_dict[sample_name] = sample_val
+    }
+  }
+
+  return sample_val_dict;
+}
+
 edit_data_change = function() {
   var already_seen, checkbox, name, real_dict, real_value, real_variance, row, rows, sample_sets, table, tables, _i, _j, _len, _len1;
   already_seen = {};
@@ -525,7 +544,7 @@ on_corr_method_change = function() {
 $('select[name=corr_type]').change(on_corr_method_change);
 
 submit_special = function(url) {
-  get_table_contents_for_form_submit("trait_data_form");
+  $("input[name=sample_vals]").val(JSON.stringify(fetch_sample_values()))
   $("#trait_data_form").attr("action", url);
   $("#trait_data_form").submit();
 };
@@ -549,7 +568,7 @@ get_table_contents_for_form_submit = function(form_id) {
  });
 }
 
-var corr_input_list = ['corr_type', 'primary_samples', 'trait_id', 'dataset', 'group', 'tool_used', 'form_url', 'corr_sample_method', 'corr_samples_group', 'corr_dataset', 'min_expr',
+var corr_input_list = ['sample_vals', 'corr_type', 'primary_samples', 'trait_id', 'dataset', 'group', 'tool_used', 'form_url', 'corr_sample_method', 'corr_samples_group', 'corr_dataset', 'min_expr',
                         'corr_return_results', 'loc_chr', 'min_loc_mb', 'max_loc_mb', 'p_range_lower', 'p_range_upper']
 
 $(".corr_compute").on("click", (function(_this) {
-- 
cgit v1.2.3


From 66b8f70f162f2d6356c6e9af5066c5b90335f7c2 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 14:33:04 -0600
Subject: Changed views.py to accept sample data for loading page and mapping
 as JSON instead of having separate form parameters for each sample + removed
 some commented out code/logging

---
 wqflask/wqflask/views.py | 16 +++++-----------
 1 file changed, 5 insertions(+), 11 deletions(-)

diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 25563e86..c136711e 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -621,12 +621,13 @@ def loading_page():
         wanted = initial_start_vars['wanted_inputs'].split(",")
         start_vars = {}
         for key, value in list(initial_start_vars.items()):
-            if key in wanted or key.startswith(('value:')):
+            if key in wanted:
                 start_vars[key] = value
 
         if 'n_samples' in start_vars:
             n_samples = int(start_vars['n_samples'])
         else:
+            sample_vals_dict = json.loads(start_vars['sample_vals'])
             if 'group' in start_vars:
                 dataset = create_dataset(start_vars['dataset'], group_name = start_vars['group'])
             else:
@@ -642,8 +643,7 @@ def loading_page():
                         samples = genofile_samples
 
             for sample in samples:
-                value = start_vars.get('value:' + sample)
-                if value != "x":
+                if sample_vals_dict[sample] != "x":
                     n_samples += 1
 
         start_vars['n_samples'] = n_samples
@@ -660,7 +660,6 @@ def loading_page():
 @app.route("/run_mapping", methods=('POST',))
 def mapping_results_page():
     initial_start_vars = request.form
-    #logger.debug("Mapping called with initial_start_vars:", initial_start_vars.items())
     logger.info(request.url)
     temp_uuid = initial_start_vars['temp_uuid']
     wanted = (
@@ -670,6 +669,7 @@ def mapping_results_page():
         'species',
         'samples',
         'vals',
+        'sample_vals',
         'first_run',
         'output_files',
         'geno_db_exists',
@@ -723,13 +723,11 @@ def mapping_results_page():
     )
     start_vars = {}
     for key, value in list(initial_start_vars.items()):
-        if key in wanted or key.startswith(('value:')):
+        if key in wanted:
             start_vars[key] = value
-    #logger.debug("Mapping called with start_vars:", start_vars)
 
     version = "v3"
     key = "mapping_results:{}:".format(version) + json.dumps(start_vars, sort_keys=True)
-    #logger.info("key is:", pf(key))
     with Bench("Loading cache"):
         result = None # Just for testing
         #result = Redis.get(key)
@@ -775,10 +773,6 @@ def mapping_results_page():
                     rendered_template = render_template("pair_scan_results.html", **result)
             else:
                 gn1_template_vars = display_mapping_results.DisplayMappingResults(result).__dict__
-                #pickled_result = pickle.dumps(result, pickle.HIGHEST_PROTOCOL)
-                #logger.info("pickled result length:", len(pickled_result))
-                #Redis.set(key, pickled_result)
-                #Redis.expire(key, 1*60)
 
                 with Bench("Rendering template"):
                     #if (gn1_template_vars['mapping_method'] == "gemma") or (gn1_template_vars['mapping_method'] == "plink"):
-- 
cgit v1.2.3


From 20314199985aa21a00a47f3c7b053ec49bc8b60d Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 14:33:44 -0600
Subject: Added sample_vals input element that is meant to contain JSON for all
 sample values (pulled from the sample table using DataTables API in
 show_trait.js)

---
 wqflask/wqflask/templates/show_trait.html | 1 +
 1 file changed, 1 insertion(+)

diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html
index c881eb76..77fc9342 100644
--- a/wqflask/wqflask/templates/show_trait.html
+++ b/wqflask/wqflask/templates/show_trait.html
@@ -35,6 +35,7 @@
         <input type="hidden" name="genofile" value="">
         <input type="hidden" name="covariates" value="">
         <input type="hidden" name="transform" value="">
+        <input type="hidden" name="sample_vals" value="">
 
         <div class="container showtrait-main-div">
             <div class="panel-group" id="accordion">
-- 
cgit v1.2.3


From 969a421efc0bd4529607fdc14332acd897d8e106 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 14:34:21 -0600
Subject: Added sample_vals to the list of mapping inputs that determines what
 is included in start_vars when trait page parameters are passed to the
 mapping loading page

---
 wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js
index 34582f21..3ae52975 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js
@@ -141,7 +141,7 @@ $('input[name=display_all]').change((function(_this) {
 })(this));
 
 //ZS: This is a list of inputs to be passed to the loading page, since not all inputs on the trait page are relevant to mapping
-var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form_url', 'method', 'transform', 'trimmed_markers', 'selected_chr', 'chromosomes', 'mapping_scale',
+var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form_url', 'method', 'transform', 'trimmed_markers', 'selected_chr', 'chromosomes', 'mapping_scale', 'sample_vals',
                           'score_type', 'suggestive', 'significant', 'num_perm', 'permCheck', 'perm_output', 'perm_strata', 'categorical_vars', 'num_bootstrap', 'bootCheck', 'bootstrap_results',
                           'LRSCheck', 'covariates', 'maf', 'use_loco', 'manhattan_plot', 'control_marker', 'control_marker_db', 'do_control', 'genofile', 
                           'pair_scan', 'startMb', 'endMb', 'graphWidth', 'lrsMax', 'additiveCheck', 'showSNP', 'showGenes', 'viewLegend', 'haplotypeAnalystCheck', 
-- 
cgit v1.2.3


From 95d1887bba6b93ea310c226cb82e9cb64f75cc67 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 14:35:09 -0600
Subject: Changed mapping_results.html to have a single sample_vals input
 instead of separate ones for every sample + added sample_vals to the list of
 inputs sent to the loading page

---
 wqflask/wqflask/templates/mapping_results.html | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html
index 1a76ef7a..2fb37832 100644
--- a/wqflask/wqflask/templates/mapping_results.html
+++ b/wqflask/wqflask/templates/mapping_results.html
@@ -31,10 +31,7 @@
         {% endif %}
         <input type="hidden" name="results_path" value="{{ mapping_results_path }}">
         <input type="hidden" name="method" value="{{ mapping_method }}">
-        <input type="hidden" name="samples" value="{{ samples|join(",") }}">
-        {% for sample in samples %}
-        <input type="hidden" name="value:{{ sample }}" value="{{ vals[loop.index - 1] }}">
-        {% endfor %}
+        <input type="hidden" name="sample_vals" value="{{ sample_vals }}">
         <input type="hidden" name="n_samples" value="{{ n_samples }}">
         <input type="hidden" name="maf" value="{{ maf }}">
         <input type="hidden" name="use_loco" value="{{ use_loco }}">
@@ -450,7 +447,7 @@
 
         });
 
-        var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form_url', 'method', 'transform', 'trimmed_markers', 'selected_chr', 'chromosomes', 'mapping_scale',
+        var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form_url', 'method', 'transform', 'trimmed_markers', 'selected_chr', 'chromosomes', 'mapping_scale', 'sample_vals',
                             'score_type', 'suggestive', 'significant', 'num_perm', 'permCheck', 'perm_output', 'perm_strata', 'categorical_vars', 'num_bootstrap', 'bootCheck', 'bootstrap_results',
                             'LRSCheck', 'covariates', 'maf', 'use_loco', 'manhattan_plot', 'color_scheme', 'manhattan_single_color', 'control_marker', 'control_marker_db', 'do_control', 'genofile',
                             'pair_scan', 'startMb', 'endMb', 'graphWidth', 'lrsMax', 'additiveCheck', 'showSNP', 'showGenes', 'viewLegend', 'haplotypeAnalystCheck', 
-- 
cgit v1.2.3


From 7544d03a6d819d70779deb79d38b7465a648c1ff Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 14:36:53 -0600
Subject: Changed run_mapping.py to get sample names and values from JSON
 instead of a bunch of separate input parameters

---
 wqflask/wqflask/marker_regression/run_mapping.py | 64 ++++++------------------
 1 file changed, 15 insertions(+), 49 deletions(-)

diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py
index 891fcc66..a1f87b61 100644
--- a/wqflask/wqflask/marker_regression/run_mapping.py
+++ b/wqflask/wqflask/marker_regression/run_mapping.py
@@ -71,56 +71,22 @@ class RunMapping(object):
         all_samples_ordered = self.dataset.group.all_samples_ordered()
 
         self.vals = []
-        if 'samples' in start_vars:
-            self.samples = start_vars['samples'].split(",")
-            if (len(genofile_samplelist) != 0):
-                for sample in genofile_samplelist:
-                    if sample in self.samples:
-                        value = start_vars.get('value:' + sample)
-                        if value:
-                            self.vals.append(value)
-                    else:
-                        self.vals.append("x")
-            else:
-                for sample in self.samples:
-                    value = start_vars.get('value:' + sample)
-                    if value:
-                        self.vals.append(value)
+        self.samples = []
+        self.sample_vals = start_vars['sample_vals']
+        sample_val_dict = json.loads(self.sample_vals)
+        samples = sample_val_dict.keys()
+        if (len(genofile_samplelist) != 0):
+            for sample in genofile_samplelist:
+                self.samples.append(sample)
+                if sample in samples:
+                    self.vals.append(sample_val_dict[sample])
+                else:
+                    self.vals.append("x")
         else:
-            self.samples = []
-            if (len(genofile_samplelist) != 0):
-                for sample in genofile_samplelist:
-                    if sample in self.dataset.group.samplelist:
-                        in_trait_data = False
-                        for item in self.this_trait.data:
-                            if self.this_trait.data[item].name == sample:
-                                value = start_vars['value:' + self.this_trait.data[item].name]
-                                self.samples.append(self.this_trait.data[item].name)
-                                self.vals.append(value)
-                                in_trait_data = True
-                                break
-                        if not in_trait_data:
-                            value = start_vars.get('value:' + sample)
-                            if value:
-                                self.samples.append(sample)
-                                self.vals.append(value)
-                    else:
-                        self.vals.append("x")
-            else:
-                for sample in self.dataset.group.samplelist: # sample is actually the name of an individual
-                    in_trait_data = False
-                    for item in self.this_trait.data:
-                        if self.this_trait.data[item].name == sample:
-                            value = start_vars['value:' + self.this_trait.data[item].name]
-                            self.samples.append(self.this_trait.data[item].name)
-                            self.vals.append(value)
-                            in_trait_data = True
-                            break
-                    if not in_trait_data:
-                        value = start_vars.get('value:' + sample)
-                        if value:
-                            self.samples.append(sample)
-                            self.vals.append(value)
+            for sample in self.dataset.group.samplelist:
+                if sample in samples:
+                    self.vals.append(sample_val_dict[sample])
+                    self.samples.append(sample)
 
         if 'n_samples' in start_vars:
             self.n_samples = start_vars['n_samples']
-- 
cgit v1.2.3


From 6d493f7ef57322f226dd310497e4dc7518440cfd Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 14:38:09 -0600
Subject: Changed display_mapping_results.py to get sample names and values
 from the JSON sample_vals parameter

---
 .../marker_regression/display_mapping_results.py      | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py
index 08c2d750..9f1b050d 100644
--- a/wqflask/wqflask/marker_regression/display_mapping_results.py
+++ b/wqflask/wqflask/marker_regression/display_mapping_results.py
@@ -270,8 +270,9 @@ class DisplayMappingResults(object):
 
         # Needing for form submission when doing single chr
         # mapping or remapping after changing options
-        self.samples = start_vars['samples']
-        self.vals = start_vars['vals']
+        self.sample_vals = start_vars['sample_vals']
+        self.sample_vals_dict = json.loads(self.sample_vals)
+
         self.transform = start_vars['transform']
         self.mapping_method = start_vars['mapping_method']
         self.mapping_results_path = start_vars['mapping_results_path']
@@ -492,11 +493,10 @@ class DisplayMappingResults(object):
 ## count the amount of individuals to be plotted, and increase self.graphHeight
         if self.haplotypeAnalystChecked and self.selectedChr > -1:
             thisTrait = self.this_trait
-            _strains, _vals, _vars, _aliases = thisTrait.export_informative()
             smd=[]
-            for ii, _val in enumerate(self.vals):
-                if _val != "x":
-                    temp = GeneralObject(name=self.samples[ii], value=float(_val))
+            for sample in self.sample_vals_dict.keys():
+                if self.sample_vals_dict[sample] != "x":
+                    temp = GeneralObject(name=sample, value=float(self.sample_vals_dict[sample]))
                     smd.append(temp)
                 else:
                     continue
@@ -1464,12 +1464,11 @@ class DisplayMappingResults(object):
         yPaddingTop = yTopOffset
 
         thisTrait = self.this_trait
-        _strains, _vals, _vars, _aliases = thisTrait.export_informative()
 
         smd=[]
-        for ii, _val in enumerate(self.vals):
-            if _val != "x":
-                temp = GeneralObject(name=self.samples[ii], value=float(_val))
+        for sample in self.sample_vals_dict.keys():
+            if self.sample_vals_dict[sample] != "x":
+                temp = GeneralObject(name=sample, value=float(self.sample_vals_dict[sample]))
                 smd.append(temp)
             else:
                 continue
-- 
cgit v1.2.3


From 41efd6840f2e1c052dbb77affd6f09fc2e2bcd05 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 14:39:31 -0600
Subject: Changed show_corr_results.py to get sample names/values from the JSON
 sample_vals parameter

---
 wqflask/wqflask/correlation/show_corr_results.py | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/wqflask/wqflask/correlation/show_corr_results.py b/wqflask/wqflask/correlation/show_corr_results.py
index 7d3b9b9f..be983c87 100644
--- a/wqflask/wqflask/correlation/show_corr_results.py
+++ b/wqflask/wqflask/correlation/show_corr_results.py
@@ -87,8 +87,6 @@ class CorrelationResults(object):
             else:
                 helper_functions.get_species_dataset_trait(self, start_vars)
 
-            #self.dataset.group.read_genotype_file()
-
             corr_samples_group = start_vars['corr_samples_group']
 
             self.sample_data = {}
@@ -454,13 +452,13 @@ class CorrelationResults(object):
         if not excluded_samples:
             excluded_samples = ()
 
+        sample_val_dict = json.loads(start_vars['sample_vals'])
         for sample in sample_names:
             if sample not in excluded_samples:
-                # print("Looking for",sample,"in",start_vars)
-                value = start_vars.get('value:' + sample)
-                if value:
-                    if not value.strip().lower() == 'x':
-                        self.sample_data[str(sample)] = float(value)
+                value = sample_val_dict[sample]
+                if not value.strip().lower() == 'x':
+                    self.sample_data[str(sample)] = float(value)
+
 
 def do_bicor(this_trait_vals, target_trait_vals):
     r_library = ro.r["library"]             # Map the library function
-- 
cgit v1.2.3


From 453ac34383d54910e821609b80b69ff41c48d0ce Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 14:53:01 -0600
Subject: Added Additive Effect when using LOCO with GEMMA

---
 wqflask/wqflask/marker_regression/gemma_mapping.py | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/wqflask/wqflask/marker_regression/gemma_mapping.py b/wqflask/wqflask/marker_regression/gemma_mapping.py
index 630a3afa..ab3a7278 100644
--- a/wqflask/wqflask/marker_regression/gemma_mapping.py
+++ b/wqflask/wqflask/marker_regression/gemma_mapping.py
@@ -54,7 +54,7 @@ def run_gemma(this_trait, this_dataset, samples, vals, covariates, use_loco, maf
                                                                                           TEMPDIR,
                                                                                           trait_filename)
           if covariates != "":
-              gemma_command += ' -c %s/%s_covariates.txt -a %s/%s_snps.txt -lmm 2 -maf %s > %s/gn2/%s.json' % (flat_files('mapping'),
+              gemma_command += ' -c %s/%s_covariates.txt -a %s/%s_snps.txt -lmm 9 -maf %s > %s/gn2/%s.json' % (flat_files('mapping'),
                                                                                                                 this_dataset.group.name,
                                                                                                                 flat_files('genotype/bimbam'),
                                                                                                                 genofile_name,
@@ -62,7 +62,7 @@ def run_gemma(this_trait, this_dataset, samples, vals, covariates, use_loco, maf
                                                                                                                 TEMPDIR,
                                                                                                                 gwa_output_filename)
           else:
-              gemma_command += ' -a %s/%s_snps.txt -lmm 2 -maf %s > %s/gn2/%s.json' % (flat_files('genotype/bimbam'),
+              gemma_command += ' -a %s/%s_snps.txt -lmm 9 -maf %s > %s/gn2/%s.json' % (flat_files('genotype/bimbam'),
                                                                                                                genofile_name,
                                                                                                                maf,
                                                                                                                TEMPDIR,
@@ -184,11 +184,8 @@ def parse_loco_output(this_dataset, gwa_output_filename, loco="True"):
                     else:
                         marker['chr'] = line.split("\t")[0]
                     marker['Mb'] = float(line.split("\t")[2]) / 1000000
-                    if loco == "True":
-                        marker['p_value'] = float(line.split("\t")[9])
-                    else:
-                        marker['p_value'] = float(line.split("\t")[10])
-                        marker['additive'] = float(line.split("\t")[7])
+                    marker['p_value'] = float(line.split("\t")[10])
+                    marker['additive'] = float(line.split("\t")[7])
                     if math.isnan(marker['p_value']) or (marker['p_value'] <= 0):
                         marker['lod_score'] = 0
                         #marker['lrs_value'] = 0
-- 
cgit v1.2.3


From 69f92ef2bc10477a80eff96fb7cc83fee11f31e8 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 17:05:55 -0600
Subject: This should fix the Github login error

---
 wqflask/wqflask/user_login.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/user_login.py b/wqflask/wqflask/user_login.py
index f25ebc32..b6266b2a 100644
--- a/wqflask/wqflask/user_login.py
+++ b/wqflask/wqflask/user_login.py
@@ -239,7 +239,7 @@ def github_oauth2():
     }
 
     result = requests.post("https://github.com/login/oauth/access_token", json=data)
-    result_dict = {arr[0]:arr[1] for arr in [tok.split("=") for tok in [token.encode("utf-8") for token in result.text.split("&")]]}
+    result_dict = {arr[0]:arr[1] for arr in [tok.split("=") for tok in result.text.split("&")]}
 
     github_user = get_github_user_details(result_dict["access_token"])
 
-- 
cgit v1.2.3


From fc717c36d334f364bbae8c98f31ddf78e18d64e3 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 18 Dec 2020 17:34:47 -0600
Subject: Added redirect_uri to the ORCID_AUTH_URL since it wasn't working due
 to missing this parameter

---
 wqflask/utility/tools.py      | 2 +-
 wqflask/wqflask/user_login.py | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py
index 68ef0f04..65df59c3 100644
--- a/wqflask/utility/tools.py
+++ b/wqflask/utility/tools.py
@@ -267,7 +267,7 @@ ORCID_CLIENT_SECRET = get_setting('ORCID_CLIENT_SECRET')
 ORCID_AUTH_URL = None
 if ORCID_CLIENT_ID != 'UNKNOWN' and ORCID_CLIENT_SECRET:
     ORCID_AUTH_URL = "https://orcid.org/oauth/authorize?response_type=code&scope=/authenticate&show_login=true&client_id=" + \
-                      ORCID_CLIENT_ID+"&client_secret="+ORCID_CLIENT_SECRET
+                      ORCID_CLIENT_ID+"&client_secret="+ORCID_CLIENT_SECRET + "&redirect_uri=" + GN2_BRANCH_URL + "n/login/orcid_oauth2"
     ORCID_TOKEN_URL = get_setting('ORCID_TOKEN_URL')
 
 ELASTICSEARCH_HOST = get_setting('ELASTICSEARCH_HOST')
diff --git a/wqflask/wqflask/user_login.py b/wqflask/wqflask/user_login.py
index b6266b2a..bc608e84 100644
--- a/wqflask/wqflask/user_login.py
+++ b/wqflask/wqflask/user_login.py
@@ -25,7 +25,7 @@ from utility.logger import getLogger
 logger = getLogger(__name__)
 
 from smtplib import SMTP
-from utility.tools import SMTP_CONNECT, SMTP_USERNAME, SMTP_PASSWORD, LOG_SQL_ALCHEMY
+from utility.tools import SMTP_CONNECT, SMTP_USERNAME, SMTP_PASSWORD, LOG_SQL_ALCHEMY, GN2_BRANCH_URL
 
 THREE_DAYS = 60 * 60 * 24 * 3
 
@@ -277,9 +277,11 @@ def orcid_oauth2():
         data = {
             "client_id": ORCID_CLIENT_ID, 
             "client_secret": ORCID_CLIENT_SECRET, 
-            "grant_type": "authorization_code", 
+            "grant_type": "authorization_code",
+            "redirect_uri": GN2_BRANCH_URL + "n/login/orcid_oauth2",
             "code": code
         }
+
         result = requests.post(ORCID_TOKEN_URL, data=data)
         result_dict = json.loads(result.text.encode("utf-8"))
 
-- 
cgit v1.2.3


From 0560b297a9a6139079ee237bc8d98f471e7703f5 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Fri, 25 Dec 2020 19:18:48 -0600
Subject: Added edit_data_change to block_by_attribute_value so it will update
 stats figures after using that tool

---
 wqflask/wqflask/static/new/javascript/show_trait.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index e9c7cce1..312cc22f 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -641,6 +641,8 @@ block_by_attribute_value = function() {
       this_val_node.value = "x";
     }
   }
+
+  edit_data_change();
 };
 $('#exclude_by_attr').click(block_by_attribute_value);
 
-- 
cgit v1.2.3


From c26304ed6a2937654794f908c13ccd3ba4a66453 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 28 Dec 2020 14:25:51 -0600
Subject: Fix issue that caused error bars to not work for bar chart

---
 wqflask/wqflask/static/new/javascript/show_trait.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 312cc22f..6918cf34 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -448,7 +448,7 @@ edit_data_change = function() {
         if (is_number(sample_val) && sample_val !== "") {
           sample_val = parseFloat(sample_val);
           sample_sets[table].add_value(sample_val);
-          if (typeof var_nodes !== 'undefined'){
+          if (typeof var_nodes === 'undefined'){
             sample_var = null;
           } else {
             sample_var = var_nodes[_j].childNodes[0].value
@@ -471,6 +471,7 @@ edit_data_change = function() {
         }
       }
     }
+
   }
 
   update_stat_values(sample_sets);
-- 
cgit v1.2.3


From 3241a8de759f18bbbc73bd755419831db37e71a0 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 28 Dec 2020 15:01:31 -0600
Subject: Added 'Location Type' option to show_trait correlation options

---
 wqflask/wqflask/templates/show_trait_calculate_correlations.html | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/wqflask/wqflask/templates/show_trait_calculate_correlations.html b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
index eaa0c308..46232b97 100644
--- a/wqflask/wqflask/templates/show_trait_calculate_correlations.html
+++ b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
@@ -80,6 +80,15 @@
                 <input name="min_expr" value="" type="text" class="form-control min-expr-field">
             </div>
         </div>
+        <div class="form-group">
+            <label for="location_type" class="col-xs-2 control-label">Location Type</label>
+            <div class="col-xs-4 controls">
+                <select name="location_type" class="form-control">
+                    {% if dataset.type != 'Publish' %}<option value="gene">Gene</option>{% endif %}
+                    <option value="highest_lod">Highest LOD</option>
+                </select>
+            </div>
+        </div>
         <div id="location_filter" class="form-group" style="display: {% if dataset.type != 'Publish' %}block{% else %}none{% endif %};">
               <label class="col-xs-2 control-label">Location</label>
               <div class="col-xs-6 controls">
-- 
cgit v1.2.3


From ab9aebc567d1a10282ae55f282993a3fa9dd3582 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 28 Dec 2020 15:14:32 -0600
Subject: Changed correlation options to always show the location field and
 both location_type options, since one or the other will always apply

---
 wqflask/wqflask/templates/show_trait_calculate_correlations.html | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/wqflask/wqflask/templates/show_trait_calculate_correlations.html b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
index 46232b97..cba977ac 100644
--- a/wqflask/wqflask/templates/show_trait_calculate_correlations.html
+++ b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
@@ -84,12 +84,12 @@
             <label for="location_type" class="col-xs-2 control-label">Location Type</label>
             <div class="col-xs-4 controls">
                 <select name="location_type" class="form-control">
-                    {% if dataset.type != 'Publish' %}<option value="gene">Gene</option>{% endif %}
+                    <option value="gene" {% if dataset.type == 'Publish' %}disabled{% endif %}>Gene</option>
                     <option value="highest_lod">Highest LOD</option>
                 </select>
             </div>
         </div>
-        <div id="location_filter" class="form-group" style="display: {% if dataset.type != 'Publish' %}block{% else %}none{% endif %};">
+        <div id="location_filter" class="form-group">
               <label class="col-xs-2 control-label">Location</label>
               <div class="col-xs-6 controls">
                   <span>
-- 
cgit v1.2.3


From a336ca94fd473fdfd6cc5a83ce879429c0f1db92 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 28 Dec 2020 15:15:01 -0600
Subject: Added JS controlling which location_type options are available
 depending upon the selected target dataset

---
 wqflask/wqflask/static/new/javascript/show_trait.js | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 6918cf34..a301615b 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -519,21 +519,26 @@ $('select[name=corr_type]').change(on_corr_method_change);
 
 on_dataset_change = function() {
   let dataset_type = $('select[name=corr_dataset] option:selected').data('type');
+  let location_type = $('select[name=location_type] option:selected').val();
 
   if (dataset_type == "mrna_assay"){
     $('#min_expr_filter').show();
-    $('#location_filter').show();
+    $('select[name=location_type] option:disabled').prop('disabled', false)
   }
   else if (dataset_type == "pheno"){
     $('#min_expr_filter').show();
-    $('#location_filter').hide();
+    $('select[name=location_type]>option:eq(0)').prop('disabled', true).attr('selected', false);
+    $('select[name=location_type]>option:eq(1)').prop('disabled', false).attr('selected', true);
   }
   else {
     $('#min_expr_filter').hide();
-    $('#location_filter').show();
+    $('select[name=location_type]>option:eq(0)').prop('disabled', false).attr('selected', true);
+    $('select[name=location_type]>option:eq(1)').prop('disabled', true).attr('selected', false);
   }
 }
+
 $('select[name=corr_dataset]').change(on_dataset_change);
+$('select[name=location_type]').change(on_dataset_change);
 
 submit_special = function(url) {
   get_table_contents_for_form_submit("trait_data_form");
-- 
cgit v1.2.3


From 8dd6f67d37c2d5cc800ee9dc33dd13a566e256fa Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 28 Dec 2020 15:48:50 -0600
Subject: Incorporated location_type into the filtering logic for the
 correlation page

---
 wqflask/wqflask/correlation/show_corr_results.py | 37 +++++++++++++++---------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/wqflask/wqflask/correlation/show_corr_results.py b/wqflask/wqflask/correlation/show_corr_results.py
index 298a3559..6175dc7e 100644
--- a/wqflask/wqflask/correlation/show_corr_results.py
+++ b/wqflask/wqflask/correlation/show_corr_results.py
@@ -101,11 +101,12 @@ class CorrelationResults(object):
                 'min_loc_mb' in start_vars and
                 'max_loc_mb' in start_vars):
 
+                self.location_type = get_string(start_vars, 'location_type')
                 self.location_chr = get_string(start_vars, 'loc_chr')
                 self.min_location_mb = get_int(start_vars, 'min_loc_mb')
                 self.max_location_mb = get_int(start_vars, 'max_loc_mb')
             else:
-                self.location_chr = self.min_location_mb = self.max_location_mb = None
+                self.location_type = self.location_chr = self.min_location_mb = self.max_location_mb = None
 
             self.get_formatted_corr_type()
             self.return_number = int(start_vars['corr_return_results'])
@@ -173,23 +174,25 @@ class CorrelationResults(object):
             self.correlation_data = collections.OrderedDict(sorted(list(self.correlation_data.items()),
                                                                    key=lambda t: -abs(t[1][0])))
 
-            if self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Geno":
-                #ZS: Convert min/max chromosome to an int for the location range option
-                range_chr_as_int = None
-                for order_id, chr_info in list(self.dataset.species.chromosomes.chromosomes.items()):
-                    if 'loc_chr' in start_vars:
-                        if chr_info.name == self.location_chr:
-                            range_chr_as_int = order_id
+
+            #ZS: Convert min/max chromosome to an int for the location range option
+            range_chr_as_int = None
+            for order_id, chr_info in list(self.dataset.species.chromosomes.chromosomes.items()):
+                if 'loc_chr' in start_vars:
+                    if chr_info.name == self.location_chr:
+                        range_chr_as_int = order_id
 
             for _trait_counter, trait in enumerate(list(self.correlation_data.keys())[:self.return_number]):
                 trait_object = create_trait(dataset=self.target_dataset, name=trait, get_qtl_info=True, get_sample_info=False)
                 if not trait_object:
                     continue
 
-                if self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Geno":
-                    #ZS: Convert trait chromosome to an int for the location range option
-                    chr_as_int = 0
-                    for order_id, chr_info in list(self.dataset.species.chromosomes.chromosomes.items()):
+                chr_as_int = 0
+                for order_id, chr_info in list(self.dataset.species.chromosomes.chromosomes.items()):
+                    if self.location_type == "highest_lod":
+                        if chr_info.name == trait_object.locus_chr:
+                            chr_as_int = order_id
+                    else:
                         if chr_info.name == trait_object.chr:
                             chr_as_int = order_id
 
@@ -199,9 +202,15 @@ class CorrelationResults(object):
                     if (self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Publish") and bool(trait_object.mean):
                         if (self.min_expr != None) and (float(trait_object.mean) < self.min_expr):
                             continue
-                    if self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Geno":
-                        if range_chr_as_int != None and (chr_as_int != range_chr_as_int):
+
+                    if range_chr_as_int != None and (chr_as_int != range_chr_as_int):
+                        continue
+                    if self.location_type == "highest_lod":
+                        if (self.min_location_mb != None) and (float(trait_object.locus_mb) < float(self.min_location_mb)):
+                            continue
+                        if (self.max_location_mb != None) and (float(trait_object.locus_mb) > float(self.max_location_mb)):
                             continue
+                    else:
                         if (self.min_location_mb != None) and (float(trait_object.mb) < float(self.min_location_mb)):
                             continue
                         if (self.max_location_mb != None) and (float(trait_object.mb) > float(self.max_location_mb)):
-- 
cgit v1.2.3


From dd2c510ea09ea3169cac3685b299640226d5606a Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Sun, 27 Dec 2020 23:17:36 +0300
Subject: update tests for run gemma

---
 .../wqflask/marker_regression/test_gemma_mapping.py   | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py
index eab6afe6..fe2569b8 100644
--- a/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py
+++ b/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py
@@ -144,21 +144,26 @@ class TestGemmaMapping(unittest.TestCase):
             "files": [["file_name", "user", "~/file1"],
                       ["file_name", "user", "~/file2"]]
         }
-        return_file_1 = """X/Y\t L1\t21\tQ\tE\tA\tP\tMMB\tCDE\t0.5
-X/Y\tL2\t21322\tQ\tE\tA\tP\tMMB\tCDE\t0.5
-chr\tL3\t12312\tQ\tE\tA\tP\tMMB\tCDE\t0.7"""
-        return_file_2 = """chr\tother\t21322\tQ\tE\tA\tP\tMMB\tCDE\t0.5"""
+        return_file="""X/Y\tM1\t28.457155\tQ\tE\tA\tMMB\t23.3\tW\t0.9\t0.85\t
+chr4\tM2\t12\tQ\tE\tMMB\tR\t24\tW\t0.87\t0.5
+Y\tM4\t12\tQ\tE\tMMB\tR\t11.6\tW\t0.21\t0.7
+X\tM5\t12\tQ\tE\tMMB\tR\t21.1\tW\t0.65\t0.6"""
+
+        return_file_2 = """chr\tother\t21322\tQ\tE\tA\tP\tMMB\tCDE\t0.5\t0.4"""
         mock_os.path.isfile.return_value = True
         file_to_write = """{"files":["file_1","file_2"]}"""
         with mock.patch("builtins.open") as mock_open:
 
             handles = (mock.mock_open(read_data="gwas").return_value, mock.mock_open(
-                read_data=return_file_1).return_value, mock.mock_open(read_data=return_file_2).return_value)
+                read_data=return_file).return_value, mock.mock_open(read_data=return_file_2).return_value)
             mock_open.side_effect = handles
             results = parse_loco_output(
                 this_dataset={}, gwa_output_filename=".xw/")
-            expected_results = [{'name': ' L1', 'chr': 'X/Y', 'Mb': 2.1e-05, 'p_value': 0.5, 'lod_score': 0.3010299956639812}, {
-                'name': 'L2', 'chr': 'X/Y', 'Mb': 0.021322, 'p_value': 0.5, 'lod_score': 0.3010299956639812}]
+            expected_results= [
+            {'name': 'M1', 'chr': 'X/Y', 'Mb': 2.8457155e-05, 'p_value': 0.85, 'additive': 23.3, 'lod_score': 0.07058107428570727},
+            {'name': 'M2', 'chr': 4, 'Mb': 1.2e-05, 'p_value': 0.5, 'additive': 24.0, 'lod_score': 0.3010299956639812},
+            {'name': 'M4', 'chr': 'Y', 'Mb': 1.2e-05, 'p_value': 0.7, 'additive': 11.6, 'lod_score': 0.1549019599857432},
+            {'name': 'M5', 'chr': 'X', 'Mb': 1.2e-05, 'p_value': 0.6, 'additive': 21.1, 'lod_score': 0.22184874961635637}]
 
             self.assertEqual(expected_results, results)
 
-- 
cgit v1.2.3


From e7324bf55b7dcfd46f7a2ab52765977fb189c26b Mon Sep 17 00:00:00 2001
From: zsloan
Date: Tue, 29 Dec 2020 13:12:48 -0600
Subject: Added location_type to the list of inputs to correlation page (a list
 of form inputs the correlation page needs is passed with it so it doesn't get
 unrelated form inputs)

---
 wqflask/wqflask/static/new/javascript/show_trait.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index a301615b..83d4f193 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -566,7 +566,7 @@ get_table_contents_for_form_submit = function(form_id) {
 }
 
 var corr_input_list = ['corr_type', 'primary_samples', 'trait_id', 'dataset', 'group', 'tool_used', 'form_url', 'corr_sample_method', 'corr_samples_group', 'corr_dataset', 'min_expr',
-                        'corr_return_results', 'loc_chr', 'min_loc_mb', 'max_loc_mb', 'p_range_lower', 'p_range_upper']
+                        'corr_return_results', 'location_type', 'loc_chr', 'min_loc_mb', 'max_loc_mb', 'p_range_lower', 'p_range_upper']
 
 $(".corr_compute").on("click", (function(_this) {
   return function() {
-- 
cgit v1.2.3


From 1bd2d85624e04966ed20ec84dc6ba2cfda85d794 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Tue, 29 Dec 2020 15:03:22 -0600
Subject: Used a try/catch to deal with situations where there's no SE/var
 column, since apparently var_nodes wasn't undefined, causing the previous
 check to not work

---
 wqflask/wqflask/static/new/javascript/show_trait.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 6918cf34..1025233b 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -448,15 +448,15 @@ edit_data_change = function() {
         if (is_number(sample_val) && sample_val !== "") {
           sample_val = parseFloat(sample_val);
           sample_sets[table].add_value(sample_val);
-          if (typeof var_nodes === 'undefined'){
-            sample_var = null;
-          } else {
+          try {
             sample_var = var_nodes[_j].childNodes[0].value
             if (is_number(sample_var)) {
               sample_var = parseFloat(sample_var)
             } else {
               sample_var = null;
             }
+          } catch {
+            sample_var = null;
           }
           sample_dict = {
             value: sample_val,
-- 
cgit v1.2.3


From 7d8e41cd6d31c51adfedcf7abc0da553dd58762c Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 4 Jan 2021 13:04:55 -0600
Subject: Removed logging line from draw_probability_plot.js

---
 wqflask/wqflask/static/new/javascript/draw_probability_plot.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/wqflask/wqflask/static/new/javascript/draw_probability_plot.js b/wqflask/wqflask/static/new/javascript/draw_probability_plot.js
index 3d756303..1b944d4f 100644
--- a/wqflask/wqflask/static/new/javascript/draw_probability_plot.js
+++ b/wqflask/wqflask/static/new/javascript/draw_probability_plot.js
@@ -118,7 +118,6 @@
           };
         };
         data = [make_data('samples_primary'), make_data('samples_other')];
-        console.log("THE DATA IS:", data);
         d3.select("#prob_plot_container svg").datum(data).call(chart);
         if (js_data.trait_symbol != null) {
             $("#prob_plot_title").html("<h3>" + js_data.trait_symbol + ": " + js_data.trait_id + "</h3>");
-- 
cgit v1.2.3


From 1e8c9e4bbc2f8b2085eaf77f469001660cf3c43d Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 4 Jan 2021 13:12:02 -0600
Subject: Increased the top margin on the trait page Bar Chart, which should
 prevent the chart options from overlapping with the title

---
 wqflask/wqflask/static/new/javascript/show_trait.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 1025233b..66f7b606 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -1302,7 +1302,7 @@ if (js_data.num_values < 256) {
     margin: {
         l: left_margin,
         r: 30,
-        t: 30,
+        t: 100,
         b: bottom_margin
     }
   };
-- 
cgit v1.2.3


From 683381f1c98afa58cc40f1a1f000f5e136c931e3 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 4 Jan 2021 13:15:55 -0600
Subject: Removed Scatterplot Matrix since it isn't working and wasn't really
 used to begin with

---
 wqflask/wqflask/static/new/javascript/show_trait.js  | 18 ------------------
 wqflask/wqflask/templates/show_trait_statistics.html | 16 ----------------
 2 files changed, 34 deletions(-)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 66f7b606..832dd1e4 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -94,25 +94,7 @@ add = function() {
 $('#add_to_collection').click(add);
 sample_lists = js_data.sample_lists;
 sample_group_types = js_data.sample_group_types;
-d3.select("#select_compare_trait").on("click", (function(_this) {
-  return function() {
-    $('.scatter-matrix-container').remove();
-    return open_trait_selection();
-  };
-})(this));
 
-$(".select_covariates").click(function () {
-  open_covariate_selection();
-});
-$(".remove_covariates").click(function () {
-  $("input[name=covariates]").val("")
-  $(".selected-covariates").val("")
-});
-d3.select("#clear_compare_trait").on("click", (function(_this) {
-  return function() {
-    return $('.scatter-matrix-container').remove();
-  };
-})(this));
 open_trait_selection = function() {
   return $('#collections_holder').load('/collections/list?color_by_trait #collections_list', (function(_this) {
     return function() {
diff --git a/wqflask/wqflask/templates/show_trait_statistics.html b/wqflask/wqflask/templates/show_trait_statistics.html
index 4f347d4e..865959b1 100644
--- a/wqflask/wqflask/templates/show_trait_statistics.html
+++ b/wqflask/wqflask/templates/show_trait_statistics.html
@@ -21,9 +21,6 @@
             <li>
                 <a href="#violin_plot_tab" class="violin_plot_tab" data-toggle="tab">Violin Plot</a>
             </li>
-            <li>
-                <a href="#scatterplot_matrix" data-toggle="tab">Scatterplot Matrix</a>
-            </li>
         </ul>
         <div class="tab-content">
             <div class="tab-pane active" id="stats_tab">
@@ -116,19 +113,6 @@
                     <div id="violin_plot"></div>
                 </div>
             </div>
-            <div class="tab-pane" id="scatterplot_matrix">
-                <div class="btn-group scatterplot-btn-div">
-                    <button type="button" class="btn btn-default" id="select_compare_trait">
-                        <i class="icon-th-large"></i> Select Traits
-                    </button>
-                    <button type="button" class="btn btn-default" id="clear_compare_trait">
-                        <i class="icon-trash"></i> Clear
-                    </button>
-                </div>
-                <div id="scatterplot_container">
-                    <div id="comparison_scatterplot" class="qtlcharts"></div>
-                </div>
-            </div>
         </div>
     </div>
     <div id="collections_holder_wrapper" style="display:none;">
-- 
cgit v1.2.3


From 257484870e4d2d0f95ea7175db2fc867154ca07f Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 4 Jan 2021 13:16:38 -0600
Subject: Removed some logging from stats.js

---
 wqflask/wqflask/static/new/javascript/stats.js | 2 --
 1 file changed, 2 deletions(-)

diff --git a/wqflask/wqflask/static/new/javascript/stats.js b/wqflask/wqflask/static/new/javascript/stats.js
index 4df03412..6c443ab3 100644
--- a/wqflask/wqflask/static/new/javascript/stats.js
+++ b/wqflask/wqflask/static/new/javascript/stats.js
@@ -91,8 +91,6 @@ Stats = (function() {
   Stats.prototype.interquartile = function() {
     var iq, length, q1, q3;
     length = this.the_values.length;
-    console.log("in interquartile the_values are:", this.the_values);
-    console.log("length is:", length);
     if (js_data.dataset_type == "ProbeSet" && js_data.data_scale == "linear_positive") {
       q1 = Math.log2(this.the_values[Math.floor(length * .25)]);
       q3 = Math.log2(this.the_values[Math.floor(length * .75)]);
-- 
cgit v1.2.3


From a344835cefaaad5b8a7b96977d3963dc3cb4111e Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 4 Jan 2021 13:45:17 -0600
Subject: Added call to change_buttons to mapping results table (which deals
 with highlighting rows and enabling the Add (to collection) button

Also added a "check_node" paramter to change_buttons since sometimes the checkbox is in the second node instead of the first when it's preceded by blank text
---
 wqflask/wqflask/static/new/javascript/search_results.js |  4 ++--
 wqflask/wqflask/templates/mapping_results.html          | 14 ++++++++++++++
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/wqflask/wqflask/static/new/javascript/search_results.js b/wqflask/wqflask/static/new/javascript/search_results.js
index 9ffef4f8..05dcfda5 100644
--- a/wqflask/wqflask/static/new/javascript/search_results.js
+++ b/wqflask/wqflask/static/new/javascript/search_results.js
@@ -1,4 +1,4 @@
-change_buttons = function() {
+change_buttons = function(check_node = 0) {
   var button, buttons, item, num_checked, text, _i, _j, _k, _l, _len, _len2, _len3, _len4, _results, _results2;
   buttons = ["#add", "#remove"];
 
@@ -6,7 +6,7 @@ change_buttons = function() {
   table_api = $('#trait_table').DataTable();
   check_cells = table_api.column(0).nodes().to$();
   for (let i = 0; i < check_cells.length; i++) {
-    if (check_cells[i].childNodes[0].checked){
+    if (check_cells[i].childNodes[check_node].checked){
       num_checked += 1
     }
   }
diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html
index 1a76ef7a..022e9f6a 100644
--- a/wqflask/wqflask/templates/mapping_results.html
+++ b/wqflask/wqflask/templates/mapping_results.html
@@ -375,6 +375,20 @@
             console.time("Creating table");
             {% if selectedChr == -1 %}
             $('#trait_table').DataTable( {
+                "drawCallback": function( settings ) {
+                  $('#trait_table tr').off().on("click", function(event) {
+                    if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') {
+                      var obj =$(this).find('input');
+                      obj.prop('checked', !obj.is(':checked'));
+                    }
+                    if ($(this).hasClass("selected")){
+                      $(this).removeClass("selected")
+                    } else {
+                      $(this).addClass("selected")
+                    }
+                    change_buttons(check_node=1)
+                  });
+                },
                 "columns": [
                     { "type": "natural", "width": "5%" },
                     { "type": "natural", "width": "8%" },
-- 
cgit v1.2.3


From 5fdcf24585ebff01b36d59d0ce1955cfc90fb482 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 4 Jan 2021 13:53:08 -0600
Subject: Only show Add button and run change_buttons function when genotypes
 are databased

---
 wqflask/wqflask/templates/mapping_results.html | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html
index 022e9f6a..985d542c 100644
--- a/wqflask/wqflask/templates/mapping_results.html
+++ b/wqflask/wqflask/templates/mapping_results.html
@@ -248,7 +248,7 @@
         <button class="btn btn-default" id="select_all"><span class="glyphicon glyphicon-ok"></span> Select All</button>
         <button class="btn btn-default" id="deselect_all"><span class="glyphicon glyphicon-remove"></span> Deselect All</button>
         <button class="btn btn-default" id="invert"><span class="glyphicon glyphicon-resize-vertical"></span> Invert</button>
-        <button class="btn btn-success" id="add" disabled><span class="glyphicon glyphicon-plus-sign"></span> Add</button>
+        {% if geno_db_exists == "True" %}<button class="btn btn-success" id="add" disabled><span class="glyphicon glyphicon-plus-sign"></span> Add</button>{% endif %}
         <br />
         <br />
           <div id="table_container" style="width:{% if 'additive' in trimmed_markers[0] %}600{% else %}550{% endif %}px;">
@@ -386,7 +386,7 @@
                     } else {
                       $(this).addClass("selected")
                     }
-                    change_buttons(check_node=1)
+                    {% if geno_db_exists == "True" %}change_buttons(check_node=1){% endif %}
                   });
                 },
                 "columns": [
-- 
cgit v1.2.3


From 468ab300c1447af0ac0eb3fdf12d6b6676f4a60f Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 4 Jan 2021 13:54:55 -0600
Subject: Removed logging line from init_genome_browser.js

---
 wqflask/wqflask/static/new/javascript/init_genome_browser.js | 2 --
 1 file changed, 2 deletions(-)

diff --git a/wqflask/wqflask/static/new/javascript/init_genome_browser.js b/wqflask/wqflask/static/new/javascript/init_genome_browser.js
index 2552fb04..508f5bf2 100644
--- a/wqflask/wqflask/static/new/javascript/init_genome_browser.js
+++ b/wqflask/wqflask/static/new/javascript/init_genome_browser.js
@@ -1,5 +1,3 @@
-console.log("THE FILES:", js_data.browser_files)
-
 snps_filename = "/browser_input?filename=" + js_data.browser_files[0]
 annot_filename = "/browser_input?filename=" + js_data.browser_files[1]
 
-- 
cgit v1.2.3


From 7032f7b05deac0bbd2e868ffd3fe42dd1c97fb7d Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Tue, 5 Jan 2021 13:14:08 -0600
Subject: add server side class unit tests

---
 wqflask/tests/unit/wqflask/test_server_side.py | 31 ++++++++++++++++++++++++++
 wqflask/wqflask/server_side.py                 | 16 ++++++-------
 2 files changed, 39 insertions(+), 8 deletions(-)
 create mode 100644 wqflask/tests/unit/wqflask/test_server_side.py

diff --git a/wqflask/tests/unit/wqflask/test_server_side.py b/wqflask/tests/unit/wqflask/test_server_side.py
new file mode 100644
index 00000000..4f91d8ca
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/test_server_side.py
@@ -0,0 +1,31 @@
+import unittest
+
+from wqflask.server_side import ServerSideTable
+
+
+class TestServerSideTableTests(unittest.TestCase):
+    """
+    Test the ServerSideTable class
+
+    test table:
+        first, second, third
+        'd', 4, 'zz'
+        'b', 2, 'aa'
+        'c', 1, 'ss'
+    """
+
+    def test_get_page(self):
+        rows_count = 3
+        table_rows = [
+            {'first': 'd', 'second': 4, 'third': 'zz'}, 
+            {'first': 'b', 'second': 2, 'third': 'aa'}, 
+            {'first': 'c', 'second': 1, 'third': 'ss'},
+        ]
+        headers = ['first', 'second', 'third']
+        request_args = {'sEcho': '1', 'iSortCol_0': '1', 'iSortingCols': '1', 'sSortDir_0': 'asc', 'iDisplayStart': '0', 'iDisplayLength': '3'}
+
+        test_page = ServerSideTable(rows_count, table_rows, headers, request_args).get_page()
+        self.assertEqual(test_page['sEcho'], '1')
+        self.assertEqual(test_page['iTotalRecords'], 'nan')
+        self.assertEqual(test_page['iTotalDisplayRecords'], '3')
+        self.assertEqual(test_page['data'], [{'first': 'b', 'second': 2, 'third': 'aa'}, {'first': 'c', 'second': 1, 'third': 'ss'}, {'first': 'd', 'second': 4, 'third': 'zz'}])
diff --git a/wqflask/wqflask/server_side.py b/wqflask/wqflask/server_side.py
index 824b00aa..5f764767 100644
--- a/wqflask/wqflask/server_side.py
+++ b/wqflask/wqflask/server_side.py
@@ -3,7 +3,7 @@
 
 
 class ServerSideTable(object):
-    '''
+    """
         This class is used to do server-side processing
         on the DataTables table such as paginating, sorting,
         filtering(not implemented) etc. This takes the load off
@@ -22,7 +22,7 @@ class ServerSideTable(object):
 
         Have a look at snp_browser_table() function in 
         wqflask/wqflask/views.py for reference use.
-    '''
+    """
 
     def __init__(self, rows_count, table_rows, header_data_names, request_values):
         self.request_values = request_values
@@ -36,12 +36,12 @@ class ServerSideTable(object):
         self.paginate_rows()
 
     def sort_rows(self):
-        '''
+        """
         Sorts the rows taking in to account the column (or columns) that the
         user has selected.
-        '''
+        """
         def is_reverse(str_direction):
-            ''' Maps the 'desc' and 'asc' words to True or False. '''
+            """ Maps the 'desc' and 'asc' words to True or False. """
             return True if str_direction == 'desc' else False
 
         if (self.request_values['iSortCol_0'] != "") and (int(self.request_values['iSortingCols']) > 0):
@@ -54,12 +54,12 @@ class ServerSideTable(object):
                               reverse=is_reverse(sort_direction))
 
     def paginate_rows(self):
-        '''
+        """
         Selects a subset of the filtered and sorted data based on if the table
         has pagination, the current page and the size of each page.
-        '''
+        """
         def requires_pagination():
-            ''' Check if the table is going to be paginated '''
+            """ Check if the table is going to be paginated """
             if self.request_values['iDisplayStart'] != "":
                 if int(self.request_values['iDisplayLength']) != -1:
                     return True
-- 
cgit v1.2.3


From 0ef495b69d99c53e7a6a216e6748898dbcc79eec Mon Sep 17 00:00:00 2001
From: zsloan
Date: Tue, 5 Jan 2021 15:24:10 -0600
Subject: Fixed issue where normalization method wasn't removed from stats
 figure axis titles when table values are reset

---
 wqflask/wqflask/static/new/javascript/show_trait.js | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 832dd1e4..765f2f2d 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -207,6 +207,8 @@ update_histogram = function() {
 
   if ($('input[name="transform"]').val() != ""){
     root.histogram_layout['xaxis']['title'] = "<b>" + js_data.unit_type +  " (" + $('input[name="transform"]').val() + ")</b>"
+  } else {
+    root.histogram_layout['xaxis']['title'] = "<b>" + js_data.unit_type + "</b>"
   }
 
   Plotly.newPlot('histogram', root.histogram_data, root.histogram_layout, root.modebar_options);
@@ -255,6 +257,8 @@ update_bar_chart = function() {
 
   if ($('input[name="transform"]').val() != ""){
     root.bar_layout['yaxis']['title'] = "<b>" + js_data.unit_type +  " (" + $('input[name="transform"]').val() + ")</b>"
+  } else {
+    root.bar_layout['yaxis']['title'] = "<b>" + js_data.unit_type + "</b>"
   }
 
   root.bar_data[0]['y'] = trait_vals
@@ -296,6 +300,8 @@ update_box_plot = function() {
 
   if ($('input[name="transform"]').val() != ""){
     root.box_layout['yaxis']['title'] = "<b>" + js_data.unit_type +  " (" + $('input[name="transform"]').val() + ")</b>"
+  } else {
+    root.box_layout['yaxis']['title'] = "<b>" + js_data.unit_type + "</b>"
   }
 
   Plotly.newPlot('box_plot', root.box_data, root.box_layout, root.modebar_options)
@@ -327,6 +333,8 @@ update_violin_plot = function() {
 
   if ($('input[name="transform"]').val() != ""){
     root.violin_layout['yaxis']['title'] = "<b>" + js_data.unit_type +  " (" + $('input[name="transform"]').val() + ")</b>"
+  } else {
+    root.violin_layout['yaxis']['title'] = "<b>" + js_data.unit_type + "</b>"
   }
 
   Plotly.newPlot('violin_plot', root.violin_data, root.violin_layout, root.modebar_options)
@@ -795,6 +803,7 @@ reset_samples_table = function() {
 };
 $('.reset').click(function() {
   reset_samples_table();
+  $('input[name="transform"]').val("");
   edit_data_change();
 });
 
-- 
cgit v1.2.3


From 2bd74f8f4e4e72a11c77d4f3e8532c303503ca11 Mon Sep 17 00:00:00 2001
From: Alexanderlacuna
Date: Mon, 16 Nov 2020 13:46:57 +0300
Subject: add unit tests for api/mapping.py

---
 wqflask/tests/unit/wqflask/api/test_mapping.py | 114 +++++++++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 wqflask/tests/unit/wqflask/api/test_mapping.py

diff --git a/wqflask/tests/unit/wqflask/api/test_mapping.py b/wqflask/tests/unit/wqflask/api/test_mapping.py
new file mode 100644
index 00000000..87b18e84
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/api/test_mapping.py
@@ -0,0 +1,114 @@
+import unittest
+from unittest import mock
+from wqflask.api.mapping import initialize_parameters
+
+
+class AttributeSetter:
+	def __init__(self,obj):
+		for key,value in obj.items():
+			setattr(self,key,value)
+
+class MockGroup(AttributeSetter):
+	def get_marker(self):
+		return None
+class TestMock(unittest.TestCase):
+	
+ #    @mock.patch("wqflask.api.mapping.gemma_mapping")
+ #    @mock.patch("wqflask.api.mapping.nitialize_parameters")
+ #    @mock.patch("wqflask.api.mapping.retrieve_sample_data")
+ #    @mock.patch("wqflask.api.mapping.create_trait")
+ #    @mock.patch("wqflask.api.mapping.data_set")
+	# def test_do_mapping_for_api(self,mock_dataset,mock_create_trait,mock_retrieve_data,mock_gemma):
+
+		# start_vars={
+		# "db":"sql_uri/db_web1",
+		# "trait_id":"idsui332rh3ui2t",
+		# "limit_to":32.1,
+		# }
+		# group_samplelist=["S1","S2","S3","S4"]
+		# dataset_group=MockGroup({"samplelist":group_samplelist})
+		# dataset=AttributeSetter({"type":"Temp","group":dataset_group})
+
+		# this_trait_data={
+		#   "Item1":AttributeSetter({
+		#     "name":"S1",
+		#     "value":"V1"
+		#   }),
+
+		#   "Item2":AttributeSetter({
+		#     "name":"S2",
+		#     "value":"V2"
+		#   }),
+
+		#   "Item3":AttributeSetter({
+		#     "name":"SX",
+		#     "value":"VX"
+		#   })
+		# }
+
+		# this_trait=AttributeSetter({"data":this_trait_data})
+
+
+		# mock_dataset.create_dataset.return_value=dataset
+
+		# mock_create_trait.return_value=this_trait
+		# mock_retrieve_data.return_value=this_trait
+
+		# mock_initialize_params={
+		#  "format":"json",
+		#   "limit_to":32.1,
+		#   "mapping_method":"gemma",
+		#   "maf":0.01,
+		#   "use_loco":True,
+		#   "num_perm":0,
+		#   "perm_check":False
+
+		# }
+
+		# mock_gemma.return_value=[ ,"filename"]
+		# pass
+
+	def test_initialize_parameters(self):
+		expected_results={
+		 "format":"json",
+		 "limit_to":False,
+		 "mapping_method":"gemma",
+		 "maf":0.01,
+		 "use_loco":True,
+		 "num_perm":0,
+		 "perm_check":False
+		}
+
+		results=initialize_parameters(start_vars={},dataset={},this_trait={})
+		self.assertEqual(results,expected_results)
+
+		start_vars={
+		"format":"F1",
+		"limit_to":"1",
+		"mapping_method":"rqtl",
+		"control_marker":True,
+		"pair_scan":"true",
+		"interval_mapping":"true",
+		"use_loco":"true",
+		"num_perm":"14"
+
+		}
+
+		results_2=initialize_parameters(start_vars=start_vars,dataset={},this_trait={})
+		expected_results={
+		"format":"F1",
+		"limit_to":1,
+		"mapping_method":"gemma",
+		"maf":0.01,
+		"use_loco":True,
+		"num_perm":14,
+		"perm_check":"ON"
+		}
+
+		self.assertEqual(results_2,expected_results)
+		
+
+
+
+
+
-- 
cgit v1.2.3


From df2c3f9ee43dd055f7766eedee32d76090ad80b2 Mon Sep 17 00:00:00 2001
From: Alexanderlacuna
Date: Mon, 16 Nov 2020 13:47:40 +0300
Subject: add unit testsfor api/correlation.py

---
 wqflask/tests/unit/wqflask/api/test_correlation.py | 83 ++++++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 wqflask/tests/unit/wqflask/api/test_correlation.py

diff --git a/wqflask/tests/unit/wqflask/api/test_correlation.py b/wqflask/tests/unit/wqflask/api/test_correlation.py
new file mode 100644
index 00000000..482dec67
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/api/test_correlation.py
@@ -0,0 +1,83 @@
+import unittest
+from unittest import mock
+from wqflask import app
+from wqflask.api.correlation import init_corr_params
+from wqflask.api.correlation import convert_to_mouse_gene_id
+from wqflask.api.correlation import do_literature_correlation_for_all_traits
+
+
+class AttributeSetter:
+    def __init__(self, obj):
+        for k, v in obj.items():
+            setattr(self, k, v)
+
+
+class TestCorrelations(unittest.TestCase):
+    def setUp(self):
+        self.app_context = app.app_context()
+        self.app_context.push()
+
+    def tearDown(self):
+        self.app_context.pop()
+
+    def test_init_corr_params(self):
+        start_vars = {
+            "return_count": "3",
+            "type": "T1",
+            "method": "spearman"
+        }
+
+        corr_params_results = init_corr_params(start_vars=start_vars)
+        expected_results = {
+            "return_count": 3,
+            "type": "T1",
+            "method": "spearman"
+        }
+
+        self.assertEqual(corr_params_results, expected_results)
+
+    @mock.patch("wqflask.api.correlation.g")
+    def test_convert_to_mouse_gene_id(self, mock_db):
+
+        results = convert_to_mouse_gene_id(species="Other", gene_id="")
+        self.assertEqual(results, None)
+
+        rat_species_results = convert_to_mouse_gene_id(
+            species="rat", gene_id="GH1")
+
+        mock_db.db.execute.return_value.fetchone.side_effect = [AttributeSetter({"mouse": "MG-1"}),AttributeSetter({"mouse":"MG-2"})]
+                                          
+        self.assertEqual(convert_to_mouse_gene_id(
+            species="mouse", gene_id="MG-4"), "MG-4")
+        self.assertEqual(convert_to_mouse_gene_id(
+            species="rat", gene_id="R1"), "MG-1")
+        self.assertEqual(convert_to_mouse_gene_id(
+            species="human", gene_id="H1"), "MG-2")
+
+    
+    
+    @mock.patch("wqflask.api.correlation.g")
+    @mock.patch("wqflask.api.correlation.convert_to_mouse_gene_id")
+    def test_do_literature_correlation_for_all_traits(self,mock_convert_to_mouse_geneid,mock_db):
+    	mock_convert_to_mouse_geneid.side_effect=["MG-1","MG-2;","MG-3","MG-4"]
+   
+
+    	trait_geneid_dict={
+    	 "TT-1":"GH-1",
+    	 "TT-2":"GH-2",
+    	 "TT-3":"GH-3"
+
+    	}
+    	mock_db.db.execute.return_value.fetchone.side_effect=[AttributeSetter({"value":"V1"}),AttributeSetter({"value":"V2"}),AttributeSetter({"value":"V3"})]
+
+
+    	this_trait=AttributeSetter({"geneid":"GH-1"})
+
+    	target_dataset=AttributeSetter({"group":AttributeSetter({"species":"rat"})})
+    	results=do_literature_correlation_for_all_traits(this_trait=this_trait,target_dataset=target_dataset,trait_geneid_dict=trait_geneid_dict,corr_params={})
+
+    	expected_results={'TT-1': ['GH-1', 0], 'TT-2': ['GH-2', 'V1'], 'TT-3': ['GH-3', 'V2']}
+    	self.assertEqual(results,expected_results)
+
+
+
-- 
cgit v1.2.3


From 3eda2b13e10937cbd661d6d411286c5b84bcd7cf Mon Sep 17 00:00:00 2001
From: Alexanderlacuna
Date: Sat, 28 Nov 2020 15:00:00 +0300
Subject: add correlation test

---
 .../correlation/test_correlation_functions.py      | 21 +++++
 .../wqflask/correlation/test_show_corr_results.py  | 95 ++++++++++++++++++++++
 2 files changed, 116 insertions(+)
 create mode 100644 wqflask/tests/unit/wqflask/correlation/test_correlation_functions.py
 create mode 100644 wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py

diff --git a/wqflask/tests/unit/wqflask/correlation/test_correlation_functions.py b/wqflask/tests/unit/wqflask/correlation/test_correlation_functions.py
new file mode 100644
index 00000000..db449eb1
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/correlation/test_correlation_functions.py
@@ -0,0 +1,21 @@
+import unittest
+from unittest import mock
+from wqflask.correlation.correlation_functions import get_trait_symbol_and_tissue_values
+from wqflask.correlation.correlation_functions import cal_zero_order_corr_for_tiss
+
+
+class TestCorrelationFunctions(unittest.TestCase):
+
+
+    @mock.patch("wqflask.correlation.correlation_functions.MrnaAssayTissueData")
+    def test_get_trait_symbol_and_tissue_values(self, mock_class):
+        """test for getting trait symbol and tissue_values"""
+        mock_class_instance = mock_class.return_value
+        mock_class_instance.gene_symbols = ["k1", "k2", "k3"]
+        mock_class_instance.get_symbol_values_pairs.return_value = {
+            "k1": ["v1", "v2", "v3"], "k2": ["v2", "v3"], "k3": ["k3"]}
+        results = get_trait_symbol_and_tissue_values(
+            symbol_list=["k1", "k2", "k3"])
+        mock_class.assert_called_with(gene_symbols=['k1', 'k2', 'k3'])
+        self.assertEqual({"k1": ["v1", "v2", "v3"], "k2": [
+                         "v2", "v3"], "k3": ["k3"]}, results)
diff --git a/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py b/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
new file mode 100644
index 00000000..4e63207e
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
@@ -0,0 +1,95 @@
+import unittest
+from unittest import mock
+from wqflask.correlation.show_corr_results import get_header_fields
+from wqflask.correlation.show_corr_results import generate_corr_json
+from wqflask.correlation.show_corr_results import do_bicor
+
+
+class Trait:
+	def __init__(self,trait_obj):
+		for key,value in trait_obj.items():
+			setattr(self,key,value)
+
+class TestShowCorrResults(unittest.TestCase):
+
+	def test_process_samples(self):
+		pass
+	def test_get_header_fields(self):
+		expected=[
+		                    ['Index',
+                                'Record',
+                                'Symbol',
+                                'Description',
+                                'Location',
+                                'Mean',
+                                'Sample rho',
+                                'N',
+                                'Sample p(rho)',
+                                'Lit rho',
+                                'Tissue rho',
+                                'Tissue p(rho)',
+                                'Max LRS',
+                                'Max LRS Location',
+                                'Additive Effect'],
+
+                            ['Index',
+                                 'ID',
+                                 'Location',
+                                 'Sample r',
+                                 'N',
+                                 'Sample p(r)']
+
+		]
+		result1=get_header_fields("ProbeSet","spearman")
+		result2=get_header_fields("Other","Other")
+		self.assertEqual(result1,expected[0])
+		self.assertEqual(result2,expected[1])
+
+
+
+
+	def test_generate_corr_json(self):
+		this_trait=Trait({"name":"trait_test"})
+		dataset=Trait({"name":"the_name"})
+		target_dataset=Trait({"type":"Publish"})
+	
+		trait_with_publish={
+		"description_display":"Trait 2 description",
+		"authors":"trait_2 ",
+		"pubmed_id":"34n4nn31hn43",
+		"lrs_location":"N/A",
+		"additive":"",
+		"sample_r":100,
+		"num_overlap":3.2,
+		"view":True,
+		"name":"trait_1",
+		"pubmed_text":"2016",
+		"additive":"",
+		"sample_r":10.5,
+		"LRS_score_repr":"N/A",
+		"LRS_location_repr":"N/A",
+		"sample_p":5,
+		"num_overlap":"num_1"
+
+
+
+		}
+		expected_results="""[{"trait_id": "trait_1", "description": "Trait 2 description", "authors": "trait_2 ", "pubmed_id": "34n4nn31hn43", "year": "2016", "lrs_score": "N/A", "lrs_location": "N/A", "additive": "N/A", "sample_r": "10.500", "num_overlap": "num_1", "sample_p": "5.000e+00"}]"""
+
+		corr_results=[Trait(trait_with_publish)]
+		results=generate_corr_json(corr_results=corr_results,this_trait=this_trait,dataset=dataset,target_dataset=target_dataset,for_api=True)
+		self.assertEqual(results,expected_results)
+		
+		
+
+	def test_generate_corr_json_view_false(self):
+		trait=Trait({"view":False})
+		corr_results=[trait]
+		this_trait=Trait({"name":"trait_test"})
+		dataset=Trait({"name":"the_name"})
+		
+
+		results_where_view_is_false=generate_corr_json(corr_results=corr_results,this_trait=this_trait,dataset={},target_dataset={},for_api=False)
+
+		# self.assertEqual(results,[])
+		self.assertEqual(results_where_view_is_false,"[]")
\ No newline at end of file
-- 
cgit v1.2.3


From 1666f8d50df090e9a14dbf0f4f195bac079de058 Mon Sep 17 00:00:00 2001
From: Alexanderlacuna
Date: Sat, 28 Nov 2020 15:11:06 +0300
Subject: add test in   api/mapping

---
 wqflask/tests/unit/wqflask/api/test_mapping.py | 55 --------------------------
 1 file changed, 55 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/api/test_mapping.py b/wqflask/tests/unit/wqflask/api/test_mapping.py
index 87b18e84..4da1725f 100644
--- a/wqflask/tests/unit/wqflask/api/test_mapping.py
+++ b/wqflask/tests/unit/wqflask/api/test_mapping.py
@@ -13,61 +13,6 @@ class MockGroup(AttributeSetter):
 		return None
 class TestMock(unittest.TestCase):
 	
- #    @mock.patch("wqflask.api.mapping.gemma_mapping")
- #    @mock.patch("wqflask.api.mapping.nitialize_parameters")
- #    @mock.patch("wqflask.api.mapping.retrieve_sample_data")
- #    @mock.patch("wqflask.api.mapping.create_trait")
- #    @mock.patch("wqflask.api.mapping.data_set")
-	# def test_do_mapping_for_api(self,mock_dataset,mock_create_trait,mock_retrieve_data,mock_gemma):
-
-		# start_vars={
-		# "db":"sql_uri/db_web1",
-		# "trait_id":"idsui332rh3ui2t",
-		# "limit_to":32.1,
-		# }
-		# group_samplelist=["S1","S2","S3","S4"]
-		# dataset_group=MockGroup({"samplelist":group_samplelist})
-		# dataset=AttributeSetter({"type":"Temp","group":dataset_group})
-
-		# this_trait_data={
-		#   "Item1":AttributeSetter({
-		#     "name":"S1",
-		#     "value":"V1"
-		#   }),
-
-		#   "Item2":AttributeSetter({
-		#     "name":"S2",
-		#     "value":"V2"
-		#   }),
-
-		#   "Item3":AttributeSetter({
-		#     "name":"SX",
-		#     "value":"VX"
-		#   })
-		# }
-
-		# this_trait=AttributeSetter({"data":this_trait_data})
-
-
-		# mock_dataset.create_dataset.return_value=dataset
-
-		# mock_create_trait.return_value=this_trait
-		# mock_retrieve_data.return_value=this_trait
-
-		# mock_initialize_params={
-		#  "format":"json",
-		#   "limit_to":32.1,
-		#   "mapping_method":"gemma",
-		#   "maf":0.01,
-		#   "use_loco":True,
-		#   "num_perm":0,
-		#   "perm_check":False
-
-		# }
-
-		# mock_gemma.return_value=[ ,"filename"]
-		# pass
-
 	def test_initialize_parameters(self):
 		expected_results={
 		 "format":"json",
-- 
cgit v1.2.3


From 7b1d35701c283973ab63db3b665951f569a8c5fc Mon Sep 17 00:00:00 2001
From: Alexander Kabui
Date: Sun, 29 Nov 2020 17:30:43 +0300
Subject: refactor code in correlation/correlation_functions

---
 .../wqflask/correlation/correlation_functions.py   | 28 ----------------------
 1 file changed, 28 deletions(-)

diff --git a/wqflask/wqflask/correlation/correlation_functions.py b/wqflask/wqflask/correlation/correlation_functions.py
index b883e361..fd7691d4 100644
--- a/wqflask/wqflask/correlation/correlation_functions.py
+++ b/wqflask/wqflask/correlation/correlation_functions.py
@@ -71,34 +71,6 @@ def cal_zero_order_corr_for_tiss (primaryValue=[], targetValue=[], method='pears
     return corr_result
 
 
-###########################################################################
-#Input: cursor, symbolList (list), dataIdDict(Dict)
-#output: symbolValuepairDict (dictionary):one dictionary of Symbol and Value Pair,
-#        key is symbol, value is one list of expression values of one probeSet;
-#function: get one dictionary whose key is gene symbol and value is tissue expression data (list type).
-#Attention! All keys are lower case!
-###########################################################################
-def get_symbol_value_pairs(tissue_data):
-    id_list = [tissue_data[symbol.lower()].data_id for item in tissue_data]
-
-    symbol_value_pairs = {}
-    value_list=[]
-
-    query = """SELECT value, id
-               FROM TissueProbeSetData
-               WHERE Id IN {}""".format(create_in_clause(id_list))
-
-    try :
-        results = g.db.execute(query).fetchall()
-        for result in results:
-            value_list.append(result.value)
-        symbol_value_pairs[symbol] = value_list
-    except:
-        symbol_value_pairs[symbol] = None
-
-    return symbol_value_pairs
-
-
 ########################################################################################################
 #input: cursor, symbolList (list), dataIdDict(Dict): key is symbol
 #output: SymbolValuePairDict(dictionary):one dictionary of Symbol and Value Pair.
-- 
cgit v1.2.3


From e535eeeff92bcfa6d6524e44591164de72d38482 Mon Sep 17 00:00:00 2001
From: Alexander Kabui
Date: Fri, 4 Dec 2020 18:43:35 +0300
Subject: add test for map_api in api/test_mapping.py

---
 wqflask/tests/unit/wqflask/api/test_mapping.py | 145 +++++++++++++++++--------
 1 file changed, 99 insertions(+), 46 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/api/test_mapping.py b/wqflask/tests/unit/wqflask/api/test_mapping.py
index 4da1725f..5455b215 100644
--- a/wqflask/tests/unit/wqflask/api/test_mapping.py
+++ b/wqflask/tests/unit/wqflask/api/test_mapping.py
@@ -1,57 +1,110 @@
 import unittest
 from unittest import mock
 from wqflask.api.mapping import initialize_parameters
+from wqflask.api.mapping import do_mapping_for_api
 
 
 class AttributeSetter:
-	def __init__(self,obj):
-		for key,value in obj.items():
-			setattr(self,key,value)
+    def __init__(self,obj):
+        for key,value in obj.items():
+            setattr(self,key,value)
 
 class MockGroup(AttributeSetter):
-	def get_marker(self):
-		return None
-class TestMock(unittest.TestCase):
-	
-	def test_initialize_parameters(self):
-		expected_results={
-		 "format":"json",
-		 "limit_to":False,
-		 "mapping_method":"gemma",
-		 "maf":0.01,
-		 "use_loco":True,
-		 "num_perm":0,
-		 "perm_check":False
-		}
-
-		results=initialize_parameters(start_vars={},dataset={},this_trait={})
-		self.assertEqual(results,expected_results)
-
-		start_vars={
-		"format":"F1",
-		"limit_to":"1",
-		"mapping_method":"rqtl",
-		"control_marker":True,
-		"pair_scan":"true",
-		"interval_mapping":"true",
-		"use_loco":"true",
-		"num_perm":"14"
-
-		}
-
-		results_2=initialize_parameters(start_vars=start_vars,dataset={},this_trait={})
-		expected_results={
-		"format":"F1",
-		"limit_to":1,
-		"mapping_method":"gemma",
-		"maf":0.01,
-		"use_loco":True,
-		"num_perm":14,
-		"perm_check":"ON"
-		}
-
-		self.assertEqual(results_2,expected_results)
-		
+    def get_marker(self):
+        self.markers=[]
+class TestMapping(unittest.TestCase):
+    
+    def test_initialize_parameters(self):
+        expected_results={
+         "format":"json",
+         "limit_to":False,
+         "mapping_method":"gemma",
+         "maf":0.01,
+         "use_loco":True,
+         "num_perm":0,
+         "perm_check":False
+        }
+
+        results=initialize_parameters(start_vars={},dataset={},this_trait={})
+        self.assertEqual(results,expected_results)
+
+        start_vars={
+        "format":"F1",
+        "limit_to":"1",
+        "mapping_method":"rqtl",
+        "control_marker":True,
+        "pair_scan":"true",
+        "interval_mapping":"true",
+        "use_loco":"true",
+        "num_perm":"14"
+
+        }
+
+        results_2=initialize_parameters(start_vars=start_vars,dataset={},this_trait={})
+        expected_results={
+        "format":"F1",
+        "limit_to":1,
+        "mapping_method":"gemma",
+        "maf":0.01,
+        "use_loco":True,
+        "num_perm":14,
+        "perm_check":"ON"
+        }
+
+        self.assertEqual(results_2,expected_results)
+
+    
+    @mock.patch("wqflask.api.mapping.rqtl_mapping.run_rqtl_geno")
+    @mock.patch("wqflask.api.mapping.gemma_mapping.run_gemma")
+    @mock.patch("wqflask.api.mapping.initialize_parameters")
+    @mock.patch("wqflask.api.mapping.retrieve_sample_data")
+    @mock.patch("wqflask.api.mapping.create_trait")
+    @mock.patch("wqflask.api.mapping.data_set.create_dataset")
+    def test_do_mapping_for_api(self,mock_create_dataset,mock_trait,mock_retrieve_sample,mock_param,run_gemma
+        ,run_rqtl_geno):
+        start_vars={
+        "db":"Temp",
+        "trait_id":"dewf3232rff2",
+        "format":"F1",
+        "mapping_method":"gemma",
+        "use_loco":True
+
+        }
+        sampleList=["S1","S2","S3","S4"]
+        samplelist=["S1","S2","S4"]
+        dataset=AttributeSetter({"group":samplelist})
+        this_trait=AttributeSetter({})
+        trait_data=AttributeSetter({
+            "data":{
+            "item1":AttributeSetter({"name":"S1","value":"S1_value"}),
+            "item2":AttributeSetter({"name":"S2","value":"S2_value"}),
+            "item3":AttributeSetter({"name":"S3","value":"S3_value"}),
+
+            }
+            })
+        trait=AttributeSetter({
+            "data":trait_data
+            })
+
+        dataset.return_value=dataset
+        mock_trait.return_value=this_trait
+
+        mock_retrieve_sample.return_value=trait
+        mock_param.return_value={
+        "format":"F1",
+        "limit_to":False,
+        "mapping_method":"gemma",
+        "maf":0.01,
+        "use_loco":"True",
+        "num_perm":14,
+        "perm_check":"ON"
+        }
+
+        run_gemma.return_value=["results"]
+        results=do_mapping_for_api(start_vars=start_vars)
+        self.assertEqual(results,("results",None))
+
+        
 
 
 
-- 
cgit v1.2.3


From e80e793455d2fc6b51dbe95414a3ba8e72652a83 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Sat, 12 Dec 2020 21:21:53 +0300
Subject: add tests for getting sample_r and p values

---
 wqflask/tests/unit/wqflask/api/test_correlation.py | 38 ++++++++++++++++++++++
 .../wqflask/correlation/test_show_corr_results.py  |  2 --
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/api/test_correlation.py b/wqflask/tests/unit/wqflask/api/test_correlation.py
index 482dec67..077f7fa9 100644
--- a/wqflask/tests/unit/wqflask/api/test_correlation.py
+++ b/wqflask/tests/unit/wqflask/api/test_correlation.py
@@ -4,6 +4,7 @@ from wqflask import app
 from wqflask.api.correlation import init_corr_params
 from wqflask.api.correlation import convert_to_mouse_gene_id
 from wqflask.api.correlation import do_literature_correlation_for_all_traits
+from wqflask.api.correlation import get_sample_r_and_p_values
 
 
 class AttributeSetter:
@@ -79,5 +80,42 @@ class TestCorrelations(unittest.TestCase):
     	expected_results={'TT-1': ['GH-1', 0], 'TT-2': ['GH-2', 'V1'], 'TT-3': ['GH-3', 'V2']}
     	self.assertEqual(results,expected_results)
 
+    @mock.patch("wqflask.api.correlation.corr_result_helpers.normalize_values")
+    def test_get_sample_r_and_p_values(self,mock_normalize):
+
+        group=AttributeSetter({"samplelist":["S1","S2","S3","S4","S5","S6","S7"]})
+        target_dataset=AttributeSetter({"group":group})
+
+        target_vals=[3.4, 6.2, 4.1,3.4,1.2,5.6]
+        trait_data={"S1":AttributeSetter({"value":2.3}),"S2":AttributeSetter({"value":1.1}),"S3":AttributeSetter({"value":6.3}),"S4":AttributeSetter({"value":3.6}),"S5":AttributeSetter({"value":4.1}),"S6":AttributeSetter({"value":5.0})}
+        this_trait=AttributeSetter({"data":trait_data})
+        mock_normalize.return_value=([2.3,1.1,6.3,3.6,4.1,5.0], [3.4,6.2,4.1,3.4,1.2,5.6], 6)
+        mock_normalize.side_effect=[([2.3,1.1,6.3,3.6,4.1,5.0], [3.4,6.2,4.1,3.4,1.2,5.6], 6),([2.3,1.1,6.3,3.6,4.1,5.0], [3.4,6.2,4.1,3.4,1.2,5.6], 6),([2.3,1.1,1.4], [3.4,6.2,4.1], 3)]
+
+        results_pearsonr=get_sample_r_and_p_values(this_trait=this_trait,this_dataset={},target_vals=target_vals,target_dataset=target_dataset,type="pearson")
+        results_spearmanr=get_sample_r_and_p_values(this_trait=this_trait,this_dataset={},target_vals=target_vals,target_dataset=target_dataset,type="spearman")
+        results_num_overlap=get_sample_r_and_p_values(this_trait=this_trait,this_dataset={},target_vals=target_vals,target_dataset=target_dataset,type="pearson")
+        self.assertEqual(mock_normalize.call_count,3)
+        
+        self.assertEqual(results_pearsonr,[-0.21618688834430866, 0.680771605997119, 6])
+        self.assertEqual(results_spearmanr,[-0.11595420713048969, 0.826848213385815, 6])
+        self.assertEqual(results_num_overlap,None)
+
+    def test_calculate_results(self):
+        corr_params={
+        "type":"pearson"
+        }
+        trait_data={
+         "T1":3.4,
+         "T2":6.2,
+         "T3":4.1,
+         "T4":3.4,
+         "T5":1.2,
+         "T6":5.6
+        }
+        target_vals=[3.4, 6.2, 4.1,3.4,1.2,5.6]
+
+
+            
 
 
diff --git a/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py b/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
index 4e63207e..969a84f5 100644
--- a/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
+++ b/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
@@ -12,8 +12,6 @@ class Trait:
 
 class TestShowCorrResults(unittest.TestCase):
 
-	def test_process_samples(self):
-		pass
 	def test_get_header_fields(self):
 		expected=[
 		                    ['Index',
-- 
cgit v1.2.3


From 0adae692f2f0ce509b32d6654438213deb3da89b Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Sat, 12 Dec 2020 23:09:04 +0300
Subject: add test for calculating correlation results

---
 wqflask/tests/unit/wqflask/api/test_correlation.py | 44 +++++++++++++++-------
 1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/api/test_correlation.py b/wqflask/tests/unit/wqflask/api/test_correlation.py
index 077f7fa9..11c7d82b 100644
--- a/wqflask/tests/unit/wqflask/api/test_correlation.py
+++ b/wqflask/tests/unit/wqflask/api/test_correlation.py
@@ -1,10 +1,12 @@
 import unittest
 from unittest import mock
 from wqflask import app
+from collections import OrderedDict 
 from wqflask.api.correlation import init_corr_params
 from wqflask.api.correlation import convert_to_mouse_gene_id
 from wqflask.api.correlation import do_literature_correlation_for_all_traits
 from wqflask.api.correlation import get_sample_r_and_p_values
+from wqflask.api.correlation import calculate_results
 
 
 class AttributeSetter:
@@ -12,6 +14,17 @@ class AttributeSetter:
         for k, v in obj.items():
             setattr(self, k, v)
 
+class MockDataset(AttributeSetter):
+    def get_trait_data(self):
+        return None
+    def retrieve_genes(self,id=None):
+        return {
+         "TT-1":"GH-1",
+         "TT-2":"GH-2",
+         "TT-3":"GH-3"
+
+        }
+
 
 class TestCorrelations(unittest.TestCase):
     def setUp(self):
@@ -101,19 +114,24 @@ class TestCorrelations(unittest.TestCase):
         self.assertEqual(results_spearmanr,[-0.11595420713048969, 0.826848213385815, 6])
         self.assertEqual(results_num_overlap,None)
 
-    def test_calculate_results(self):
-        corr_params={
-        "type":"pearson"
-        }
-        trait_data={
-         "T1":3.4,
-         "T2":6.2,
-         "T3":4.1,
-         "T4":3.4,
-         "T5":1.2,
-         "T6":5.6
-        }
-        target_vals=[3.4, 6.2, 4.1,3.4,1.2,5.6]
+    @mock.patch("wqflask.api.correlation.do_literature_correlation_for_all_traits")
+    def test_calculate_results(self,literature_correlation):
+ 
+        literature_correlation.return_value={'TT-1': ['GH-1', 0], 'TT-2': ['GH-2', 3], 'TT-3': ['GH-3', 1]}
+
+
+
+        this_dataset=MockDataset({"group":AttributeSetter({"species":"rat"})})
+        target_dataset=MockDataset({"group":AttributeSetter({"species":"rat"})})
+        this_trait=AttributeSetter({"geneid":"GH-1"})
+        corr_params={"type":"literature"}
+        sorted_results=calculate_results(this_trait=this_trait,this_dataset=this_dataset,target_dataset=target_dataset,corr_params=corr_params)
+        expected_results={'TT-2': ['GH-2', 3], 'TT-3': ['GH-3', 1], 'TT-1': ['GH-1', 0]}
+
+        self.assertTrue(isinstance(sorted_results,OrderedDict))
+        self.assertEqual(type(sorted_results),OrderedDict)
+
+
 
 
             
-- 
cgit v1.2.3


From b7e2d17536febbeb47dc91015781cc6fc4647905 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Sat, 12 Dec 2020 23:36:27 +0300
Subject: replace assertEqual with assertAlmostEqual for floats

---
 wqflask/tests/unit/wqflask/api/test_correlation.py | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/api/test_correlation.py b/wqflask/tests/unit/wqflask/api/test_correlation.py
index 11c7d82b..9fa848a4 100644
--- a/wqflask/tests/unit/wqflask/api/test_correlation.py
+++ b/wqflask/tests/unit/wqflask/api/test_correlation.py
@@ -108,10 +108,12 @@ class TestCorrelations(unittest.TestCase):
         results_pearsonr=get_sample_r_and_p_values(this_trait=this_trait,this_dataset={},target_vals=target_vals,target_dataset=target_dataset,type="pearson")
         results_spearmanr=get_sample_r_and_p_values(this_trait=this_trait,this_dataset={},target_vals=target_vals,target_dataset=target_dataset,type="spearman")
         results_num_overlap=get_sample_r_and_p_values(this_trait=this_trait,this_dataset={},target_vals=target_vals,target_dataset=target_dataset,type="pearson")
-        self.assertEqual(mock_normalize.call_count,3)
-        
-        self.assertEqual(results_pearsonr,[-0.21618688834430866, 0.680771605997119, 6])
-        self.assertEqual(results_spearmanr,[-0.11595420713048969, 0.826848213385815, 6])
+        expected_pearsonr=[-0.21618688834430866, 0.680771605997119, 6]
+        expected_spearmanr=[-0.11595420713048969, 0.826848213385815, 6]
+        for i,val in enumerate(expected_pearsonr):
+            self.assertAlmostEqual(val,results_pearsonr[i])
+        for i,val in enumerate(expected_spearmanr):
+            self.assertAlmostEqual(val,results_spearmanr[i])
         self.assertEqual(results_num_overlap,None)
 
     @mock.patch("wqflask.api.correlation.do_literature_correlation_for_all_traits")
@@ -133,7 +135,6 @@ class TestCorrelations(unittest.TestCase):
 
 
 
-
             
 
 
-- 
cgit v1.2.3


From c3bfc7c07bba06c9334350111df0b9444b85b31b Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Sat, 12 Dec 2020 23:56:26 +0300
Subject: modify tests for calculate correlation results

---
 wqflask/tests/unit/wqflask/api/test_correlation.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/tests/unit/wqflask/api/test_correlation.py b/wqflask/tests/unit/wqflask/api/test_correlation.py
index 9fa848a4..cbcd006d 100644
--- a/wqflask/tests/unit/wqflask/api/test_correlation.py
+++ b/wqflask/tests/unit/wqflask/api/test_correlation.py
@@ -131,7 +131,7 @@ class TestCorrelations(unittest.TestCase):
         expected_results={'TT-2': ['GH-2', 3], 'TT-3': ['GH-3', 1], 'TT-1': ['GH-1', 0]}
 
         self.assertTrue(isinstance(sorted_results,OrderedDict))
-        self.assertEqual(type(sorted_results),OrderedDict)
+        self.assertEqual(dict(sorted_results),expected_results)
 
 
 
-- 
cgit v1.2.3


From d10b6a9bc3ed4d3f824a0dfd115f05ed647aa8c3 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Mon, 14 Dec 2020 20:08:41 +0300
Subject: pep8 formatting and refactoring tests

---
 wqflask/tests/unit/wqflask/api/test_correlation.py | 145 +++++++++++----------
 1 file changed, 79 insertions(+), 66 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/api/test_correlation.py b/wqflask/tests/unit/wqflask/api/test_correlation.py
index cbcd006d..d0264b87 100644
--- a/wqflask/tests/unit/wqflask/api/test_correlation.py
+++ b/wqflask/tests/unit/wqflask/api/test_correlation.py
@@ -1,7 +1,7 @@
 import unittest
 from unittest import mock
 from wqflask import app
-from collections import OrderedDict 
+from collections import OrderedDict
 from wqflask.api.correlation import init_corr_params
 from wqflask.api.correlation import convert_to_mouse_gene_id
 from wqflask.api.correlation import do_literature_correlation_for_all_traits
@@ -14,14 +14,16 @@ class AttributeSetter:
         for k, v in obj.items():
             setattr(self, k, v)
 
+
 class MockDataset(AttributeSetter):
     def get_trait_data(self):
         return None
-    def retrieve_genes(self,id=None):
+
+    def retrieve_genes(self, id=None):
         return {
-         "TT-1":"GH-1",
-         "TT-2":"GH-2",
-         "TT-3":"GH-3"
+            "TT-1": "GH-1",
+            "TT-2": "GH-2",
+            "TT-3": "GH-3"
 
         }
 
@@ -59,8 +61,9 @@ class TestCorrelations(unittest.TestCase):
         rat_species_results = convert_to_mouse_gene_id(
             species="rat", gene_id="GH1")
 
-        mock_db.db.execute.return_value.fetchone.side_effect = [AttributeSetter({"mouse": "MG-1"}),AttributeSetter({"mouse":"MG-2"})]
-                                          
+        mock_db.db.execute.return_value.fetchone.side_effect = [
+            AttributeSetter({"mouse": "MG-1"}), AttributeSetter({"mouse": "MG-2"})]
+
         self.assertEqual(convert_to_mouse_gene_id(
             species="mouse", gene_id="MG-4"), "MG-4")
         self.assertEqual(convert_to_mouse_gene_id(
@@ -68,73 +71,83 @@ class TestCorrelations(unittest.TestCase):
         self.assertEqual(convert_to_mouse_gene_id(
             species="human", gene_id="H1"), "MG-2")
 
-    
-    
     @mock.patch("wqflask.api.correlation.g")
     @mock.patch("wqflask.api.correlation.convert_to_mouse_gene_id")
-    def test_do_literature_correlation_for_all_traits(self,mock_convert_to_mouse_geneid,mock_db):
-    	mock_convert_to_mouse_geneid.side_effect=["MG-1","MG-2;","MG-3","MG-4"]
-   
-
-    	trait_geneid_dict={
-    	 "TT-1":"GH-1",
-    	 "TT-2":"GH-2",
-    	 "TT-3":"GH-3"
+    def test_do_literature_correlation_for_all_traits(self, mock_convert_to_mouse_geneid, mock_db):
+        mock_convert_to_mouse_geneid.side_effect = [
+            "MG-1", "MG-2;", "MG-3", "MG-4"]
 
-    	}
-    	mock_db.db.execute.return_value.fetchone.side_effect=[AttributeSetter({"value":"V1"}),AttributeSetter({"value":"V2"}),AttributeSetter({"value":"V3"})]
+        trait_geneid_dict = {
+            "TT-1": "GH-1",
+            "TT-2": "GH-2",
+            "TT-3": "GH-3"
 
+        }
+        mock_db.db.execute.return_value.fetchone.side_effect = [AttributeSetter(
+            {"value": "V1"}), AttributeSetter({"value": "V2"}), AttributeSetter({"value": "V3"})]
 
-    	this_trait=AttributeSetter({"geneid":"GH-1"})
+        this_trait = AttributeSetter({"geneid": "GH-1"})
 
-    	target_dataset=AttributeSetter({"group":AttributeSetter({"species":"rat"})})
-    	results=do_literature_correlation_for_all_traits(this_trait=this_trait,target_dataset=target_dataset,trait_geneid_dict=trait_geneid_dict,corr_params={})
+        target_dataset = AttributeSetter(
+            {"group": AttributeSetter({"species": "rat"})})
+        results = do_literature_correlation_for_all_traits(
+            this_trait=this_trait, target_dataset=target_dataset, trait_geneid_dict=trait_geneid_dict, corr_params={})
 
-    	expected_results={'TT-1': ['GH-1', 0], 'TT-2': ['GH-2', 'V1'], 'TT-3': ['GH-3', 'V2']}
-    	self.assertEqual(results,expected_results)
+        expected_results = {'TT-1': ['GH-1', 0],
+                            'TT-2': ['GH-2', 'V1'], 'TT-3': ['GH-3', 'V2']}
+        self.assertEqual(results, expected_results)
 
     @mock.patch("wqflask.api.correlation.corr_result_helpers.normalize_values")
-    def test_get_sample_r_and_p_values(self,mock_normalize):
-
-        group=AttributeSetter({"samplelist":["S1","S2","S3","S4","S5","S6","S7"]})
-        target_dataset=AttributeSetter({"group":group})
-
-        target_vals=[3.4, 6.2, 4.1,3.4,1.2,5.6]
-        trait_data={"S1":AttributeSetter({"value":2.3}),"S2":AttributeSetter({"value":1.1}),"S3":AttributeSetter({"value":6.3}),"S4":AttributeSetter({"value":3.6}),"S5":AttributeSetter({"value":4.1}),"S6":AttributeSetter({"value":5.0})}
-        this_trait=AttributeSetter({"data":trait_data})
-        mock_normalize.return_value=([2.3,1.1,6.3,3.6,4.1,5.0], [3.4,6.2,4.1,3.4,1.2,5.6], 6)
-        mock_normalize.side_effect=[([2.3,1.1,6.3,3.6,4.1,5.0], [3.4,6.2,4.1,3.4,1.2,5.6], 6),([2.3,1.1,6.3,3.6,4.1,5.0], [3.4,6.2,4.1,3.4,1.2,5.6], 6),([2.3,1.1,1.4], [3.4,6.2,4.1], 3)]
-
-        results_pearsonr=get_sample_r_and_p_values(this_trait=this_trait,this_dataset={},target_vals=target_vals,target_dataset=target_dataset,type="pearson")
-        results_spearmanr=get_sample_r_and_p_values(this_trait=this_trait,this_dataset={},target_vals=target_vals,target_dataset=target_dataset,type="spearman")
-        results_num_overlap=get_sample_r_and_p_values(this_trait=this_trait,this_dataset={},target_vals=target_vals,target_dataset=target_dataset,type="pearson")
-        expected_pearsonr=[-0.21618688834430866, 0.680771605997119, 6]
-        expected_spearmanr=[-0.11595420713048969, 0.826848213385815, 6]
-        for i,val in enumerate(expected_pearsonr):
-            self.assertAlmostEqual(val,results_pearsonr[i])
-        for i,val in enumerate(expected_spearmanr):
-            self.assertAlmostEqual(val,results_spearmanr[i])
-        self.assertEqual(results_num_overlap,None)
+    def test_get_sample_r_and_p_values(self, mock_normalize):
+
+        group = AttributeSetter(
+            {"samplelist": ["S1", "S2", "S3", "S4", "S5", "S6", "S7"]})
+        target_dataset = AttributeSetter({"group": group})
+
+        target_vals = [3.4, 6.2, 4.1, 3.4, 1.2, 5.6]
+        trait_data = {"S1": AttributeSetter({"value": 2.3}), "S2": AttributeSetter({"value": 1.1}), 
+        "S3": AttributeSetter(
+            {"value": 6.3}), "S4": AttributeSetter({"value": 3.6}), "S5": AttributeSetter({"value": 4.1}), 
+        "S6": AttributeSetter({"value": 5.0})}
+        this_trait = AttributeSetter({"data": trait_data})
+        mock_normalize.return_value = ([2.3, 1.1, 6.3, 3.6, 4.1, 5.0],
+                                       [3.4, 6.2, 4.1, 3.4, 1.2, 5.6], 6)
+        mock_normalize.side_effect = [([2.3, 1.1, 6.3, 3.6, 4.1, 5.0],
+                                       [3.4, 6.2, 4.1, 3.4, 1.2, 5.6], 6),
+                                      ([2.3, 1.1, 6.3, 3.6, 4.1, 5.0],
+                                       [3.4, 6.2, 4.1, 3.4, 1.2, 5.6], 6),
+                                      ([2.3, 1.1, 1.4], [3.4, 6.2, 4.1], 3)]
+
+        results_pearsonr = get_sample_r_and_p_values(this_trait=this_trait, this_dataset={
+        }, target_vals=target_vals, target_dataset=target_dataset, type="pearson")
+        results_spearmanr = get_sample_r_and_p_values(this_trait=this_trait, this_dataset={
+        }, target_vals=target_vals, target_dataset=target_dataset, type="spearman")
+        results_num_overlap = get_sample_r_and_p_values(this_trait=this_trait, this_dataset={
+        }, target_vals=target_vals, target_dataset=target_dataset, type="pearson")
+        expected_pearsonr = [-0.21618688834430866, 0.680771605997119, 6]
+        expected_spearmanr = [-0.11595420713048969, 0.826848213385815, 6]
+        for i, val in enumerate(expected_pearsonr):
+            self.assertAlmostEqual(val, results_pearsonr[i],4)
+        for i, val in enumerate(expected_spearmanr):
+            self.assertAlmostEqual(val, results_spearmanr[i],4)
+        self.assertEqual(results_num_overlap, None)
 
     @mock.patch("wqflask.api.correlation.do_literature_correlation_for_all_traits")
-    def test_calculate_results(self,literature_correlation):
- 
-        literature_correlation.return_value={'TT-1': ['GH-1', 0], 'TT-2': ['GH-2', 3], 'TT-3': ['GH-3', 1]}
-
-
-
-        this_dataset=MockDataset({"group":AttributeSetter({"species":"rat"})})
-        target_dataset=MockDataset({"group":AttributeSetter({"species":"rat"})})
-        this_trait=AttributeSetter({"geneid":"GH-1"})
-        corr_params={"type":"literature"}
-        sorted_results=calculate_results(this_trait=this_trait,this_dataset=this_dataset,target_dataset=target_dataset,corr_params=corr_params)
-        expected_results={'TT-2': ['GH-2', 3], 'TT-3': ['GH-3', 1], 'TT-1': ['GH-1', 0]}
-
-        self.assertTrue(isinstance(sorted_results,OrderedDict))
-        self.assertEqual(dict(sorted_results),expected_results)
-
-
-
-            
-
-
+    def test_calculate_results(self, literature_correlation):
+
+        literature_correlation.return_value = {
+            'TT-1': ['GH-1', 0], 'TT-2': ['GH-2', 3], 'TT-3': ['GH-3', 1]}
+
+        this_dataset = MockDataset(
+            {"group": AttributeSetter({"species": "rat"})})
+        target_dataset = MockDataset(
+            {"group": AttributeSetter({"species": "rat"})})
+        this_trait = AttributeSetter({"geneid": "GH-1"})
+        corr_params = {"type": "literature"}
+        sorted_results = calculate_results(
+            this_trait=this_trait, this_dataset=this_dataset, target_dataset=target_dataset, corr_params=corr_params)
+        expected_results = {'TT-2': ['GH-2', 3],
+                            'TT-3': ['GH-3', 1], 'TT-1': ['GH-1', 0]}
+
+        self.assertTrue(isinstance(sorted_results, OrderedDict))
+        self.assertEqual(dict(sorted_results), expected_results)
-- 
cgit v1.2.3


From 4773ac8715896489562df9321b4a4d34ae61d6a7 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Mon, 14 Dec 2020 20:10:37 +0300
Subject: pep8 formatting in wqflask/api/test_mapping.py

---
 wqflask/tests/unit/wqflask/api/test_mapping.py | 154 ++++++++++++-------------
 1 file changed, 75 insertions(+), 79 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/api/test_mapping.py b/wqflask/tests/unit/wqflask/api/test_mapping.py
index 5455b215..b094294a 100644
--- a/wqflask/tests/unit/wqflask/api/test_mapping.py
+++ b/wqflask/tests/unit/wqflask/api/test_mapping.py
@@ -5,108 +5,104 @@ from wqflask.api.mapping import do_mapping_for_api
 
 
 class AttributeSetter:
-    def __init__(self,obj):
-        for key,value in obj.items():
-            setattr(self,key,value)
+    def __init__(self, obj):
+        for key, value in obj.items():
+            setattr(self, key, value)
+
 
 class MockGroup(AttributeSetter):
     def get_marker(self):
-        self.markers=[]
+        self.markers = []
+
+
 class TestMapping(unittest.TestCase):
-    
+
     def test_initialize_parameters(self):
-        expected_results={
-         "format":"json",
-         "limit_to":False,
-         "mapping_method":"gemma",
-         "maf":0.01,
-         "use_loco":True,
-         "num_perm":0,
-         "perm_check":False
+        expected_results = {
+            "format": "json",
+            "limit_to": False,
+            "mapping_method": "gemma",
+            "maf": 0.01,
+            "use_loco": True,
+            "num_perm": 0,
+            "perm_check": False
         }
 
-        results=initialize_parameters(start_vars={},dataset={},this_trait={})
-        self.assertEqual(results,expected_results)
+        results = initialize_parameters(
+            start_vars={}, dataset={}, this_trait={})
+        self.assertEqual(results, expected_results)
 
-        start_vars={
-        "format":"F1",
-        "limit_to":"1",
-        "mapping_method":"rqtl",
-        "control_marker":True,
-        "pair_scan":"true",
-        "interval_mapping":"true",
-        "use_loco":"true",
-        "num_perm":"14"
+        start_vars = {
+            "format": "F1",
+            "limit_to": "1",
+            "mapping_method": "rqtl",
+            "control_marker": True,
+            "pair_scan": "true",
+            "interval_mapping": "true",
+            "use_loco": "true",
+            "num_perm": "14"
 
         }
 
-        results_2=initialize_parameters(start_vars=start_vars,dataset={},this_trait={})
-        expected_results={
-        "format":"F1",
-        "limit_to":1,
-        "mapping_method":"gemma",
-        "maf":0.01,
-        "use_loco":True,
-        "num_perm":14,
-        "perm_check":"ON"
+        results_2 = initialize_parameters(
+            start_vars=start_vars, dataset={}, this_trait={})
+        expected_results = {
+            "format": "F1",
+            "limit_to": 1,
+            "mapping_method": "gemma",
+            "maf": 0.01,
+            "use_loco": True,
+            "num_perm": 14,
+            "perm_check": "ON"
         }
 
-        self.assertEqual(results_2,expected_results)
+        self.assertEqual(results_2, expected_results)
 
-    
     @mock.patch("wqflask.api.mapping.rqtl_mapping.run_rqtl_geno")
     @mock.patch("wqflask.api.mapping.gemma_mapping.run_gemma")
     @mock.patch("wqflask.api.mapping.initialize_parameters")
     @mock.patch("wqflask.api.mapping.retrieve_sample_data")
     @mock.patch("wqflask.api.mapping.create_trait")
     @mock.patch("wqflask.api.mapping.data_set.create_dataset")
-    def test_do_mapping_for_api(self,mock_create_dataset,mock_trait,mock_retrieve_sample,mock_param,run_gemma
-        ,run_rqtl_geno):
-        start_vars={
-        "db":"Temp",
-        "trait_id":"dewf3232rff2",
-        "format":"F1",
-        "mapping_method":"gemma",
-        "use_loco":True
+    def test_do_mapping_for_api(self, mock_create_dataset, mock_trait, mock_retrieve_sample, mock_param, run_gemma, run_rqtl_geno):
+        start_vars = {
+            "db": "Temp",
+            "trait_id": "dewf3232rff2",
+            "format": "F1",
+            "mapping_method": "gemma",
+            "use_loco": True
 
         }
-        sampleList=["S1","S2","S3","S4"]
-        samplelist=["S1","S2","S4"]
-        dataset=AttributeSetter({"group":samplelist})
-        this_trait=AttributeSetter({})
-        trait_data=AttributeSetter({
-            "data":{
-            "item1":AttributeSetter({"name":"S1","value":"S1_value"}),
-            "item2":AttributeSetter({"name":"S2","value":"S2_value"}),
-            "item3":AttributeSetter({"name":"S3","value":"S3_value"}),
+        sampleList = ["S1", "S2", "S3", "S4"]
+        samplelist = ["S1", "S2", "S4"]
+        dataset = AttributeSetter({"group": samplelist})
+        this_trait = AttributeSetter({})
+        trait_data = AttributeSetter({
+            "data": {
+                "item1": AttributeSetter({"name": "S1", "value": "S1_value"}),
+                "item2": AttributeSetter({"name": "S2", "value": "S2_value"}),
+                "item3": AttributeSetter({"name": "S3", "value": "S3_value"}),
 
             }
-            })
-        trait=AttributeSetter({
-            "data":trait_data
-            })
-
-        dataset.return_value=dataset
-        mock_trait.return_value=this_trait
-
-        mock_retrieve_sample.return_value=trait
-        mock_param.return_value={
-        "format":"F1",
-        "limit_to":False,
-        "mapping_method":"gemma",
-        "maf":0.01,
-        "use_loco":"True",
-        "num_perm":14,
-        "perm_check":"ON"
+        })
+        trait = AttributeSetter({
+            "data": trait_data
+        })
+
+        dataset.return_value = dataset
+        mock_trait.return_value = this_trait
+
+        mock_retrieve_sample.return_value = trait
+        mock_param.return_value = {
+            "format": "F1",
+            "limit_to": False,
+            "mapping_method": "gemma",
+            "maf": 0.01,
+            "use_loco": "True",
+            "num_perm": 14,
+            "perm_check": "ON"
         }
 
-        run_gemma.return_value=["results"]
-        results=do_mapping_for_api(start_vars=start_vars)
-        self.assertEqual(results,("results",None))
-
-        
-
-
-
-
-
+        run_gemma.return_value = ["results"]
+        results = do_mapping_for_api(start_vars=start_vars)
+        self.assertEqual(results, ("results", None))
-- 
cgit v1.2.3


From 6b6820ec9975ae4c7e9628e0d2b41754b0429b0e Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Wed, 16 Dec 2020 11:29:19 +0300
Subject: modify tests for show_corr_results

---
 wqflask/tests/unit/wqflask/correlation/__init__.py |   0
 .../correlation/test_correlation_functions.py      |   3 +-
 .../wqflask/correlation/test_show_corr_results.py  | 174 +++++++++++----------
 3 files changed, 90 insertions(+), 87 deletions(-)
 create mode 100644 wqflask/tests/unit/wqflask/correlation/__init__.py

diff --git a/wqflask/tests/unit/wqflask/correlation/__init__.py b/wqflask/tests/unit/wqflask/correlation/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/wqflask/tests/unit/wqflask/correlation/test_correlation_functions.py b/wqflask/tests/unit/wqflask/correlation/test_correlation_functions.py
index db449eb1..44d2e0fc 100644
--- a/wqflask/tests/unit/wqflask/correlation/test_correlation_functions.py
+++ b/wqflask/tests/unit/wqflask/correlation/test_correlation_functions.py
@@ -5,8 +5,7 @@ from wqflask.correlation.correlation_functions import cal_zero_order_corr_for_ti
 
 
 class TestCorrelationFunctions(unittest.TestCase):
-
-
+    
     @mock.patch("wqflask.correlation.correlation_functions.MrnaAssayTissueData")
     def test_get_trait_symbol_and_tissue_values(self, mock_class):
         """test for getting trait symbol and tissue_values"""
diff --git a/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py b/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
index 969a84f5..ffb96dd6 100644
--- a/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
+++ b/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
@@ -2,92 +2,96 @@ import unittest
 from unittest import mock
 from wqflask.correlation.show_corr_results import get_header_fields
 from wqflask.correlation.show_corr_results import generate_corr_json
-from wqflask.correlation.show_corr_results import do_bicor
 
 
-class Trait:
-	def __init__(self,trait_obj):
-		for key,value in trait_obj.items():
-			setattr(self,key,value)
+class AttributeSetter:
+    def __init__(self, trait_obj):
+        for key, value in trait_obj.items():
+            setattr(self, key, value)
 
-class TestShowCorrResults(unittest.TestCase):
 
-	def test_get_header_fields(self):
-		expected=[
-		                    ['Index',
-                                'Record',
-                                'Symbol',
-                                'Description',
-                                'Location',
-                                'Mean',
-                                'Sample rho',
-                                'N',
-                                'Sample p(rho)',
-                                'Lit rho',
-                                'Tissue rho',
-                                'Tissue p(rho)',
-                                'Max LRS',
-                                'Max LRS Location',
-                                'Additive Effect'],
-
-                            ['Index',
-                                 'ID',
-                                 'Location',
-                                 'Sample r',
-                                 'N',
-                                 'Sample p(r)']
-
-		]
-		result1=get_header_fields("ProbeSet","spearman")
-		result2=get_header_fields("Other","Other")
-		self.assertEqual(result1,expected[0])
-		self.assertEqual(result2,expected[1])
-
-
-
-
-	def test_generate_corr_json(self):
-		this_trait=Trait({"name":"trait_test"})
-		dataset=Trait({"name":"the_name"})
-		target_dataset=Trait({"type":"Publish"})
-	
-		trait_with_publish={
-		"description_display":"Trait 2 description",
-		"authors":"trait_2 ",
-		"pubmed_id":"34n4nn31hn43",
-		"lrs_location":"N/A",
-		"additive":"",
-		"sample_r":100,
-		"num_overlap":3.2,
-		"view":True,
-		"name":"trait_1",
-		"pubmed_text":"2016",
-		"additive":"",
-		"sample_r":10.5,
-		"LRS_score_repr":"N/A",
-		"LRS_location_repr":"N/A",
-		"sample_p":5,
-		"num_overlap":"num_1"
-
-
-
-		}
-		expected_results="""[{"trait_id": "trait_1", "description": "Trait 2 description", "authors": "trait_2 ", "pubmed_id": "34n4nn31hn43", "year": "2016", "lrs_score": "N/A", "lrs_location": "N/A", "additive": "N/A", "sample_r": "10.500", "num_overlap": "num_1", "sample_p": "5.000e+00"}]"""
-
-		corr_results=[Trait(trait_with_publish)]
-		results=generate_corr_json(corr_results=corr_results,this_trait=this_trait,dataset=dataset,target_dataset=target_dataset,for_api=True)
-		self.assertEqual(results,expected_results)
-		
-		
-
-	def test_generate_corr_json_view_false(self):
-		trait=Trait({"view":False})
-		corr_results=[trait]
-		this_trait=Trait({"name":"trait_test"})
-		dataset=Trait({"name":"the_name"})
-		
-
-		results_where_view_is_false=generate_corr_json(corr_results=corr_results,this_trait=this_trait,dataset={},target_dataset={},for_api=False)
-
-		# self.assertEqual(results,[])
-		self.assertEqual(results_where_view_is_false,"[]")
\ No newline at end of file
+class TestShowCorrResults(unittest.TestCase):
+    def test_get_header_fields(self):
+        expected = [
+            ['Index',
+             'Record',
+             'Symbol',
+             'Description',
+             'Location',
+             'Mean',
+             'Sample rho',
+             'N',
+             'Sample p(rho)',
+             'Lit rho',
+             'Tissue rho',
+             'Tissue p(rho)',
+             'Max LRS',
+             'Max LRS Location',
+             'Additive Effect'],
+
+            ['Index',
+             'ID',
+             'Location',
+             'Sample r',
+             'N',
+             'Sample p(r)']
+
+        ]
+        result1 = get_header_fields("ProbeSet", "spearman")
+        result2 = get_header_fields("Other", "Other")
+        self.assertEqual(result1, expected[0])
+        self.assertEqual(result2, expected[1])
+
+    @mock.patch("wqflask.correlation.show_corr_results.hmac.data_hmac")
+    def test_generate_corr_json(self, mock_data_hmac):
+        mock_data_hmac.return_value = "hajsdiau"
+
+        dataset = AttributeSetter({"name": "the_name"})
+        this_trait = AttributeSetter(
+            {"name": "trait_test", "dataset": dataset})
+        target_dataset = AttributeSetter({"type": "Publish"})
+        corr_trait_1 = AttributeSetter({
+            "name": "trait_1",
+            "dataset": AttributeSetter({"name": "dataset_1"}),
+            "view": True,
+            "abbreviation": "T1",
+            "description_display": "Trait I description",
+            "authors": "JM J,JYEW",
+            "pubmed_id": "34n4nn31hn43",
+            "pubmed_text": "2016",
+            "pubmed_link": "https://www.load",
+            "lod_score": "",
+            "LRS_location_repr": "BXBS",
+            "additive": "",
+            "sample_r": 10.5,
+            "num_overlap": 2,
+            "sample_p": 5
+
+
+
+
+        })
+        corr_results = [corr_trait_1]
+
+        dataset_type_other = {
+            "location": "cx-3-4",
+            "sample_4": 12.32,
+            "num_overlap": 3,
+            "sample_p": 10.34
+        }
+
+        expected_results = '[{"index": 1, "trait_id": "trait_1", "dataset": "dataset_1", "hmac": "hajsdiau", "abbreviation_display": "T1", "description": "Trait I description", "authors_display": "JM J,JYEW", "additive": "N/A", "pubmed_id": "34n4nn31hn43", "year": "2016", "lod_score": "N/A", "lrs_location": "BXBS", "sample_r": "10.500", "num_overlap": 2, "sample_p": "5.000e+00"}]'
+
+        results1 = generate_corr_json(corr_results=corr_results, this_trait=this_trait,
+                                      dataset=dataset, target_dataset=target_dataset, for_api=True)
+        self.assertEqual(expected_results, results1)
+
+    def test_generate_corr_json_view_false(self):
+        trait = AttributeSetter({"view": False})
+        corr_results = [trait]
+        this_trait = AttributeSetter({"name": "trait_test"})
+        dataset = AttributeSetter({"name": "the_name"})
+
+        results_where_view_is_false = generate_corr_json(
+            corr_results=corr_results, this_trait=this_trait, dataset={}, target_dataset={}, for_api=False)
+        self.assertEqual(results_where_view_is_false, "[]")
-- 
cgit v1.2.3


From f2e4e893f5639f216f8cc6fc57984aaebffd82ef Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Mon, 14 Dec 2020 14:11:23 +0300
Subject: add tests for snp browser

---
 wqflask/tests/unit/wqflask/snp_browser/__init__.py |  0
 .../unit/wqflask/snp_browser/test_snp_browser.py   | 84 ++++++++++++++++++++++
 2 files changed, 84 insertions(+)
 create mode 100644 wqflask/tests/unit/wqflask/snp_browser/__init__.py
 create mode 100644 wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py

diff --git a/wqflask/tests/unit/wqflask/snp_browser/__init__.py b/wqflask/tests/unit/wqflask/snp_browser/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
new file mode 100644
index 00000000..e8751778
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
@@ -0,0 +1,84 @@
+import unittest
+from unittest import mock
+from wqflask import app
+from wqflask.snp_browser.snp_browser import get_gene_id
+from wqflask.snp_browser.snp_browser import get_gene_id_name_dict
+from wqflask.snp_browser.snp_browser import check_if_in_gene
+from wqflask.snp_browser.snp_browser import get_browser_sample_lists
+from wqflask.snp_browser.snp_browser import get_header_list
+
+class TestSnpBrowser(unittest.TestCase):
+    def setUp(self):
+        self.app_context = app.app_context()
+        self.app_context.push()
+
+    def tearDown(self):
+        self.app_context.pop()
+
+
+    @mock.patch("wqflask.snp_browser.snp_browser.g")
+    def test_get_gene_id(self, mock_db):
+        mock_db.db.execute.return_value.fetchone.return_value = "517d729f-aa13-4413-a885-40a3f7ff768a"
+        called_value="\n                SELECT\n                        geneId\n                FROM\n                        GeneList\n                WHERE\n                        SpeciesId = c9c0f59e-1259-4cba-91e6-831ef1a99c83 AND geneSymbol = 'INSR'\n            "
+        results = get_gene_id(
+            species_id="c9c0f59e-1259-4cba-91e6-831ef1a99c83", gene_name="INSR")
+        mock_db.db.execute.assert_called_once_with(called_value)
+        self.assertEqual(results, "517d729f-aa13-4413-a885-40a3f7ff768a")
+
+    @mock.patch("wqflask.snp_browser.snp_browser.g")
+    def test_gene_id_name_dict(self,mock_db):
+    	no_gene_names=[]
+    	self.assertEqual("",get_gene_id_name_dict(species_id="fregb343bui43g4",gene_name_list=no_gene_names))
+    	gene_name_list=["GH1","GH2","GH3"]
+    	mock_db.db.execute.return_value.fetchall.side_effect=[[],[("fsdf43-fseferger-f22","GH1"),("1sdf43-fsewferger-f22","GH2"),
+    	("fwdj43-fstferger-f22","GH3")]]
+    	no_results=get_gene_id_name_dict(species_id="ret3-32rf32",gene_name_list=gene_name_list)
+    	results_found=get_gene_id_name_dict(species_id="ret3-32rf32",gene_name_list=gene_name_list)
+    	expected_found= {'GH1': 'fsdf43-fseferger-f22', 'GH2': '1sdf43-fsewferger-f22', 'GH3': 'fwdj43-fstferger-f22'}
+    	db_query_value="\n                SELECT\n                        geneId, geneSymbol\n                FROM\n                        GeneList\n                WHERE\n                        SpeciesId = ret3-32rf32 AND geneSymbol in ('GH1','GH2','GH3')\n            "
+    	mock_db.db.execute.assert_called_with(db_query_value)
+    	self.assertEqual(results_found,expected_found)
+    	self.assertEqual(no_results,{})
+
+    @mock.patch("wqflask.snp_browser.snp_browser.g")
+    def test_check_if_in_gene(self,mock_db):
+    	mock_db.db.execute.return_value.fetchone.side_effect=[("fsdf-232sdf-sdf","GHA"),""]
+    	results_found=check_if_in_gene(species_id="517d729f-aa13-4413-a885-40a3f7ff768a",chr="CH1",mb=12.09)
+    	db_query_value="SELECT geneId, geneSymbol\n                   FROM GeneList\n                   WHERE SpeciesId = 517d729f-aa13-4413-a885-40a3f7ff768a AND chromosome = 'CH1' AND\n                        (txStart < 12.09 AND txEnd > 12.09); "
+    	gene_not_found=check_if_in_gene(species_id="517d729f-aa13-4413-a885-40a3f7ff768a",chr="CH1",mb=12.09)
+    	mock_db.db.execute.assert_called_with(db_query_value)
+    	self.assertEqual(gene_not_found,"")
+
+    @mock.patch("wqflask.snp_browser.snp_browser.g")
+    def test_get_browser_sample_lists(self,mock_db):
+    	mock_db.db.execute.return_value.fetchall.return_value=[]
+
+    	results=get_browser_sample_lists(species_id="12")
+    	self.assertEqual(results, {'mouse': [], 'rat': []})
+
+    def test_get_header_list(self):
+    	empty_columns={"snp_source":"false","conservation_score":"true","gene_name":"false","transcript":"false","exon":"false","domain_2":"true","function":"false","function_details":"true"}
+    	strains={"mouse":["S1","S2","S3","S4","S5"],"rat":[]}
+    	expected_results=([['Index', 'SNP ID', 'Chr', 'Mb', 'Alleles', 'ConScore', 'Domain 1', 'Domain 2', 'Details'], ['S1', 'S2', 'S3', 'S4', 'S5']], 5)
+
+    	results_with_snp=get_header_list(variant_type="SNP",strains=strains,species="Mouse",empty_columns=empty_columns)
+    	results_with_indel=get_header_list(variant_type="InDel",strains=strains,species="rat",empty_columns=[])
+    	expected_results_with_indel=(['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start', 'Mb End', 'Strand', 'Size', 'Sequence', 'Source'],0)
+
+    	self.assertEqual(expected_results,results_with_snp)
+    	self.assertEqual(results_with_indel,expected_results_with_indel)
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
-- 
cgit v1.2.3


From db3170eb2fe66d8fd337803a730c18367df1b150 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Mon, 14 Dec 2020 16:11:07 +0300
Subject: add tests for type checking

---
 wqflask/tests/unit/utility/test_type_checking.py | 57 ++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 wqflask/tests/unit/utility/test_type_checking.py

diff --git a/wqflask/tests/unit/utility/test_type_checking.py b/wqflask/tests/unit/utility/test_type_checking.py
new file mode 100644
index 00000000..1ea11695
--- /dev/null
+++ b/wqflask/tests/unit/utility/test_type_checking.py
@@ -0,0 +1,57 @@
+import unittest
+from utility.type_checking import is_float
+from utility.type_checking import is_int
+from utility.type_checking import is_str
+from utility.type_checking import get_float
+from utility.type_checking import get_int
+from utility.type_checking import get_string
+class TestTypeChecking(unittest.TestCase):
+	def test_is_float(self):
+		floats=[2,1.2,'3.1']
+		not_floats=["String",None,[],()]
+		for flt in floats:
+			results=is_float(flt)
+			self.assertTrue(results)
+		for nflt in not_floats:
+			results=is_float(nflt)
+			self.assertFalse(results)
+
+	def test_is_int(self):
+		int_values=[1,1.1]
+		not_int_values=["1sdf",None,[],"1.1"]
+		for int_val in int_values:
+			results=is_int(int_val)
+			self.assertTrue(results)
+		for not_int in not_int_values:
+			results=is_int(not_int)
+			self.assertFalse(results)
+
+	def test_is_str(self):
+		string_values=[1,False,[],{},"string_value"]
+		falsey_values=[None]
+		for string_val in string_values:
+			results=is_str(string_val)
+			self.assertTrue(results)
+		for non_string in falsey_values:
+			results=is_str(non_string)
+			self.assertFalse(results)
+
+
+	def test_get_float(self):
+		vars_object={"min_value":"12"}
+		results=get_float(vars_object,"min_value")
+		self.assertEqual(results,12.0)
+
+	def test_get_int(self):
+		vars_object={"lx_value":"1"}
+		results=get_int(vars_object,"lx_value")
+		self.assertEqual(results,1)
+
+	def test_get_string(self):
+		string_object={"mx_value":1}
+		results=get_string(string_object,"mx_value")
+		self.assertEqual(results,"1")
+
+
+
+
-- 
cgit v1.2.3


From 2030cc56db878b05e5507c7c3d5ddef39ff223cb Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Mon, 14 Dec 2020 16:15:01 +0300
Subject: replace vars with vars_obj which is a function name in python

---
 wqflask/utility/type_checking.py | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/wqflask/utility/type_checking.py b/wqflask/utility/type_checking.py
index f15b17e2..6b029317 100644
--- a/wqflask/utility/type_checking.py
+++ b/wqflask/utility/type_checking.py
@@ -23,20 +23,20 @@ def is_str(value):
     except:
         return False
 
-def get_float(vars,name,default=None):
-    if name in vars:
-        if is_float(vars[name]):
-            return float(vars[name])
+def get_float(vars_obj,name,default=None):
+    if name in vars_obj:
+        if is_float(vars_obj[name]):
+            return float(vars_obj[name])
     return default
 
-def get_int(vars,name,default=None):
-    if name in vars:
-        if is_int(vars[name]):
-            return float(vars[name])
+def get_int(vars_obj,name,default=None):
+    if name in vars_obj:
+        if is_int(vars_obj[name]):
+            return float(vars_obj[name])
     return default
 
-def get_string(vars,name,default=None):
-    if name in vars:
-        if not vars[name] is None:
-            return str(vars[name])
+def get_string(vars_obj,name,default=None):
+    if name in vars_obj:
+        if not vars_obj[name] is None:
+            return str(vars_obj[name])
     return default
-- 
cgit v1.2.3


From 868b8cba1cda983d8d401e60e30794529b557c80 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Mon, 14 Dec 2020 22:36:36 +0300
Subject: modify get_header tests

---
 .../unit/wqflask/snp_browser/test_snp_browser.py   | 23 +++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
index e8751778..9ec32c78 100644
--- a/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
+++ b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
@@ -15,6 +15,18 @@ class TestSnpBrowser(unittest.TestCase):
     def tearDown(self):
         self.app_context.pop()
 
+    def test_get_header_list(self):
+        empty_columns={"snp_source":"false","conservation_score":"true","gene_name":"false","transcript":"false","exon":"false","domain_2":"true","function":"false","function_details":"true"}
+        strains={"mouse":["S1","S2","S3","S4","S5"],"rat":[]}
+        expected_results=([['Index', 'SNP ID', 'Chr', 'Mb', 'Alleles', 'ConScore', 'Domain 1', 'Domain 2', 'Details'], ['S1', 'S2', 'S3', 'S4', 'S5']], 5)
+
+        results_with_snp=get_header_list(variant_type="SNP",strains=strains,species="Mouse",empty_columns=empty_columns)
+        results_with_indel=get_header_list(variant_type="InDel",strains=strains,species="rat",empty_columns=[])
+        expected_results_with_indel=(['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start', 'Mb End', 'Strand', 'Size', 'Sequence', 'Source'],0)
+
+        self.assertEqual(expected_results,results_with_snp)
+        self.assertEqual(results_with_indel,expected_results_with_indel)
+
 
     @mock.patch("wqflask.snp_browser.snp_browser.g")
     def test_get_gene_id(self, mock_db):
@@ -56,17 +68,6 @@ class TestSnpBrowser(unittest.TestCase):
     	results=get_browser_sample_lists(species_id="12")
     	self.assertEqual(results, {'mouse': [], 'rat': []})
 
-    def test_get_header_list(self):
-    	empty_columns={"snp_source":"false","conservation_score":"true","gene_name":"false","transcript":"false","exon":"false","domain_2":"true","function":"false","function_details":"true"}
-    	strains={"mouse":["S1","S2","S3","S4","S5"],"rat":[]}
-    	expected_results=([['Index', 'SNP ID', 'Chr', 'Mb', 'Alleles', 'ConScore', 'Domain 1', 'Domain 2', 'Details'], ['S1', 'S2', 'S3', 'S4', 'S5']], 5)
-
-    	results_with_snp=get_header_list(variant_type="SNP",strains=strains,species="Mouse",empty_columns=empty_columns)
-    	results_with_indel=get_header_list(variant_type="InDel",strains=strains,species="rat",empty_columns=[])
-    	expected_results_with_indel=(['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start', 'Mb End', 'Strand', 'Size', 'Sequence', 'Source'],0)
-
-    	self.assertEqual(expected_results,results_with_snp)
-    	self.assertEqual(results_with_indel,expected_results_with_indel)
 
 
 
-- 
cgit v1.2.3


From 5a73d56fdbe197e99b476d49d4adce9403c8daeb Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Fri, 18 Dec 2020 15:18:19 +0300
Subject: refactor tests and pep8 formatting

---
 wqflask/tests/unit/utility/test_type_checking.py   |  93 ++++++++--------
 .../unit/wqflask/snp_browser/test_snp_browser.py   | 120 ++++++++++++---------
 2 files changed, 112 insertions(+), 101 deletions(-)

diff --git a/wqflask/tests/unit/utility/test_type_checking.py b/wqflask/tests/unit/utility/test_type_checking.py
index 1ea11695..48d110c7 100644
--- a/wqflask/tests/unit/utility/test_type_checking.py
+++ b/wqflask/tests/unit/utility/test_type_checking.py
@@ -5,53 +5,50 @@ from utility.type_checking import is_str
 from utility.type_checking import get_float
 from utility.type_checking import get_int
 from utility.type_checking import get_string
-class TestTypeChecking(unittest.TestCase):
-	def test_is_float(self):
-		floats=[2,1.2,'3.1']
-		not_floats=["String",None,[],()]
-		for flt in floats:
-			results=is_float(flt)
-			self.assertTrue(results)
-		for nflt in not_floats:
-			results=is_float(nflt)
-			self.assertFalse(results)
-
-	def test_is_int(self):
-		int_values=[1,1.1]
-		not_int_values=["1sdf",None,[],"1.1"]
-		for int_val in int_values:
-			results=is_int(int_val)
-			self.assertTrue(results)
-		for not_int in not_int_values:
-			results=is_int(not_int)
-			self.assertFalse(results)
-
-	def test_is_str(self):
-		string_values=[1,False,[],{},"string_value"]
-		falsey_values=[None]
-		for string_val in string_values:
-			results=is_str(string_val)
-			self.assertTrue(results)
-		for non_string in falsey_values:
-			results=is_str(non_string)
-			self.assertFalse(results)
-
-
-	def test_get_float(self):
-		vars_object={"min_value":"12"}
-		results=get_float(vars_object,"min_value")
-		self.assertEqual(results,12.0)
-
-	def test_get_int(self):
-		vars_object={"lx_value":"1"}
-		results=get_int(vars_object,"lx_value")
-		self.assertEqual(results,1)
-
-	def test_get_string(self):
-		string_object={"mx_value":1}
-		results=get_string(string_object,"mx_value")
-		self.assertEqual(results,"1")
-
-
 
 
+class TestTypeChecking(unittest.TestCase):
+    def test_is_float(self):
+        floats = [2, 1.2, '3.1']
+        not_floats = ["String", None, [], ()]
+        for flt in floats:
+            results = is_float(flt)
+            self.assertTrue(results)
+        for nflt in not_floats:
+            results = is_float(nflt)
+            self.assertFalse(results)
+
+    def test_is_int(self):
+        int_values = [1, 1.1]
+        not_int_values = ["string", None, [], "1.1"]
+        for int_val in int_values:
+            results = is_int(int_val)
+            self.assertTrue(results)
+        for not_int in not_int_values:
+            results = is_int(not_int)
+            self.assertFalse(results)
+
+    def test_is_str(self):
+        string_values = [1, False, [], {}, "string_value"]
+        falsey_values = [None]
+        for string_val in string_values:
+            results = is_str(string_val)
+            self.assertTrue(results)
+        for non_string in falsey_values:
+            results = is_str(non_string)
+            self.assertFalse(results)
+
+    def test_get_float(self):
+        vars_object = {"min_value": "12"}
+        results = get_float(vars_object, "min_value")
+        self.assertEqual(results, 12.0)
+
+    def test_get_int(self):
+        vars_object = {"lx_value": "1"}
+        results = get_int(vars_object, "lx_value")
+        self.assertEqual(results, 1)
+
+    def test_get_string(self):
+        string_object = {"mx_value": 1}
+        results = get_string(string_object, "mx_value")
+        self.assertEqual(results, "1")
\ No newline at end of file
diff --git a/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
index 9ec32c78..496d228f 100644
--- a/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
+++ b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
@@ -7,6 +7,7 @@ from wqflask.snp_browser.snp_browser import check_if_in_gene
 from wqflask.snp_browser.snp_browser import get_browser_sample_lists
 from wqflask.snp_browser.snp_browser import get_header_list
 
+
 class TestSnpBrowser(unittest.TestCase):
     def setUp(self):
         self.app_context = app.app_context()
@@ -16,70 +17,83 @@ class TestSnpBrowser(unittest.TestCase):
         self.app_context.pop()
 
     def test_get_header_list(self):
-        empty_columns={"snp_source":"false","conservation_score":"true","gene_name":"false","transcript":"false","exon":"false","domain_2":"true","function":"false","function_details":"true"}
-        strains={"mouse":["S1","S2","S3","S4","S5"],"rat":[]}
-        expected_results=([['Index', 'SNP ID', 'Chr', 'Mb', 'Alleles', 'ConScore', 'Domain 1', 'Domain 2', 'Details'], ['S1', 'S2', 'S3', 'S4', 'S5']], 5)
-
-        results_with_snp=get_header_list(variant_type="SNP",strains=strains,species="Mouse",empty_columns=empty_columns)
-        results_with_indel=get_header_list(variant_type="InDel",strains=strains,species="rat",empty_columns=[])
-        expected_results_with_indel=(['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start', 'Mb End', 'Strand', 'Size', 'Sequence', 'Source'],0)
-
-        self.assertEqual(expected_results,results_with_snp)
-        self.assertEqual(results_with_indel,expected_results_with_indel)
-
+        empty_columns = {"snp_source": "false", "conservation_score": "true", "gene_name": "false",
+                         "transcript": "false", "exon": "false", "domain_2": "true", "function": "false", "function_details": "true"}
+        strains = {"mouse": ["S1", "S2", "S3", "S4", "S5"], "rat": []}
+        expected_results = ([['Index', 'SNP ID', 'Chr', 'Mb', 'Alleles', 'ConScore',
+                              'Domain 1', 'Domain 2', 'Details'], ['S1', 'S2', 'S3', 'S4', 'S5']], 5)
+
+        results_with_snp = get_header_list(
+            variant_type="SNP", strains=strains, species="Mouse", empty_columns=empty_columns)
+        results_with_indel = get_header_list(
+            variant_type="InDel", strains=strains, species="rat", empty_columns=[])
+        expected_results_with_indel = (
+            ['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start', 
+            'Mb End', 'Strand', 'Size', 'Sequence', 'Source'], 0)
+
+        self.assertEqual(expected_results, results_with_snp)
+        self.assertEqual(results_with_indel, expected_results_with_indel)
 
     @mock.patch("wqflask.snp_browser.snp_browser.g")
     def test_get_gene_id(self, mock_db):
         mock_db.db.execute.return_value.fetchone.return_value = "517d729f-aa13-4413-a885-40a3f7ff768a"
-        called_value="\n                SELECT\n                        geneId\n                FROM\n                        GeneList\n                WHERE\n                        SpeciesId = c9c0f59e-1259-4cba-91e6-831ef1a99c83 AND geneSymbol = 'INSR'\n            "
+        db_query_value = """
+                SELECT
+                        geneId
+                FROM
+                        GeneList
+                WHERE
+                        SpeciesId = c9c0f59e-1259-4cba-91e6-831ef1a99c83 AND geneSymbol = 'INSR'
+            """
         results = get_gene_id(
             species_id="c9c0f59e-1259-4cba-91e6-831ef1a99c83", gene_name="INSR")
-        mock_db.db.execute.assert_called_once_with(called_value)
+        mock_db.db.execute.assert_called_once_with(db_query_value)
         self.assertEqual(results, "517d729f-aa13-4413-a885-40a3f7ff768a")
 
     @mock.patch("wqflask.snp_browser.snp_browser.g")
-    def test_gene_id_name_dict(self,mock_db):
-    	no_gene_names=[]
-    	self.assertEqual("",get_gene_id_name_dict(species_id="fregb343bui43g4",gene_name_list=no_gene_names))
-    	gene_name_list=["GH1","GH2","GH3"]
-    	mock_db.db.execute.return_value.fetchall.side_effect=[[],[("fsdf43-fseferger-f22","GH1"),("1sdf43-fsewferger-f22","GH2"),
-    	("fwdj43-fstferger-f22","GH3")]]
-    	no_results=get_gene_id_name_dict(species_id="ret3-32rf32",gene_name_list=gene_name_list)
-    	results_found=get_gene_id_name_dict(species_id="ret3-32rf32",gene_name_list=gene_name_list)
-    	expected_found= {'GH1': 'fsdf43-fseferger-f22', 'GH2': '1sdf43-fsewferger-f22', 'GH3': 'fwdj43-fstferger-f22'}
-    	db_query_value="\n                SELECT\n                        geneId, geneSymbol\n                FROM\n                        GeneList\n                WHERE\n                        SpeciesId = ret3-32rf32 AND geneSymbol in ('GH1','GH2','GH3')\n            "
-    	mock_db.db.execute.assert_called_with(db_query_value)
-    	self.assertEqual(results_found,expected_found)
-    	self.assertEqual(no_results,{})
+    def test_gene_id_name_dict(self, mock_db):
+        no_gene_names = []
+        self.assertEqual("", get_gene_id_name_dict(
+            species_id="fregb343bui43g4", gene_name_list=no_gene_names))
+        gene_name_list = ["GH1", "GH2", "GH3"]
+        mock_db.db.execute.return_value.fetchall.side_effect = [[], [("fsdf43-fseferger-f22", "GH1"), ("1sdf43-fsewferger-f22", "GH2"),
+                                                                     ("fwdj43-fstferger-f22", "GH3")]]
+        no_results = get_gene_id_name_dict(
+            species_id="ret3-32rf32", gene_name_list=gene_name_list)
+        results_found = get_gene_id_name_dict(
+            species_id="ret3-32rf32", gene_name_list=gene_name_list)
+        expected_found = {'GH1': 'fsdf43-fseferger-f22',
+                          'GH2': '1sdf43-fsewferger-f22', 'GH3': 'fwdj43-fstferger-f22'}
+        db_query_value = """
+                SELECT
+                        geneId, geneSymbol
+                FROM
+                        GeneList
+                WHERE
+                        SpeciesId = ret3-32rf32 AND geneSymbol in ('GH1','GH2','GH3')
+            """
+        mock_db.db.execute.assert_called_with(db_query_value)
+        self.assertEqual(results_found, expected_found)
+        self.assertEqual(no_results, {})
 
     @mock.patch("wqflask.snp_browser.snp_browser.g")
-    def test_check_if_in_gene(self,mock_db):
-    	mock_db.db.execute.return_value.fetchone.side_effect=[("fsdf-232sdf-sdf","GHA"),""]
-    	results_found=check_if_in_gene(species_id="517d729f-aa13-4413-a885-40a3f7ff768a",chr="CH1",mb=12.09)
-    	db_query_value="SELECT geneId, geneSymbol\n                   FROM GeneList\n                   WHERE SpeciesId = 517d729f-aa13-4413-a885-40a3f7ff768a AND chromosome = 'CH1' AND\n                        (txStart < 12.09 AND txEnd > 12.09); "
-    	gene_not_found=check_if_in_gene(species_id="517d729f-aa13-4413-a885-40a3f7ff768a",chr="CH1",mb=12.09)
-    	mock_db.db.execute.assert_called_with(db_query_value)
-    	self.assertEqual(gene_not_found,"")
+    def test_check_if_in_gene(self, mock_db):
+        mock_db.db.execute.return_value.fetchone.side_effect = [
+            ("fsdf-232sdf-sdf", "GHA"), ""]
+        results_found = check_if_in_gene(
+            species_id="517d729f-aa13-4413-a885-40a3f7ff768a", chr="CH1", mb=12.09)
+        db_query_value = """SELECT geneId, geneSymbol
+                   FROM GeneList
+                   WHERE SpeciesId = 517d729f-aa13-4413-a885-40a3f7ff768a AND chromosome = 'CH1' AND
+                        (txStart < 12.09 AND txEnd > 12.09); """
+        gene_not_found = check_if_in_gene(
+            species_id="517d729f-aa13-4413-a885-40a3f7ff768a", chr="CH1", mb=12.09)
+        mock_db.db.execute.assert_called_with(db_query_value)
+        self.assertEqual(gene_not_found, "")
 
     @mock.patch("wqflask.snp_browser.snp_browser.g")
-    def test_get_browser_sample_lists(self,mock_db):
-    	mock_db.db.execute.return_value.fetchall.return_value=[]
-
-    	results=get_browser_sample_lists(species_id="12")
-    	self.assertEqual(results, {'mouse': [], 'rat': []})
-
-
-
-
-
-
-
- 
-
-
-
-
-
-
-
+    def test_get_browser_sample_lists(self, mock_db):
+        mock_db.db.execute.return_value.fetchall.return_value = []
 
+        results = get_browser_sample_lists(species_id="12")
+        self.assertEqual(results, {'mouse': [], 'rat': []})
-- 
cgit v1.2.3


From 47d6c4d9c39b8a506f65ce86a11ff394be76f3d0 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Thu, 17 Dec 2020 20:59:54 +0300
Subject: replace scroller/css/scroller.dataTables.min.css with
 scrollerStyle/css/scroller.dataTables.min.css

---
 wqflask/wqflask/templates/search_result_page.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index 765c4ab8..411a6628 100644
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -3,7 +3,7 @@
 {% block css %}
     <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" />
     <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='fontawesome/css/font-awesome.min.css') }}" />
-    <link rel="stylesheet" type="text/css" href="{{ url_for('js', filename='DataTablesExtensions/scroller/css/scroller.dataTables.min.css') }}">
+    <link rel="stylesheet" type="text/css" href="{{ url_for('js', filename='DataTablesExtensions/scrollerStyle/css/scroller.dataTables.min.css') }}">
     <link rel="stylesheet" type="text/css" href="{{ url_for('js', filename='DataTablesExtensions/buttonStyles/css/buttons.dataTables.min.css') }}">
     <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">
     <link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" />
-- 
cgit v1.2.3


From 6781bda17452ee5b948fd0deb217df464a4a7202 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Thu, 17 Dec 2020 21:12:26 +0300
Subject: add scroller.dataTables.min.css and dataTables.scroller.min.js to
 mechanical rob

---
 test/requests/link_checker.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/requests/link_checker.py b/test/requests/link_checker.py
index bc3b5861..f162ec84 100644
--- a/test/requests/link_checker.py
+++ b/test/requests/link_checker.py
@@ -103,9 +103,9 @@ def check_packaged_js_files(args_obj, parser):
         "/js/DataTablesExtensions/colResize/dataTables.colResize.js",
         "/js/DataTablesExtensions/colReorder/js/dataTables.colReorder.js",
         "/js/DataTablesExtensions/buttons/js/buttons.colVis.min.js",
-        "/js/DataTablesExtensions/scroller/js/scroller.dataTables.min.js",
+        "/js/DataTablesExtensions/scroller/js/dataTables.scroller.min.js",
         "/js/DataTables/js/jquery.dataTables.js",
-        "/css/DataTablesExtensions/scroller/css/scroller.dataTables.min.css",
+        "/js/DataTablesExtensions/scrollerStyle/css/scroller.dataTables.min.css",
         # Datatables plugins:
         "/js/DataTablesExtensions/plugins/sorting/natural.js",
         "/js/DataTablesExtensions/plugins/sorting/scientific.js",
-- 
cgit v1.2.3


From b605f52440e84909631b6afdf510a9e513260901 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Wed, 6 Jan 2021 08:21:44 +0300
Subject: fix tests for show_corr_results

---
 wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py b/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
index ffb96dd6..33601990 100644
--- a/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
+++ b/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
@@ -61,6 +61,7 @@ class TestShowCorrResults(unittest.TestCase):
             "pubmed_text": "2016",
             "pubmed_link": "https://www.load",
             "lod_score": "",
+            "mean": "",
             "LRS_location_repr": "BXBS",
             "additive": "",
             "sample_r": 10.5,
@@ -80,7 +81,7 @@ class TestShowCorrResults(unittest.TestCase):
             "sample_p": 10.34
         }
 
-        expected_results = '[{"index": 1, "trait_id": "trait_1", "dataset": "dataset_1", "hmac": "hajsdiau", "abbreviation_display": "T1", "description": "Trait I description", "authors_display": "JM J,JYEW", "additive": "N/A", "pubmed_id": "34n4nn31hn43", "year": "2016", "lod_score": "N/A", "lrs_location": "BXBS", "sample_r": "10.500", "num_overlap": 2, "sample_p": "5.000e+00"}]'
+        expected_results = '[{"index": 1, "trait_id": "trait_1", "dataset": "dataset_1", "hmac": "hajsdiau", "abbreviation_display": "T1", "description": "Trait I description", "mean": "N/A", "authors_display": "JM J,JYEW", "additive": "N/A", "pubmed_id": "34n4nn31hn43", "year": "2016", "lod_score": "N/A", "lrs_location": "BXBS", "sample_r": "10.500", "num_overlap": 2, "sample_p": "5.000e+00"}]'
 
         results1 = generate_corr_json(corr_results=corr_results, this_trait=this_trait,
                                       dataset=dataset, target_dataset=target_dataset, for_api=True)
-- 
cgit v1.2.3


From 4203e9609dcf59fa7369e9e0dde02d0da3c8e32f Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Wed, 6 Jan 2021 08:50:30 +0300
Subject: update tests for snp_browser

---
 .../tests/unit/wqflask/snp_browser/test_snp_browser.py    | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
index 496d228f..7fa96dba 100644
--- a/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
+++ b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
@@ -21,18 +21,25 @@ class TestSnpBrowser(unittest.TestCase):
                          "transcript": "false", "exon": "false", "domain_2": "true", "function": "false", "function_details": "true"}
         strains = {"mouse": ["S1", "S2", "S3", "S4", "S5"], "rat": []}
         expected_results = ([['Index', 'SNP ID', 'Chr', 'Mb', 'Alleles', 'ConScore',
-                              'Domain 1', 'Domain 2', 'Details'], ['S1', 'S2', 'S3', 'S4', 'S5']], 5)
+                              'Domain 1', 'Domain 2', 'Details'], 
+                              ['S1', 'S2', 'S3', 'S4', 'S5']], 5, 
+                              ['index', 'snp_name', 'chr', 'mb_formatted', 'alleles', 
+                              'conservation_score', 'domain_1', 'domain_2',
+                              'function_details', 'S1', 'S2', 'S3', 'S4', 'S5'])
 
         results_with_snp = get_header_list(
             variant_type="SNP", strains=strains, species="Mouse", empty_columns=empty_columns)
         results_with_indel = get_header_list(
             variant_type="InDel", strains=strains, species="rat", empty_columns=[])
         expected_results_with_indel = (
-            ['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start', 
-            'Mb End', 'Strand', 'Size', 'Sequence', 'Source'], 0)
+            ['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start',
+             'Mb End', 'Strand', 'Size', 'Sequence', 'Source'], 0, 
+             ['index', 'indel_name', 'indel_type', 'indel_chr', 'indel_mb_s',
+            'indel_mb_e', 'indel_strand', 'indel_size', 'indel_sequence', 'source_name'])
 
         self.assertEqual(expected_results, results_with_snp)
-        self.assertEqual(results_with_indel, expected_results_with_indel)
+        # self.assertEqual(results_with_indel, expected_results_with_indel)
+        self.assertEqual(expected_results_with_indel, results_with_indel)
 
     @mock.patch("wqflask.snp_browser.snp_browser.g")
     def test_get_gene_id(self, mock_db):
-- 
cgit v1.2.3


From e55aa51937abf03897a20a52dd7dbf3cfc4ac6c8 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Wed, 6 Jan 2021 08:54:47 +0300
Subject: remove comments

---
 wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
index 7fa96dba..ce3e7b83 100644
--- a/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
+++ b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
@@ -38,7 +38,6 @@ class TestSnpBrowser(unittest.TestCase):
             'indel_mb_e', 'indel_strand', 'indel_size', 'indel_sequence', 'source_name'])
 
         self.assertEqual(expected_results, results_with_snp)
-        # self.assertEqual(results_with_indel, expected_results_with_indel)
         self.assertEqual(expected_results_with_indel, results_with_indel)
 
     @mock.patch("wqflask.snp_browser.snp_browser.g")
-- 
cgit v1.2.3


From 7bcc5d1e8111d7c74299c7f017c4a0427f8b4830 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Wed, 6 Jan 2021 11:51:01 -0600
Subject: Changes to the way R/qtl deals with 4-way crosses so it will work
 with new HET3-ITP genotypes

---
 wqflask/wqflask/marker_regression/rqtl_mapping.py | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/wqflask/wqflask/marker_regression/rqtl_mapping.py b/wqflask/wqflask/marker_regression/rqtl_mapping.py
index 0a5758af..4117a0e5 100644
--- a/wqflask/wqflask/marker_regression/rqtl_mapping.py
+++ b/wqflask/wqflask/marker_regression/rqtl_mapping.py
@@ -94,9 +94,6 @@ def run_rqtl_geno(vals, samples, dataset, mapping_scale, method, model, permChec
         ro.r('all_covars <- cbind(marker_covars, trait_covars)')
     else:
         ro.r('all_covars <- marker_covars')
-    #logger.info("Saving");
-    #ro.r('save.image(file = "/home/dannya/gn2-danny/cross.RData")')
-    #logger.info("Saving Done");
     covars = ro.r['all_covars']
     #DEBUG to save the session object to file
     if pair_scan:
@@ -159,7 +156,7 @@ def generate_cross_from_geno(dataset, scale_units):        # TODO: Need to figur
          toskip = which(unlist(lapply(header, function(x){ length(grep("Chr\t", x)) })) == 1)-1                            # Major hack to skip the geno headers
          type <- getGenoCode(header, 'type')
          if(type == '4-way'){
-            genocodes <- c('1','2','3','4')
+            genocodes <- NULL
          } else {
             genocodes <- c(getGenoCode(header, 'mat'), getGenoCode(header, 'het'), getGenoCode(header, 'pat'))             # Get the genotype codes
          }
@@ -174,7 +171,7 @@ def generate_cross_from_geno(dataset, scale_units):        # TODO: Need to figur
          require(qtl)
          if(type == '4-way'){
            cat('Loading in as 4-WAY\n')
-           cross = read.cross(file=out, 'csvr', genotypes=genocodes, crosstype="4way", convertXdata=FALSE)                 # Load the created cross file using R/qtl read.cross
+           cross = read.cross(file=out, 'csvr', genotypes=NULL, crosstype="4way")                                         # Load the created cross file using R/qtl read.cross
          }else if(type == 'f2'){
            cat('Loading in as F2\n')
            cross = read.cross(file=out, 'csvr', genotypes=genocodes, crosstype="f2")                                       # Load the created cross file using R/qtl read.cross
@@ -332,8 +329,6 @@ def add_cofactors(cross, this_dataset, covariates, samples):
                         covar_name_string += '"' + col_name + '", '
                     else:
                         covar_name_string += '"' + col_name + '"'
-
-                logger.info("covar_name_string:" + covar_name_string)
         else:
             col_name = "covar_" + str(i)
             cross = add_phenotype(cross, covar_as_string, col_name)
@@ -343,7 +338,6 @@ def add_cofactors(cross, this_dataset, covariates, samples):
                 covar_name_string += '"' + col_name + '"'
 
     covar_name_string += ")"
-    logger.info("covar_name_string:" + covar_name_string); 
     covars_ob = pull_var("trait_covars", cross, covar_name_string)
     return cross, covars_ob
 
-- 
cgit v1.2.3


From f617bca3f5298454f8944205f84ae77e0c59ca4b Mon Sep 17 00:00:00 2001
From: zsloan
Date: Wed, 6 Jan 2021 11:53:04 -0600
Subject: Added line to views.py to fixes error if the genotype file contains
 samples not listed in the DB

---
 wqflask/wqflask/views.py | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index c136711e..6b706b3f 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -643,8 +643,9 @@ def loading_page():
                         samples = genofile_samples
 
             for sample in samples:
-                if sample_vals_dict[sample] != "x":
-                    n_samples += 1
+                if sample in sample_vals_dict:
+                    if sample_vals_dict[sample] != "x":
+                        n_samples += 1
 
         start_vars['n_samples'] = n_samples
         start_vars['wanted_inputs'] = initial_start_vars['wanted_inputs']
@@ -749,10 +750,9 @@ def mapping_results_page():
                     rendered_template = render_template("mapping_error.html")
                     return rendered_template
             except:
-                rendered_template = render_template("mapping_error.html")
-                return rendered_template
+               rendered_template = render_template("mapping_error.html")
+               return rendered_template
 
-            #if template_vars.mapping_method != "gemma" and template_vars.mapping_method != "plink":
             template_vars.js_data = json.dumps(template_vars.js_data,
                                                     default=json_default_handler,
                                                     indent="   ")
-- 
cgit v1.2.3


From 6c63b869d047daca44ff5facee44833f52b0d861 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 11 Jan 2021 13:49:04 -0600
Subject: Added something to line accounting for certain BXD individual groups
 when building the correlation drop-down

---
 wqflask/wqflask/show_trait/show_trait.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/show_trait/show_trait.py b/wqflask/wqflask/show_trait/show_trait.py
index 4c6dd005..9b4a8fa4 100644
--- a/wqflask/wqflask/show_trait/show_trait.py
+++ b/wqflask/wqflask/show_trait/show_trait.py
@@ -372,7 +372,7 @@ class ShowTrait(object):
 
         # We're checking a string here!
         assert isinstance(this_group, str), "We need a string type thing here"
-        if this_group[:3] == 'BXD' and this_group != "BXD-Longevity":
+        if this_group[:3] == 'BXD' and this_group != "BXD-Longevity" and this_group != "BXD-AE":
             this_group = 'BXD'
 
         if this_group:
-- 
cgit v1.2.3


From 2016470a13945e6bb833d28583de9e0877fe91eb Mon Sep 17 00:00:00 2001
From: zsloan
Date: Mon, 11 Jan 2021 14:21:47 -0600
Subject: Fixed error with JS that adds text to footer showing how long it took
 to render the page

---
 wqflask/wqflask/templates/base.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html
index e368a4be..facebdff 100644
--- a/wqflask/wqflask/templates/base.html
+++ b/wqflask/wqflask/templates/base.html
@@ -264,7 +264,7 @@
     {% endblock %}
 
     <script type="text/javascript">
-     $(window).load(function() {
+     document.addEventListener('DOMContentLoaded', function() {
          let timeToLoad = document.createElement("p");
          timeToLoad.innerHTML = "It took your browser " + ((Date.now() - pageLoadStart)/1000) + " second(s) to render this page";
          document.querySelector("footer .row .col-xs-6").appendChild(timeToLoad);
-- 
cgit v1.2.3


From 3c0715dc52dc583d8a84907a9ba41a799ed3068a Mon Sep 17 00:00:00 2001
From: zsloan
Date: Tue, 12 Jan 2021 11:09:11 -0600
Subject: Added a line that redraws the DataTable, which fixes its initial
 scroll height

---
 wqflask/wqflask/templates/search_result_page.html | 37 ++++++-----------------
 1 file changed, 9 insertions(+), 28 deletions(-)

diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index 411a6628..5fe65c00 100644
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -146,6 +146,7 @@
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='js_alt/md5.min.js') }}"></script>
 
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTables/js/jquery.dataTables.min.js') }}"></script>
+    <script language="javascript" type="text/javascript" src="https://cdn.datatables.net/scroller/2.0.2/js/dataTables.scroller.min.js"></script>
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='jszip/jszip.min.js') }}"></script>
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/plugins/sorting/natural.js') }}"></script>
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/buttons/js/dataTables.buttons.min.js') }}"></script>
@@ -383,36 +384,16 @@
                     }{% endif %}
                 ],
                 "order": [[1, "asc" ]],
-                {% if dataset.type != 'Geno' %}
-                buttons: [
-                    {
-                        extend: 'columnsToggle',
-                        columns: function( idx, data, node ) {
-                          if (idx != 0) {
-                            return true;
-                          } else {
-                            return false;
-                          }
-                        },
-                        postfixButtons: [ 'colvisRestore' ]
-                    }
-                ],
-                'sDom': "Bpitirp",
-                {% else %}
-                'sDom': "pitirp",
-                {% endif %}
-                'iDisplayLength': 500,
-                'deferRender': true,
-                'paging': true,
-                'orderClasses': true,
-                'processing': true,
-                'bServerSide': true,
-                'sAjaxSource': '/search_table'+getParams(window.location.href),
-                'infoCallback': function(settings, start, end, max, total, pre) {
-                  return "Showing " + start + " to " + (start + this.api().data().length - 1) + " of " + total + " entries";
-                }
+                'sDom': "itir",
+                "autoWidth": true,
+                "bSortClasses": false,
+                "scrollY": "100vh",
+                "scroller":  true,
+                "scrollCollapse": true
             } );
             
+            trait_table.draw(); //ZS: This makes the table adjust its height properly on initial load
+
             $('.toggle-vis').on( 'click', function (e) {
               e.preventDefault();
 
-- 
cgit v1.2.3


From b3aba44e452fbfeb9f79c91f94b00061057937a4 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Tue, 12 Jan 2021 17:51:06 -0600
Subject: Fixed issue causing interval mapping to not be displayed correctly

---
 wqflask/wqflask/marker_regression/run_mapping.py | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py
index 891fcc66..38f8c26d 100644
--- a/wqflask/wqflask/marker_regression/run_mapping.py
+++ b/wqflask/wqflask/marker_regression/run_mapping.py
@@ -138,15 +138,15 @@ class RunMapping(object):
             mapping_results_filename = self.dataset.group.name + "_" + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
             self.mapping_results_path = "{}{}.csv".format(webqtlConfig.GENERATED_IMAGE_DIR, mapping_results_filename)
 
-        if start_vars['manhattan_plot']:
-            self.color_scheme = "alternating"
-            if "color_scheme" in start_vars:
-                self.color_scheme = start_vars['color_scheme']
-                if self.color_scheme == "single":
-                    self.manhattan_single_color = start_vars['manhattan_single_color']
-            self.manhattan_plot = True
-        else:
-            self.manhattan_plot = False
+        self.manhattan_plot = False
+        if 'manhattan_plot' in start_vars:
+            if start_vars['manhattan_plot'].lower() != "false":
+                self.color_scheme = "alternating"
+                if "color_scheme" in start_vars:
+                    self.color_scheme = start_vars['color_scheme']
+                    if self.color_scheme == "single":
+                        self.manhattan_single_color = start_vars['manhattan_single_color']
+                self.manhattan_plot = True
 
         self.maf = start_vars['maf'] # Minor allele frequency
         if "use_loco" in start_vars:
-- 
cgit v1.2.3


From 7d97698ca88460c2f66b67ada31085b02cbc9ee4 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Tue, 12 Jan 2021 17:56:52 -0600
Subject: Fixed a bunch fo remaining issues with positioning legend items on
 the right side of the mapping figure

---
 .../marker_regression/display_mapping_results.py   | 87 +++++++++++-----------
 1 file changed, 43 insertions(+), 44 deletions(-)

diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py
index 9f778160..bba08f63 100644
--- a/wqflask/wqflask/marker_regression/display_mapping_results.py
+++ b/wqflask/wqflask/marker_regression/display_mapping_results.py
@@ -860,7 +860,10 @@ class DisplayMappingResults(object):
                            text='%2.1f'%item, font=bootScaleFont, fill=BLACK)
 
         if self.legendChecked:
-            startPosY = 30
+            if hasattr(self.traitList[0], 'chr') and hasattr(self.traitList[0], 'mb'):
+                startPosY = 30
+            else:
+                startPosY = 15
             smallLabelFont = ImageFont.truetype(font=TREBUC_FILE, size=12*fontZoom)
             leftOffset = canvas.size[0] - xRightOffset - 190
             im_drawer.rectangle(
@@ -942,28 +945,6 @@ class DisplayMappingResults(object):
             draw_open_polygon(canvas, xy=traitPixel, outline=BLACK,
                               fill=self.TRANSCRIPT_LOCATION_COLOR)
 
-        if self.legendChecked:
-            startPosY = 15
-            nCol = 2
-            smallLabelFont = ImageFont.truetype(font=TREBUC_FILE, size=12*fontZoom)
-            if self.manhattan_plot:
-                leftOffset = xLeftOffset
-            else:
-                leftOffset = xLeftOffset+(nCol-1)*200*fontZoom
-            draw_open_polygon(
-                canvas,
-                xy=(
-                    (leftOffset+7, startPosY-7),
-                    (leftOffset, startPosY+7),
-                    (leftOffset+14, startPosY+7)),
-                outline=BLACK, fill=self.TRANSCRIPT_LOCATION_COLOR
-            )
-            TEXT_Y_DISPLACEMENT = -8
-            im_drawer.text(
-                text="Sequence Site",
-                xy=(leftOffset+15, startPosY+TEXT_Y_DISPLACEMENT), font=smallLabelFont,
-                fill=self.TOP_RIGHT_INFO_COLOR)
-
     def drawSNPTrackNew(self, canvas, offset= (40, 120, 80, 10), zoom = 1, startMb = None, endMb = None):
         im_drawer = ImageDraw.Draw(canvas)
         if self.plotScale != 'physic' or self.selectedChr == -1 or not self.diffCol:
@@ -1060,17 +1041,38 @@ class DisplayMappingResults(object):
         labelFont=ImageFont.truetype(font=TREBUC_FILE, size=12*fontZoom)
         startPosY = 15
         stepPosY = 12*fontZoom
+
+        startPosX = canvas.size[0] - xRightOffset - 415
+        if hasattr(self.traitList[0], 'chr') and hasattr(self.traitList[0], 'mb'):
+            startPosY = 15
+            nCol = 2
+            smallLabelFont = ImageFont.truetype(font=TREBUC_FILE, size=12*fontZoom)
+
+            leftOffset = canvas.size[0] - xRightOffset - 190
+            draw_open_polygon(
+                canvas,
+                xy=(
+                    (leftOffset + 6, startPosY-7),
+                    (leftOffset - 1, startPosY+7),
+                    (leftOffset + 13, startPosY+7)),
+                outline=BLACK, fill=self.TRANSCRIPT_LOCATION_COLOR
+            )
+            TEXT_Y_DISPLACEMENT = -8
+            im_drawer.text(
+                text="Sequence Site",
+                xy=(leftOffset + 20, startPosY+TEXT_Y_DISPLACEMENT), font=smallLabelFont,
+                fill=self.TOP_RIGHT_INFO_COLOR)
+
         if self.manhattan_plot != True:
             im_drawer.line(
-                xy=((xLeftOffset, startPosY), (xLeftOffset+32, startPosY)),
+                xy=((startPosX, startPosY), (startPosX+32, startPosY)),
                 fill=self.LRS_COLOR, width=2)
             im_drawer.text(
-                text=self.LRS_LOD, xy=(xLeftOffset+40, startPosY+TEXT_Y_DISPLACEMENT),
+                text=self.LRS_LOD, xy=(startPosX+40, startPosY+TEXT_Y_DISPLACEMENT),
                 font=labelFont, fill=BLACK)
             startPosY += stepPosY
 
         if self.additiveChecked:
-            startPosX = canvas.size[0] - xRightOffset - 400
             im_drawer.line(
                 xy=((startPosX, startPosY), (startPosX+17, startPosY)),
                 fill=self.ADDITIVE_COLOR_POSITIVE, width=2)
@@ -1080,10 +1082,9 @@ class DisplayMappingResults(object):
             im_drawer.text(
                 text='Additive Effect', xy=(startPosX+40, startPosY+TEXT_Y_DISPLACEMENT),
                 font=labelFont, fill=BLACK)
+            startPosY += stepPosY
 
         if self.genotype.type == 'intercross' and self.dominanceChecked:
-            startPosX = canvas.size[0] - xRightOffset - 400
-            startPosY += stepPosY
             im_drawer.line(
                 xy=((startPosX, startPosY), (startPosX+17, startPosY)),
                 fill=self.DOMINANCE_COLOR_POSITIVE, width=4)
@@ -1093,44 +1094,42 @@ class DisplayMappingResults(object):
             im_drawer.text(
                 text='Dominance Effect', xy=(startPosX+42, startPosY+5),
                 font=labelFont, fill=BLACK)
+            startPosY += stepPosY
 
         if self.haplotypeAnalystChecked:
-            startPosY += stepPosY
-            startPosX = canvas.size[0] - xRightOffset - 400
             im_drawer.line(
-                xy=((startPosX, startPosY), (startPosX+17, startPosY)),
+                xy=((startPosX-34, startPosY), (startPosX-17, startPosY)),
                 fill=self.HAPLOTYPE_POSITIVE, width=4)
             im_drawer.line(
-                xy=((startPosX+18, startPosY), (startPosX+35, startPosY)),
+                xy=((startPosX-17, startPosY), (startPosX, startPosY)),
                 fill=self.HAPLOTYPE_NEGATIVE, width=4)
             im_drawer.line(
-                xy=((startPosX+36, startPosY), (startPosX+53, startPosY)),
+                xy=((startPosX, startPosY), (startPosX+17, startPosY)),
                 fill=self.HAPLOTYPE_HETEROZYGOUS, width=4)
             im_drawer.line(
-                xy=((startPosX+54, startPosY), (startPosX+67, startPosY)),
+                xy=((startPosX+17, startPosY), (startPosX+34, startPosY)),
                 fill=self.HAPLOTYPE_RECOMBINATION, width=4)
             im_drawer.text(
                 text='Haplotypes (Pat, Mat, Het, Unk)',
-                xy=(startPosX+76, startPosY+5), font=labelFont, fill=BLACK)
+                xy=(startPosX+41, startPosY+TEXT_Y_DISPLACEMENT), font=labelFont, fill=BLACK)
+            startPosY += stepPosY
 
         if self.permChecked and self.nperm > 0:
-            startPosY += stepPosY
-            if self.bootChecked and not self.multipleInterval:
-                startPosX = canvas.size[0] - xRightOffset - 400
-            else:
-                startPosX = canvas.size[0] - xRightOffset - 190
+            thisStartX = startPosX
+            if self.multipleInterval and not self.bootChecked:
+                thisStartX = canvas.size[0] - xRightOffset - 205
             im_drawer.line(
-                xy=((startPosX, startPosY), ( startPosX + 32, startPosY)),
+                xy=((thisStartX, startPosY), ( startPosX + 32, startPosY)),
                 fill=self.SIGNIFICANT_COLOR, width=self.SIGNIFICANT_WIDTH)
             im_drawer.line(
-                xy=((startPosX, startPosY + stepPosY), ( startPosX + 32, startPosY + stepPosY)),
+                xy=((thisStartX, startPosY + stepPosY), ( startPosX + 32, startPosY + stepPosY)),
                 fill=self.SUGGESTIVE_COLOR, width=self.SUGGESTIVE_WIDTH)
             im_drawer.text(
                 text='Significant %s = %2.2f' % (self.LRS_LOD, self.significant),
-                xy=(startPosX+42, startPosY+TEXT_Y_DISPLACEMENT), font=labelFont, fill=BLACK)
+                xy=(thisStartX+40, startPosY+TEXT_Y_DISPLACEMENT), font=labelFont, fill=BLACK)
             im_drawer.text(
                 text='Suggestive %s = %2.2f' % (self.LRS_LOD, self.suggestive),
-                xy=(startPosX+42, startPosY + TEXT_Y_DISPLACEMENT +stepPosY), font=labelFont,
+                xy=(thisStartX+40, startPosY + TEXT_Y_DISPLACEMENT +stepPosY), font=labelFont,
                 fill=BLACK)
 
         labelFont = ImageFont.truetype(font=VERDANA_FILE, size=12*fontZoom)
-- 
cgit v1.2.3


From 4e8a9dfabf3580f1dd2cfeaa407bae726e7659a0 Mon Sep 17 00:00:00 2001
From: robwwilliams
Date: Wed, 13 Jan 2021 11:56:32 -0600
Subject: Just some tweaks to first paragrfaph

---
 README.md | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/README.md b/README.md
index cd35defb..bfb16ddb 100644
--- a/README.md
+++ b/README.md
@@ -3,13 +3,12 @@
 
 # GeneNetwork
 
-This repository contains the source code for the GeneNetwork (GN)
-server http://gn2.genenetwork.org/ (version 2 aka GN2). GN is a Web
-2.0 style framework with included tools for doing genetics online
-using high-throughput data. GN is used for a wide range of studies. An
-exhaustive list of publications mentioning GN and its previous
-incarnation WebQTL can be found
-[here](http://www.genenetwork.org/reference.html).
+This repository contains the current source code for GeneNetwork (GN)
+(https://www.genenetwork.org/ (version 2). GN2 is a Web
+2.0-style framework that includes data and computational tools for online genetics and genomic analysis of 
+many different populations and many types of molecular, cellular, and physiological data. 
+The system is used by scientists and clinians in the field of precision health care and systems genetics.
+GN and its predecessors have been in operation since Jan 1994, making it one of the longest-lived web services in biomedical research (https://en.wikipedia.org/wiki/GeneNetwork, and see a partial list of publications using GN and its predecessor, WebQTL (https://genenetwork.org/references/).
 
 ## Install
 
-- 
cgit v1.2.3


From ac28594a4eba9c73b836170ef81beb93f40a11d6 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Wed, 13 Jan 2021 14:18:02 -0600
Subject: The Scroller CSS was removed because it forces all row text onto one
 line; Scroller still seems to function fine without it, which is a little
 strange

---
 wqflask/wqflask/templates/search_result_page.html | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index 5fe65c00..b8f89121 100644
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -3,7 +3,6 @@
 {% block css %}
     <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" />
     <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='fontawesome/css/font-awesome.min.css') }}" />
-    <link rel="stylesheet" type="text/css" href="{{ url_for('js', filename='DataTablesExtensions/scrollerStyle/css/scroller.dataTables.min.css') }}">
     <link rel="stylesheet" type="text/css" href="{{ url_for('js', filename='DataTablesExtensions/buttonStyles/css/buttons.dataTables.min.css') }}">
     <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">
     <link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" />
@@ -125,7 +124,7 @@
             {% endif %}
           </div>
           {% endif %}
-          <div id="table_container" {% if dataset.type == 'ProbeSet' or dataset.type == 'Publish' %}style="min-width: 1500px;"{% endif %}>
+          <div id="table_container" {% if dataset.type == 'ProbeSet' or dataset.type == 'Publish' %}style="min-width: 1500px; max-width:100%;"{% endif %}>
             <table class="table-hover table-striped cell-border" id='trait_table' style="float: left; width: {% if dataset.type == 'Geno' %}380px{% else %}100%{% endif %};">
                 <tbody>
                  <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td>
@@ -310,7 +309,6 @@
                     {
                       'title': "Description",
                       'type': "natural",
-                      'width': "500px",
                       'data': null,
                       'render': function(data, type, row, meta) {
 			                  try {
-- 
cgit v1.2.3


From 4a67b437215b04a089449f93cfa9ebcaed5640dd Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 14 Jan 2021 14:22:02 -0600
Subject: Re-added some code that was accidentally removed that was needed for
 adding cofactors to mapping

---
 wqflask/wqflask/static/new/javascript/show_trait.js | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 2ec9d6d5..1c8e328d 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -95,6 +95,14 @@ $('#add_to_collection').click(add);
 sample_lists = js_data.sample_lists;
 sample_group_types = js_data.sample_group_types;
 
+$(".select_covariates").click(function () {
+  open_covariate_selection();
+});
+$(".remove_covariates").click(function () {
+  $("input[name=covariates]").val("")
+  $(".selected-covariates").val("")
+});
+
 open_trait_selection = function() {
   return $('#collections_holder').load('/collections/list?color_by_trait #collections_list', (function(_this) {
     return function() {
-- 
cgit v1.2.3


From aa5d3d6bfedd7df8c6e35465d60bba1c11c8fa79 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 14 Jan 2021 14:22:47 -0600
Subject: Added transform text to mapping figure and fixed an issue where
 cofactors weren't appearing in the metadata

---
 .../marker_regression/display_mapping_results.py   | 46 +++++++++++++++++-----
 1 file changed, 37 insertions(+), 9 deletions(-)

diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py
index 9f1b050d..0de9b9a1 100644
--- a/wqflask/wqflask/marker_regression/display_mapping_results.py
+++ b/wqflask/wqflask/marker_regression/display_mapping_results.py
@@ -636,7 +636,7 @@ class DisplayMappingResults(object):
             btminfo.append(HtmlGenWrapper.create_br_tag())
             btminfo.append('Mapping using genotype data as a trait will result in infinity LRS at one locus. In order to display the result properly, all LRSs higher than 100 are capped at 100.')
 
-    def plotIntMapping(self, canvas, offset= (80, 120, 20, 100), zoom = 1, startMb = None, endMb = None, showLocusForm = ""):
+    def plotIntMapping(self, canvas, offset= (80, 120, 90, 100), zoom = 1, startMb = None, endMb = None, showLocusForm = ""):
         im_drawer = ImageDraw.Draw(canvas)
         #calculating margins
         xLeftOffset, xRightOffset, yTopOffset, yBottomOffset = offset
@@ -644,10 +644,11 @@ class DisplayMappingResults(object):
             yTopOffset = max(90, yTopOffset)
         else:
             if self.legendChecked:
+                yTopOffset += 10
                 if self.covariates != "" and self.controlLocus and self.doControl != "false":
-                    yTopOffset = max(120, yTopOffset)
-                else:
-                    yTopOffset = max(100, yTopOffset)
+                    yTopOffset += 20
+                if len(self.transform) > 0:
+                    yTopOffset += 5
             else:
                 pass
 
@@ -1131,6 +1132,7 @@ class DisplayMappingResults(object):
 
         labelFont = ImageFont.truetype(font=VERDANA_FILE, size=12*fontZoom)
         labelColor = BLACK
+
         if self.dataset.type == "Publish" or self.dataset.type == "Geno":
             dataset_label = self.dataset.fullname
         else:
@@ -1172,6 +1174,7 @@ class DisplayMappingResults(object):
             else:
                 string3 += 'no control for other QTLs'
 
+        y_constant = 10
         if self.this_trait.name:
             if self.selectedChr == -1:
                 identification = "Mapping on All Chromosomes for "
@@ -1197,23 +1200,48 @@ class DisplayMappingResults(object):
                 im_drawer.textsize(string2, font=labelFont)[0])
             im_drawer.text(
                 text=identification,
-                xy=(canvas.size[0] - xRightOffset-d, 20*fontZoom), font=labelFont,
+                xy=(canvas.size[0] - xRightOffset-d, y_constant*fontZoom), font=labelFont,
                 fill=labelColor)
+            y_constant += 15
         else:
             d = 4+ max(
                 im_drawer.textsize(string1, font=labelFont)[0],
                 im_drawer.textsize(string2, font=labelFont)[0])
+
+        if len(self.transform) > 0:
+            transform_text = "Transform - "
+            if self.transform == "qnorm":
+                transform_text += "Quantile Normalized"
+            elif self.transform == "log2" or self.transform == "log10":
+                transform_text += self.transform.capitalize()
+            elif self.transform == "sqrt":
+                transform_text += "Square Root"
+            elif self.transform == "zscore":
+                transform_text += "Z-Score"
+            elif self.transform == "invert":
+                transform_text += "Invert +/-"
+
+            im_drawer.text(
+                text=transform_text, xy=(canvas.size[0] - xRightOffset-d, y_constant*fontZoom),
+                font=labelFont, fill=labelColor)
+            y_constant += 15
         im_drawer.text(
-            text=string1, xy=(canvas.size[0] - xRightOffset-d, 35*fontZoom),
+            text=string1, xy=(canvas.size[0] - xRightOffset-d, y_constant*fontZoom),
             font=labelFont, fill=labelColor)
+        y_constant += 15
         im_drawer.text(
-            text=string2, xy=(canvas.size[0] - xRightOffset-d, 50*fontZoom),
+            text=string2, xy=(canvas.size[0] - xRightOffset-d, y_constant*fontZoom),
             font=labelFont, fill=labelColor)
+        y_constant += 15
         if string3 != '':
             im_drawer.text(
-                text=string3, xy=(canvas.size[0] - xRightOffset-d, 65*fontZoom),
+                text=string3, xy=(canvas.size[0] - xRightOffset-d, y_constant*fontZoom),
                 font=labelFont, fill=labelColor)
-
+            y_constant += 15
+            if string4 != '':
+                im_drawer.text(
+                    text=string4, xy=(canvas.size[0] - xRightOffset-d, y_constant*fontZoom),
+                    font=labelFont, fill=labelColor)
 
     def drawGeneBand(self, canvas, gifmap, plotXScale, offset= (40, 120, 80, 10), zoom = 1, startMb = None, endMb = None):
         im_drawer = ImageDraw.Draw(canvas)
-- 
cgit v1.2.3


From 355e5337330f57ee173aaf309805ca1b0ec0503c Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 14 Jan 2021 15:35:35 -0600
Subject: Fixed mistake where the mapping figure Transform text didn't have its
 X position set correctly

---
 wqflask/wqflask/marker_regression/display_mapping_results.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py
index 864f3264..4df56190 100644
--- a/wqflask/wqflask/marker_regression/display_mapping_results.py
+++ b/wqflask/wqflask/marker_regression/display_mapping_results.py
@@ -1223,7 +1223,7 @@ class DisplayMappingResults(object):
                 transform_text += "Invert +/-"
 
             im_drawer.text(
-                text=transform_text, xy=(canvas.size[0] - xRightOffset-d, y_constant*fontZoom),
+                text=transform_text, xy=(xLeftOffset, y_constant*fontZoom),
                 font=labelFont, fill=labelColor)
             y_constant += 15
         im_drawer.text(
-- 
cgit v1.2.3


From 0bac313ba6a6c4cf04acf230641cc4208a386275 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 14 Jan 2021 15:53:53 -0600
Subject: Added some lines that check if salt is already bytes and convert it
 if necessary (this is caused by salt being passed to a function as bytes when
 an account is registered but being passed as a string when logging in)

---
 wqflask/wqflask/pbkdf2.py     | 4 ++--
 wqflask/wqflask/user_login.py | 6 +++++-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/wqflask/wqflask/pbkdf2.py b/wqflask/wqflask/pbkdf2.py
index aea5b06c..6346df03 100644
--- a/wqflask/wqflask/pbkdf2.py
+++ b/wqflask/wqflask/pbkdf2.py
@@ -2,15 +2,15 @@ import hashlib
 
 from werkzeug.security import safe_str_cmp as ssc
 
-
 # Replace this because it just wraps around Python3's internal
 # functions. Added this during migration.
 def pbkdf2_hex(data, salt, iterations=1000, keylen=24, hashfunc="sha1"):
     """Wrapper function of python's hashlib.pbkdf2_hmac.
     """
+
     dk = hashlib.pbkdf2_hmac(hashfunc,
                              bytes(data, "utf-8"),  # password
-                             bytes(salt, "utf-8"),  # salt
+                             salt,
                              iterations,
                              keylen)
     return dk.hex()
diff --git a/wqflask/wqflask/user_login.py b/wqflask/wqflask/user_login.py
index bc608e84..041f1f11 100644
--- a/wqflask/wqflask/user_login.py
+++ b/wqflask/wqflask/user_login.py
@@ -39,8 +39,12 @@ def basic_info():
 
 
 def encode_password(pass_gen_fields, unencrypted_password):
+    if isinstance(pass_gen_fields['salt'], bytes):
+        salt = pass_gen_fields['salt']
+    else:
+        salt = bytes(pass_gen_fields['salt'], "utf-8")
     encrypted_password = pbkdf2.pbkdf2_hex(str(unencrypted_password), 
-                                           pass_gen_fields['salt'], 
+                                           salt,
                                            pass_gen_fields['iterations'], 
                                            pass_gen_fields['keylength'], 
                                            pass_gen_fields['hashfunc'])
-- 
cgit v1.2.3


From db31d53421c033a9907d2c67bc8a0c3c911b5402 Mon Sep 17 00:00:00 2001
From: Alexanderkabui
Date: Thu, 14 Jan 2021 21:13:01 +0300
Subject: resize image in facilities page

---
 wqflask/wqflask/templates/facilities.html | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/wqflask/wqflask/templates/facilities.html b/wqflask/wqflask/templates/facilities.html
index 56b127f9..dc8d0ded 100644
--- a/wqflask/wqflask/templates/facilities.html
+++ b/wqflask/wqflask/templates/facilities.html
@@ -4,6 +4,14 @@
 
 {% block css %}
 <link rel="stylesheet" type="text/css" href="/static/new/css/markdown.css" />
+
+<style>
+	 img[src="https://github.com/genenetwork/gn-docs/raw/master/general/help/octopus.jpg"] {
+    width:100%;
+    margin:20px 0px;
+}
+</style>
+
 {% endblock %}
 
 {% block content %}
-- 
cgit v1.2.3


From c228aff0cc9480f7b9ee46e54c9fef0f46299a3d Mon Sep 17 00:00:00 2001
From: zsloan
Date: Sun, 17 Jan 2021 14:57:52 -0600
Subject: Set default description to avoid error in situations where
 description is None

---
 wqflask/wqflask/search_results.py | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/wqflask/wqflask/search_results.py b/wqflask/wqflask/search_results.py
index c4ea2921..9e8001cf 100644
--- a/wqflask/wqflask/search_results.py
+++ b/wqflask/wqflask/search_results.py
@@ -120,7 +120,9 @@ class SearchResultPage(object):
                 trait_dict['hmac'] = hmac.data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name))
                 if this_trait.dataset.type == "ProbeSet":
                     trait_dict['symbol'] = this_trait.symbol
-                    trait_dict['description'] = this_trait.description_display
+                    trait_dict['description'] = "N/A"
+                    if this_trait.description_display:
+                        trait_dict['description'] = this_trait.description_display
                     trait_dict['location'] = this_trait.location_repr
                     trait_dict['mean'] = "N/A"
                     trait_dict['additive'] = "N/A"
@@ -136,7 +138,9 @@ class SearchResultPage(object):
                 elif this_trait.dataset.type == "Geno":
                     trait_dict['location'] = this_trait.location_repr
                 elif this_trait.dataset.type == "Publish":
-                    trait_dict['description'] = this_trait.description_display
+                    trait_dict['description'] = "N/A"
+                    if this_trait.description_display:
+                        trait_dict['description'] = this_trait.description_display
                     trait_dict['authors'] = this_trait.authors
                     trait_dict['pubmed_id'] = "N/A"
                     if this_trait.pubmed_id:
-- 
cgit v1.2.3


From 715d9137038887c6654a14d22dc0512bb01aaf86 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 17 Jan 2021 08:51:06 -0600
Subject: modify the main query in gene global search to add locus chr, locus
 mb and optimize the speed of query

---
 wqflask/wqflask/gsearch.py | 37 ++++++++++++++++++++++---------------
 1 file changed, 22 insertions(+), 15 deletions(-)

diff --git a/wqflask/wqflask/gsearch.py b/wqflask/wqflask/gsearch.py
index 9e46c0c5..6ff57563 100644
--- a/wqflask/wqflask/gsearch.py
+++ b/wqflask/wqflask/gsearch.py
@@ -1,4 +1,6 @@
 import json
+import datetime as dt
+from types import SimpleNamespace
 
 from flask import Flask, g
 from base.data_set import create_dataset
@@ -9,8 +11,9 @@ from base import webqtlConfig
 
 from utility import hmac
 
-from utility.type_checking import is_float, is_int, is_str, get_float, get_int, get_string
 from utility.benchmark import Bench
+from utility.authentication_tools import check_resource_availability
+from utility.type_checking import is_float, is_int, is_str, get_float, get_int, get_string
 
 from utility.logger import getLogger
 logger = getLogger(__name__)
@@ -42,15 +45,19 @@ class GSearch(object):
                 ProbeSetXRef.LRS AS lrs,
                 ProbeSetXRef.`Locus` AS locus,
                 ProbeSetXRef.`pValue` AS pvalue,
-                ProbeSetXRef.`additive` AS additive
-                FROM Species, InbredSet, ProbeSetXRef, ProbeSet, ProbeFreeze, ProbeSetFreeze, Tissue
-                WHERE InbredSet.`SpeciesId`=Species.`Id`
-                AND ProbeFreeze.InbredSetId=InbredSet.`Id`
-                AND ProbeFreeze.`TissueId`=Tissue.`Id`
-                AND ProbeSetFreeze.ProbeFreezeId=ProbeFreeze.Id
-                AND ( MATCH (ProbeSet.Name,ProbeSet.description,ProbeSet.symbol,alias,GenbankId, UniGeneId, Probe_Target_Description) AGAINST ('%s' IN BOOLEAN MODE) )
-                AND ProbeSet.Id = ProbeSetXRef.ProbeSetId
-                AND ProbeSetXRef.ProbeSetFreezeId=ProbeSetFreeze.Id
+                ProbeSetXRef.`additive` AS additive,
+                ProbeSetFreeze.Id AS probesetfreeze_id,
+                Geno.Chr as geno_chr,
+                Geno.Mb as geno_mb
+                FROM Species 
+                INNER JOIN InbredSet ON InbredSet.`SpeciesId`=Species.`Id` 
+                INNER JOIN ProbeFreeze ON ProbeFreeze.InbredSetId=InbredSet.`Id` 
+                INNER JOIN Tissue ON ProbeFreeze.`TissueId`=Tissue.`Id` 
+                INNER JOIN ProbeSetFreeze ON ProbeSetFreeze.ProbeFreezeId=ProbeFreeze.Id 
+                INNER JOIN ProbeSetXRef ON ProbeSetXRef.ProbeSetFreezeId=ProbeSetFreeze.Id 
+                INNER JOIN ProbeSet ON ProbeSet.Id = ProbeSetXRef.ProbeSetId 
+                LEFT JOIN Geno ON ProbeSetXRef.Locus = Geno.Name AND Geno.SpeciesId = Species.Id
+                WHERE ( MATCH (ProbeSet.Name,ProbeSet.description,ProbeSet.symbol,ProbeSet.alias,ProbeSet.GenbankId, ProbeSet.UniGeneId, ProbeSet.Probe_Target_Description) AGAINST ('%s' IN BOOLEAN MODE) )
                 AND ProbeSetFreeze.confidentiality < 1
                 AND ProbeSetFreeze.public > 0
                 ORDER BY species_name, inbredset_name, tissue_name, probesetfreeze_name, probeset_name
@@ -90,16 +97,16 @@ class GSearch(object):
                     this_trait['additive'] = "N/A"
                     if line[14] != "" and line[14] != None:
                         this_trait['additive'] = '%.3f' % line[14]
+                    this_trait['dataset_id'] = line[15]
+                    this_trait['locus_chr'] = line[16]
+                    this_trait['locus_mb'] = line[17]
 
                     #dataset = create_dataset(line[3], "ProbeSet", get_samplelist=False)
                     #trait_id = line[4]
                     #with Bench("Building trait object"):
-                    trait_ob = create_trait(dataset_name=this_trait['dataset'], name=this_trait['name'], get_qtl_info=True, get_sample_info=False)
-                    if not trait_ob:
-                        continue
                     max_lrs_text = "N/A"
-                    if trait_ob.locus_chr != "" and trait_ob.locus_mb != "":
-                        max_lrs_text = "Chr" + str(trait_ob.locus_chr) + ": " + str(trait_ob.locus_mb)
+                    if this_trait['locus_chr'] != None and this_trait['locus_mb'] != None:
+                        max_lrs_text = "Chr" + str(this_trait['locus_chr']) + ": " + str(this_trait['locus_mb'])
                     this_trait['max_lrs_text'] = max_lrs_text
 
                     trait_list.append(this_trait)
-- 
cgit v1.2.3


From 6749974cccdf10fc300c4265720dfd147db88989 Mon Sep 17 00:00:00 2001
From: uditgulati
Date: Sun, 17 Jan 2021 08:57:12 -0600
Subject: add dataset object creation, permission check in global search code
 itself which takes the load off creating Trait object

---
 wqflask/wqflask/gsearch.py | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/wqflask/wqflask/gsearch.py b/wqflask/wqflask/gsearch.py
index 6ff57563..2b8d4bc1 100644
--- a/wqflask/wqflask/gsearch.py
+++ b/wqflask/wqflask/gsearch.py
@@ -68,6 +68,7 @@ class GSearch(object):
                 re = g.db.execute(sql).fetchall()
 
             trait_list = []
+            dataset_to_permissions = {}
             with Bench("Creating trait objects"):
                 for i, line in enumerate(re):
                     this_trait = {}
@@ -101,9 +102,15 @@ class GSearch(object):
                     this_trait['locus_chr'] = line[16]
                     this_trait['locus_mb'] = line[17]
 
-                    #dataset = create_dataset(line[3], "ProbeSet", get_samplelist=False)
-                    #trait_id = line[4]
-                    #with Bench("Building trait object"):
+                    dataset_ob = SimpleNamespace(id=this_trait["dataset_id"], type="ProbeSet",species=this_trait["species"])
+                    if dataset_ob.id not in dataset_to_permissions:
+                        permissions = check_resource_availability(dataset_ob)
+                        dataset_to_permissions[dataset_ob.id] = permissions
+                    else:
+                        pemissions = dataset_to_permissions[dataset_ob.id]
+                    if "view" not in permissions['data']:
+                        continue
+
                     max_lrs_text = "N/A"
                     if this_trait['locus_chr'] != None and this_trait['locus_mb'] != None:
                         max_lrs_text = "Chr" + str(this_trait['locus_chr']) + ": " + str(this_trait['locus_mb'])
-- 
cgit v1.2.3


From 5187e582721ddfbb1e864378823f2685748bf5f2 Mon Sep 17 00:00:00 2001
From: BonfaceKilz
Date: Mon, 18 Jan 2021 11:15:33 +0300
Subject: Pass salt as bytes when testing pbkdf2_hex

* wqflask/tests/unit/wqflask/test_pbkdf2.py (test_pbkdf2_hex): Make
password salt bytes. Breaking change introduced in 0bac313ba.
---
 wqflask/tests/unit/wqflask/test_pbkdf2.py | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/wqflask/tests/unit/wqflask/test_pbkdf2.py b/wqflask/tests/unit/wqflask/test_pbkdf2.py
index a33fbd4f..7ad6c83e 100644
--- a/wqflask/tests/unit/wqflask/test_pbkdf2.py
+++ b/wqflask/tests/unit/wqflask/test_pbkdf2.py
@@ -11,43 +11,43 @@ class TestPbkdf2(unittest.TestCase):
         """
 
         for password, salt, iterations, keylen, expected_value in [
-                ('password', 'salt', 1, 20,
+                ('password', b'salt', 1, 20,
                  '0c60c80f961f0e71f3a9b524af6012062fe037a6'),
-                ('password', 'salt', 2, 20,
+                ('password', b'salt', 2, 20,
                  'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'),
-                ('password', 'salt', 4096, 20,
+                ('password', b'salt', 4096, 20,
                  '4b007901b765489abead49d926f721d065a429c1'),
                 ('passwordPASSWORDpassword',
-                 'saltSALTsaltSALTsaltSALTsaltSALTsalt',
+                 b'saltSALTsaltSALTsaltSALTsaltSALTsalt',
                  4096, 25,
                  '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038'),
-                ('pass\x00word', 'sa\x00lt', 4096, 16,
+                ('pass\x00word', b'sa\x00lt', 4096, 16,
                  '56fa6aa75548099dcc37d7f03425e0c3'),
-                ('password', 'ATHENA.MIT.EDUraeburn', 1, 16,
+                ('password', b'ATHENA.MIT.EDUraeburn', 1, 16,
                  'cdedb5281bb2f801565a1122b2563515'),
-                ('password', 'ATHENA.MIT.EDUraeburn', 1, 32,
+                ('password', b'ATHENA.MIT.EDUraeburn', 1, 32,
                  ('cdedb5281bb2f80'
                   '1565a1122b256351'
                   '50ad1f7a04bb9f3a33'
                   '3ecc0e2e1f70837')),
-                ('password', 'ATHENA.MIT.EDUraeburn', 2, 16,
+                ('password', b'ATHENA.MIT.EDUraeburn', 2, 16,
                  '01dbee7f4a9e243e988b62c73cda935d'),
-                ('password', 'ATHENA.MIT.EDUraeburn', 2, 32,
+                ('password', b'ATHENA.MIT.EDUraeburn', 2, 32,
                  ('01dbee7f4a9e243e9'
                   '88b62c73cda935da05'
                   '378b93244ec8f48a99'
                   'e61ad799d86')),
-                ('password', 'ATHENA.MIT.EDUraeburn', 1200, 32,
+                ('password', b'ATHENA.MIT.EDUraeburn', 1200, 32,
                  ('5c08eb61fdf71e'
                   '4e4ec3cf6ba1f55'
                   '12ba7e52ddbc5e51'
                   '42f708a31e2e62b1e13')),
-                ('X' * 64, 'pass phrase equals block size', 1200, 32,
+                ('X' * 64, b'pass phrase equals block size', 1200, 32,
                  ('139c30c0966bc32ba'
                   '55fdbf212530ac9c5'
                   'ec59f1a452f5cc9ad'
                   '940fea0598ed1')),
-                ('X' * 65, 'pass phrase exceeds block size', 1200, 32,
+                ('X' * 65, b'pass phrase exceeds block size', 1200, 32,
                  ('9ccad6d468770cd'
                   '51b10e6a68721be6'
                   '11a8b4d282601db3'
-- 
cgit v1.2.3


From 8ed5d0e89cead10b03e5660c8eb87cf58a173436 Mon Sep 17 00:00:00 2001
From: BonfaceKilz
Date: Mon, 18 Jan 2021 11:20:02 +0300
Subject: Remove extra newlines in PR and issue templates

---
 .github/ISSUE_TEMPLATE/bug_report.md      |  6 ------
 .github/ISSUE_TEMPLATE/feature_request.md | 11 -----------
 .github/ISSUE_TEMPLATE/user_story.md      |  4 ----
 .github/PULL_REQUEST_TEMPLATE.md          |  3 ---
 4 files changed, 24 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 48bad39b..af60c290 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -8,27 +8,21 @@ assignees: ''
 ---
 
 **Describe the bug**
-
 <!-- A clear and concise description of what the bug is. -->
 
 **To Reproduce**
-
 <!-- Steps to reproduce the behavior -->
 
 **Expected behavior**
-
 <!-- A clear and concise description of what you expected to happen. -->
 
 **Screenshots**
-
 <!-- If applicable, add screenshots to help explain your problem. -->
 
 **Environment setup (please complete the following information):**
-
 <!-- - OS: [e.g. Linux] -->
 <!-- - Guix Version (optional) -->
 <!-- - [Anything else you think is relevant] -->
 
 **Additional context**
-
 <!-- Add any other context about the problem here. -->
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index eb6c3e4b..813974c1 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -8,34 +8,23 @@ assignees: ''
 ---
 
 ## Is your feature request related to a problem? Please describe.
-
 <!-- A clear and concise description of what the problem is. -->
-
 <!-- Example: I'm always frustrated when [...] -->
 
 ## Describe the solution you'd like
-
 <!-- A clear and concise description of what you want to happen. -->
 
 ## Describe alternatives you've considered
-
 <!-- A clear and concise description of any alternative solutions or features you've considered. -->
 
 ## User Stories (optional)
-
 <!-- Example: -->
-
 <!-- As a _[role or persona]_, I want _[goal/ need]_ so that _[why]_ -->
-
 <!-- **Feature:** _[Brief description of feature]_ -->
-
 <!-- _[Any additional descriptions on feature]_ -->
-
 <!-- **Scenario:**
-
 Please use _[Gherkin](https://cucumber.io/docs/gherkin/reference/)_
 here -->
 
 ## Additional context
-
 <!-- Add any other context or screenshots about the feature request here. -->
diff --git a/.github/ISSUE_TEMPLATE/user_story.md b/.github/ISSUE_TEMPLATE/user_story.md
index 52ae775d..d46976ba 100644
--- a/.github/ISSUE_TEMPLATE/user_story.md
+++ b/.github/ISSUE_TEMPLATE/user_story.md
@@ -6,11 +6,7 @@ labels: ''
 assignees: ''
 
 ---
-
 <!-- As a _[role or persona]_, I want _[goal/ need]_ so that _[why]_ -->
-
 <!-- **Feature:** _[Brief description of feature]_ -->
-
 <!-- _[Any additional descriptions on feature]_ -->
-
 <!-- **Scenario:** Please use _[Gherkin](https://cucumber.io/docs/gherkin/reference/)_ here -->
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index f3371183..926b0548 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -6,15 +6,12 @@
 assurance checks that should be done. What are the expectations -->
 
 #### Any background context you want to provide?
-
 <!-- Anything the reviewer should be aware of ahead of testing -->
 
 #### What are the relevant pivotal tracker stories?
-
 <!-- Does this PR track anything anywhere? -->
 
 #### Screenshots (if appropriate)
 
 #### Questions
-
 <!-- Are there any questions for the reviewer -->
-- 
cgit v1.2.3


From 42fd88d0e57462d4538ae328564fcc55da761991 Mon Sep 17 00:00:00 2001
From: BonfaceKilz
Date: Mon, 18 Jan 2021 11:30:36 +0300
Subject: Revert "resize image in facilities page"

This reverts commit db31d53421c033a9907d2c67bc8a0c3c911b5402.
---
 wqflask/wqflask/templates/facilities.html | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/wqflask/wqflask/templates/facilities.html b/wqflask/wqflask/templates/facilities.html
index dc8d0ded..56b127f9 100644
--- a/wqflask/wqflask/templates/facilities.html
+++ b/wqflask/wqflask/templates/facilities.html
@@ -4,14 +4,6 @@
 
 {% block css %}
 <link rel="stylesheet" type="text/css" href="/static/new/css/markdown.css" />
-
-<style>
-	 img[src="https://github.com/genenetwork/gn-docs/raw/master/general/help/octopus.jpg"] {
-    width:100%;
-    margin:20px 0px;
-}
-</style>
-
 {% endblock %}
 
 {% block content %}
-- 
cgit v1.2.3


From 3b2a835fce1cda94f0649d45297867ddb5994731 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 21 Jan 2021 12:50:28 -0600
Subject: Fixed the Select Top Rows feature to use DataTables API instead of
 JQuery

---
 .../static/new/javascript/search_results.js        | 48 +++++++++++++---------
 1 file changed, 28 insertions(+), 20 deletions(-)

diff --git a/wqflask/wqflask/static/new/javascript/search_results.js b/wqflask/wqflask/static/new/javascript/search_results.js
index 05dcfda5..ecb1220d 100644
--- a/wqflask/wqflask/static/new/javascript/search_results.js
+++ b/wqflask/wqflask/static/new/javascript/search_results.js
@@ -95,29 +95,37 @@ $(function() {
 
   $('#select_top').keyup(function(){
       num_rows = $(this).val()
+
       if (num_rows = parseInt(num_rows)){
-          i = 0
-          $('#trait_table > tbody > tr').each(function(){
-              if (i < num_rows) {
-                  $(this).find('.trait_checkbox').prop("checked", true)
-                  if (!$(this).closest('tr').hasClass('selected')) {
-                      $(this).closest('tr').addClass('selected')
-                  }
-              }
-              else {
-                  if ($(this).closest('tr').hasClass('selected')) {
-                      $(this).closest('tr').removeClass('selected')
-                      $(this).find('.trait_checkbox').prop("checked", false)
-                  }
-              }
-              i += 1
-          });
+          table_api = $('#trait_table').DataTable();
+
+          check_cells = table_api.column(0).nodes().to$();
+          for (let i = 0; i < num_rows; i++) {
+            check_cells[i].childNodes[0].checked = true;
+          }
+
+          check_rows = table_api.rows().nodes();
+          for (let i=0; i < num_rows; i++) {
+            if (check_rows[i].classList.contains("selected")){
+              continue
+            } else {
+              check_rows[i].classList.add("selected")
+            }
+          }
+          for (let i = num_rows; i < check_rows.length; i++){
+            check_cells[i].childNodes[0].checked = false;
+            if (check_rows[i].classList.contains("selected")){
+              check_rows[i].classList.remove("selected")
+            }
+          }
       }
       else {
-          $('#trait_table > tbody > tr').each(function(){
-              $(this).closest('tr').removeClass('selected')
-              $(this).find('.trait_checkbox').prop("checked", false)
-          });
+        for (let i = 0; i < check_rows.length; i++){
+          check_cells[i].childNodes[0].checked = false;
+          if (check_rows[i].classList.contains("selected")){
+            check_rows[i].classList.remove("selected")
+          }
+        }
       }
       change_buttons();
   });
-- 
cgit v1.2.3


From af386b6d11872d633cd23185c22e8f9f8d650fd2 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 21 Jan 2021 14:27:46 -0600
Subject: Adjusted Search Result table column widths and header alignments

---
 wqflask/wqflask/templates/search_result_page.html | 37 ++++++++++++-----------
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index b8f89121..eb42eb3a 100644
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -274,41 +274,42 @@
                       }
                     },
                     {
-                      'title': "Location",
+                      'title': "<div style='text-align: right;'>Location</div>",
                       'type': "natural-minus-na",
                       'width': "125px",
                       'data': "location"
                     },
                     {
-                      'title': "Mean",
+                      'title': "<div style='text-align: right;'>Mean</div>",
                       'type': "natural-minus-na",
-                      'width': "40px",
+                      'width': "30px",
                       'data': "mean",
                       'orderSequence': [ "desc", "asc"]
                     },
                     {
-                      'title': "Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>LOD",
+                      'title': "<div style='text-align: right;'>Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>LOD&ensp;&emsp;</div>",
                       'type': "natural-minus-na",
                       'data': "lod_score",
                       'width': "60px",
                       'orderSequence': [ "desc", "asc"]
                     },
                     {
-                      'title': "Peak Location",
+                      'title': "<div style='text-align: right;'>Peak Location</div>",
                       'type': "natural-minus-na",
                       'width': "125px",
                       'data': "lrs_location"
                     },
                     {
-                      'title': "Effect Size<a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>",
+                      'title': "<div style='text-align: right;'>Effect <a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>Size&ensp;&emsp;</div>",
                       'type': "natural-minus-na",
                       'data': "additive",
-                      'width': "90px",
+                      'width': "60px",
                       'orderSequence': [ "desc", "asc"]
                     }{% elif dataset.type == 'Publish' %},
                     {
                       'title': "Description",
                       'type': "natural",
+                      'width': "500px",
                       'data': null,
                       'render': function(data, type, row, meta) {
 			                  try {
@@ -319,16 +320,16 @@
                       }
                     },
                     {
-                      'title': "Mean",
+                      'title': "<div style='text-align: right;'>Mean</div>",
                       'type': "natural-minus-na",
-                      'width': "110px",
+                      'width': "30px",
                       'data': "mean",
                       'orderSequence': [ "desc", "asc"]
                     },
                     {
                       'title': "Authors",
                       'type': "natural",
-                      'width': "500px",
+                      'width': "400px",
                       'data': null,
                       'render': function(data, type, row, meta) {
                         author_list = data.authors.split(",")
@@ -341,10 +342,10 @@
                       }
                     },
                     {
-                      'title': "Year",
+                      'title': "<div style='text-align: right;'>Year</div>",
                       'type': "natural-minus-na",
                       'data': null,
-                      'width': "80px",
+                      'width': "25px",
                       'render': function(data, type, row, meta) {
                         if (data.pubmed_id != "N/A"){
                           return '<a href="' + data.pubmed_link + '">' + data.pubmed_text + '</a>'
@@ -355,34 +356,34 @@
                       'orderSequence': [ "desc", "asc"]
                     },
                     {
-                      'title': "Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>LOD",
+                      'title': "<div style='text-align: right;'>Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>LOD&ensp;&emsp;</div>",
                       'type': "natural-minus-na",
                       'data': "lod_score",
                       'width': "60px",
                       'orderSequence': [ "desc", "asc"]
                     },
                     {
-                      'title': "Peak Location",
+                      'title': "<div style='text-align: right;'>Peak Location</div>",
                       'type': "natural-minus-na",
                       'width': "120px",
                       'data': "lrs_location"
                     },
                     {
-                      'title': "Effect Size<a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>",
+                      'title': "<div style='text-align: right;'>Effect <a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>Size&ensp;&emsp;</div>",
                       'type': "natural-minus-na",
-                      'width': "120px",
+                      'width': "60px",
                       'data': "additive",
                       'orderSequence': [ "desc", "asc"]
                     }{% elif dataset.type == 'Geno' %},
                     {
-                      'title': "Location",
+                      'title': "<div style='text-align: right;'>Location</div>",
                       'type': "natural-minus-na",
                       'width': "120px",
                       'data': "location"
                     }{% endif %}
                 ],
                 "order": [[1, "asc" ]],
-                'sDom': "itir",
+                'sDom': "iti",
                 "autoWidth": true,
                 "bSortClasses": false,
                 "scrollY": "100vh",
-- 
cgit v1.2.3


From 1ad00938cafb2f0511658397050f6e938854d194 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 21 Jan 2021 14:31:14 -0600
Subject: Changed CSS for show/hide column buttons so it's more obvious when
 one is selected

---
 wqflask/wqflask/static/new/css/trait_list.css | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/static/new/css/trait_list.css b/wqflask/wqflask/static/new/css/trait_list.css
index b83655da..b765cdd4 100644
--- a/wqflask/wqflask/static/new/css/trait_list.css
+++ b/wqflask/wqflask/static/new/css/trait_list.css
@@ -12,7 +12,7 @@ div.show-hide-container {
 }
 
 button.active {
-    background: #e5e5e5;
+    background: #BEBEBE;
     -webkit-box-shadow: inset 0px 0px 5px #c1c1c1;
        -moz-box-shadow: inset 0px 0px 5px #c1c1c1;
             box-shadow: inset 0px 0px 5px #c1c1c1;
-- 
cgit v1.2.3


From db2d9d81493750971ccfe59934dcb6e00f67c521 Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 21 Jan 2021 15:15:12 -0600
Subject: Decreased the width of the Authors column some

---
 wqflask/wqflask/templates/search_result_page.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index eb42eb3a..9b36568c 100644
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -329,7 +329,7 @@
                     {
                       'title': "Authors",
                       'type': "natural",
-                      'width': "400px",
+                      'width': "300px",
                       'data': null,
                       'render': function(data, type, row, meta) {
                         author_list = data.authors.split(",")
-- 
cgit v1.2.3


From 9f12da2623c3ca9156300c825fe0f86ad08bb76e Mon Sep 17 00:00:00 2001
From: zsloan
Date: Thu, 21 Jan 2021 15:26:26 -0600
Subject: Added modified Scroller CSS to trait_list.css in order to add the
 text showing current row when scrolling and remove a 0 that was appearing
 below the table

---
 wqflask/wqflask/static/new/css/trait_list.css | 36 ++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/wqflask/wqflask/static/new/css/trait_list.css b/wqflask/wqflask/static/new/css/trait_list.css
index b765cdd4..c7249721 100644
--- a/wqflask/wqflask/static/new/css/trait_list.css
+++ b/wqflask/wqflask/static/new/css/trait_list.css
@@ -17,4 +17,38 @@ button.active {
        -moz-box-shadow: inset 0px 0px 5px #c1c1c1;
             box-shadow: inset 0px 0px 5px #c1c1c1;
      outline: none;
-  }
\ No newline at end of file
+}
+
+div.dts {
+    display:block !important
+}
+
+div.dts div.dts_loading {
+    z-index:1
+}
+
+div.dts div.dts_label {
+    position:absolute;
+    right:10px;
+    background:rgba(0,0,0,0.8);
+    color:white;
+    box-shadow:3px 3px 10px rgba(0,0,0,0.5);
+    text-align:right;
+    border-radius:3px;
+    padding:0.4em;
+    z-index:2;
+    display:none
+}
+
+div.dts div.dataTables_scrollBody {
+    background:repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, #fff 10px, #fff 20px)
+}
+
+div.dts div.dataTables_scrollBody table {
+    z-index:2
+}
+
+div.dts div.dataTables_paginate,div.dts div.dataTables_length{
+    display:none
+}
+
-- 
cgit v1.2.3