about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--test/requests/link_checker.py4
-rw-r--r--wqflask/tests/unit/utility/test_type_checking.py54
-rw-r--r--wqflask/tests/unit/wqflask/api/test_correlation.py153
-rw-r--r--wqflask/tests/unit/wqflask/api/test_mapping.py108
-rw-r--r--wqflask/tests/unit/wqflask/correlation/__init__.py0
-rw-r--r--wqflask/tests/unit/wqflask/correlation/test_correlation_functions.py20
-rw-r--r--wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py98
-rw-r--r--wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py51
-rw-r--r--wqflask/tests/unit/wqflask/snp_browser/__init__.py0
-rw-r--r--wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py105
-rw-r--r--wqflask/tests/unit/wqflask/test_server_side.py31
-rw-r--r--wqflask/utility/tools.py2
-rw-r--r--wqflask/utility/type_checking.py24
-rw-r--r--wqflask/wqflask/correlation/correlation_functions.py28
-rw-r--r--wqflask/wqflask/correlation/show_corr_results.py16
-rw-r--r--wqflask/wqflask/marker_regression/gemma_mapping.py11
-rw-r--r--wqflask/wqflask/search_results.py16
-rw-r--r--wqflask/wqflask/server_side.py93
-rw-r--r--wqflask/wqflask/snp_browser/snp_browser.py54
-rw-r--r--wqflask/wqflask/static/new/css/snp_browser.css6
-rw-r--r--wqflask/wqflask/static/new/javascript/draw_probability_plot.js1
-rw-r--r--wqflask/wqflask/static/new/javascript/init_genome_browser.js2
-rw-r--r--wqflask/wqflask/static/new/javascript/search_results.js4
-rw-r--r--wqflask/wqflask/static/new/javascript/show_trait.js66
-rw-r--r--wqflask/wqflask/static/new/javascript/stats.js2
-rw-r--r--wqflask/wqflask/templates/correlation_page.html26
-rw-r--r--wqflask/wqflask/templates/mapping_results.html16
-rw-r--r--wqflask/wqflask/templates/search_result_page.html40
-rw-r--r--wqflask/wqflask/templates/show_trait_calculate_correlations.html152
-rwxr-xr-xwqflask/wqflask/templates/show_trait_mapping_tools.html8
-rw-r--r--wqflask/wqflask/templates/show_trait_statistics.html16
-rw-r--r--wqflask/wqflask/templates/snp_browser.html142
-rw-r--r--wqflask/wqflask/user_login.py8
-rw-r--r--wqflask/wqflask/views.py42
34 files changed, 1085 insertions, 314 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",
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..48d110c7
--- /dev/null
+++ b/wqflask/tests/unit/utility/test_type_checking.py
@@ -0,0 +1,54 @@
+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 = ["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/api/test_correlation.py b/wqflask/tests/unit/wqflask/api/test_correlation.py
new file mode 100644
index 00000000..d0264b87
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/api/test_correlation.py
@@ -0,0 +1,153 @@
+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:
+    def __init__(self, obj):
+        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):
+        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)
+
+    @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],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)
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..b094294a
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/api/test_mapping.py
@@ -0,0 +1,108 @@
+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)
+
+
+class MockGroup(AttributeSetter):
+    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))
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
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/correlation/__init__.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..44d2e0fc
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/correlation/test_correlation_functions.py
@@ -0,0 +1,20 @@
+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..33601990
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/correlation/test_show_corr_results.py
@@ -0,0 +1,98 @@
+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
+
+
+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])
+
+    @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": "",
+            "mean": "",
+            "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", "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)
+        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, "[]")
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..fe2569b8 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")
@@ -172,21 +144,26 @@ X\tgn7\t2324424\tQ\tE\tA\tP\tMMB\tCDE\t0.4
             "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)
 
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
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/snp_browser/__init__.py
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..ce3e7b83
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/snp_browser/test_snp_browser.py
@@ -0,0 +1,105 @@
+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()
+
+    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, 
+                              ['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', '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(expected_results_with_indel, 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"
+        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(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 = """
+                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
+                   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': []})
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/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/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
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.
diff --git a/wqflask/wqflask/correlation/show_corr_results.py b/wqflask/wqflask/correlation/show_corr_results.py
index be983c87..a36b947c 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)
@@ -195,15 +194,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,
@@ -517,6 +516,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:
@@ -530,6 +530,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:
@@ -603,6 +605,7 @@ def get_header_fields(data_type, corr_method):
                             'Record',
                             'Abbreviation',
                             'Description',
+                            'Mean',
                             'Authors',
                             'Year',
                             'Sample rho',
@@ -616,6 +619,7 @@ def get_header_fields(data_type, corr_method):
                             'Record',
                             'Abbreviation',
                             'Description',
+                            'Mean',
                             'Authors',
                             'Year',
                             'Sample r',
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
diff --git a/wqflask/wqflask/search_results.py b/wqflask/wqflask/search_results.py
index 0d0894a4..c4ea2921 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
@@ -161,7 +160,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/server_side.py b/wqflask/wqflask/server_side.py
new file mode 100644
index 00000000..5f764767
--- /dev/null
+++ b/wqflask/wqflask/server_side.py
@@ -0,0 +1,93 @@
+# handles server side table processing
+
+
+
+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, rows_count, table_rows, header_data_names, request_values):
+        self.request_values = request_values
+        self.sEcho = self.request_values['sEcho']
+
+        self.rows_count = rows_count
+        self.table_rows = table_rows
+        self.header_data_names = 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 6c3fcf53..a52399a2 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,21 +14,21 @@ 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
+            del self.filtered_results
+
+            if 'sEcho' not in start_vars:
                 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:
@@ -368,19 +368,19 @@ 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):
-            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,13 +520,10 @@ 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)
 
         return the_rows
-                
 
     def include_record(self, domain, function, snp_source, conservation_score):
         """ Decide whether to add this record """
@@ -674,9 +671,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":
@@ -703,11 +704,16 @@ 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.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']
+        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 = []
@@ -868,8 +874,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 +887,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()
 
diff --git a/wqflask/wqflask/static/new/css/snp_browser.css b/wqflask/wqflask/static/new/css/snp_browser.css
index 30fe9a59..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,
@@ -18,7 +22,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 {
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>");
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]
 
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/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index b71a9dd8..b8ffa8e8 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -94,33 +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));
-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();
-});
-$(".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() {
@@ -233,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);
@@ -281,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
@@ -322,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)
@@ -353,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)
@@ -475,15 +457,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,
@@ -498,6 +480,7 @@ edit_data_change = function() {
         }
       }
     }
+
   }
 
   update_stat_values(sample_sets);
@@ -543,6 +526,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) {
   $("input[name=sample_vals]").val(JSON.stringify(fetch_sample_values()))
   $("#trait_data_form").attr("action", url);
@@ -650,6 +651,8 @@ block_by_attribute_value = function() {
       this_val_node.value = "x";
     }
   }
+
+  edit_data_change();
 };
 $('#exclude_by_attr').click(block_by_attribute_value);
 
@@ -819,6 +822,7 @@ reset_samples_table = function() {
 };
 $('.reset').click(function() {
   reset_samples_table();
+  $('input[name="transform"]').val("");
   edit_data_change();
 });
 
@@ -1308,7 +1312,7 @@ if (js_data.num_values < 256) {
     margin: {
         l: left_margin,
         r: 30,
-        t: 30,
+        t: 100,
         b: bottom_margin
     }
   };
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)]);
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>
@@ -399,6 +400,13 @@
                       }
                     },
                     {
+                      'title': "Mean",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "mean",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
                       'title': "Authors",
                       'type': "natural",
                       'width': "400px",
@@ -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 %}
diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html
index 2fb37832..c2256e47 100644
--- a/wqflask/wqflask/templates/mapping_results.html
+++ b/wqflask/wqflask/templates/mapping_results.html
@@ -245,7 +245,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;">
@@ -372,6 +372,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")
+                    }
+                    {% if geno_db_exists == "True" %}change_buttons(check_node=1){% endif %}
+                  });
+                },
                 "columns": [
                     { "type": "natural", "width": "5%" },
                     { "type": "natural", "width": "8%" },
diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index f2334512..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" />
@@ -160,6 +160,16 @@
 
     <script type="text/javascript" charset="utf-8">
         $(document).ready( function () {
+
+            var getParams = function(url) {
+                let parser = document.createElement('a');
+                parser.href = url;
+                let params = parser.search.substring(1);
+                if(params.length > 0) {
+                    return ('?'+params);
+                }
+                return params;
+            };
             
             $('#trait_table tr').click(function(event) {
                 if (event.target.type !== 'checkbox') {
@@ -225,7 +235,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 + '">'
                       }
@@ -373,15 +383,33 @@
                     }{% endif %}
                 ],
                 "order": [[1, "asc" ]],
-                'sDom': "itirp",
+                {% 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,
-                '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/templates/show_trait_calculate_correlations.html b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
index ba72ff27..eaa0c308 100644
--- a/wqflask/wqflask/templates/show_trait_calculate_correlations.html
+++ b/wqflask/wqflask/templates/show_trait_calculate_correlations.html
@@ -2,86 +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 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 != "Publish" %}
-          <div 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">
+        <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>
@@ -91,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">
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 %}
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;">
diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html
index a96b8e3b..b9aea570 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">
@@ -107,8 +107,14 @@
               </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="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">
@@ -182,24 +188,21 @@
     </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>
           <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: 15px;">{% for letter in strain %}<div style="transform: rotate(90deg);">{{ 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>
@@ -208,7 +211,6 @@
       <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td>
       </tbody>
     </table>
-    {% endif %}
     {% endif %}     
     </div>
   </div>
@@ -222,12 +224,24 @@
   <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 empty_columns = {{ empty_columns|safe }};
+
+      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">
 
+    var getParams = function(url) {
+      let parser = document.createElement('a');
+      parser.href = url;
+      let params = parser.search.substring(1);
+      if(params.length > 0) {
+        return ('?'+params);
+      }
+      return params;
+    };
+
     var substringMatcher = function(strs) {
       return function findMatches(q, cb) {
         var matches, substringRegex;
@@ -260,19 +274,20 @@
       source: substringMatcher(rat_genes)
     });
 
-    {% if filtered_results is defined %}
+    {% if table_rows is defined %}
     $("#results_table").DataTable( {
-      'data': json_rows,
       {% if variant_type == "SNP" %}
       'columns': [
         {
           'data': null,
+          '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'
+          'data': 'index',
+          'className': 'dt-body-right'
         }, {
           'data': null,
           'render': function(data, type, row, meta) {
@@ -283,27 +298,30 @@
             }
           }
         }, {
-          '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" %}{
           '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
             }
           }
         }, {% 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) {
             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
             }
@@ -330,6 +348,7 @@
         }, {% endif %} {% for item in allele_list %} {
           'data': null,
           'orderable': false,
+          '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]
@@ -339,12 +358,9 @@
           }
         }{% 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++) {
+      'createdRow': function(row, data, dataIndex) {
+        for (i = remain_field_count; i < total_field_count; 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');
@@ -380,24 +396,29 @@
         {
           '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'
+          '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'
         }, {
@@ -407,15 +428,28 @@
       {% endif %}
       'order': [[1, "asc" ]],
       'sDom': "rtip",
-      'iDisplayLength': 500,
-      'processing': true,
-      'language': {
-        'loadingRecords': '&nbsp;',
-        'processing': 'Loading...'
+      'iDisplayLength': 100,
+      'bServerSide': true,
+      '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";
       }
     });
     {% 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()
@@ -509,6 +543,40 @@
       });
       $("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");
+      for(let i = 1; i < col_header.length; i++) {
+        headers.push(col_header[i].getAttribute("name"));
+      }
+      csv.push(headers.join(","));
+
+      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 (let 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 = "variant_data.csv";
+      downloadLink.href = window.URL.createObjectURL(csvFile);
+      downloadLink.style.display = "none";
+      document.body.appendChild(downloadLink);
+      downloadLink.click();
+    });
   </script>
 {% endblock %}
 
diff --git a/wqflask/wqflask/user_login.py b/wqflask/wqflask/user_login.py
index f25ebc32..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
 
@@ -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"])
 
@@ -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"))
 
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index c136711e..2b3e2a37 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -26,6 +26,15 @@ 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
 
+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
 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
@@ -220,6 +229,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)
@@ -890,6 +919,19 @@ 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)
+    snp_table_data = snp_browser.SnpBrowser(request.args)
+    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)
+
 @app.route("/tutorial/WebQTLTour", methods=('GET',))
 def tutorial_page():
     #ZS: Currently just links to GN1