about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--wqflask/base/trait.py2
-rw-r--r--wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py205
-rw-r--r--wqflask/tests/unit/wqflask/marker_regression/test_plink_mapping.py85
-rw-r--r--wqflask/tests/unit/wqflask/marker_regression/test_qtlreaper_mapping.py21
-rw-r--r--wqflask/tests/unit/wqflask/marker_regression/test_rqtl_mapping.py48
-rw-r--r--wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py284
-rw-r--r--wqflask/wqflask/correlation/show_corr_results.py110
-rw-r--r--wqflask/wqflask/export_traits.py8
-rw-r--r--wqflask/wqflask/marker_regression/gemma_mapping.py9
-rw-r--r--wqflask/wqflask/marker_regression/plink_mapping.py22
-rw-r--r--wqflask/wqflask/marker_regression/qtlreaper_mapping.py46
-rw-r--r--wqflask/wqflask/static/new/css/show_trait.css4
-rw-r--r--wqflask/wqflask/static/new/css/trait_list.css32
-rw-r--r--wqflask/wqflask/static/new/javascript/lodheatmap.js6
-rw-r--r--wqflask/wqflask/static/new/javascript/panelutil.js1
-rw-r--r--wqflask/wqflask/static/new/javascript/search_results.js165
-rw-r--r--wqflask/wqflask/static/new/javascript/show_trait.js138
-rw-r--r--wqflask/wqflask/templates/collections/view.html33
-rw-r--r--wqflask/wqflask/templates/correlation_page.html568
-rw-r--r--wqflask/wqflask/templates/search_result_page.html47
-rw-r--r--wqflask/wqflask/templates/show_trait_transform_and_filter.html59
21 files changed, 1391 insertions, 502 deletions
diff --git a/wqflask/base/trait.py b/wqflask/base/trait.py
index 0f8f937c..ec8c40a0 100644
--- a/wqflask/base/trait.py
+++ b/wqflask/base/trait.py
@@ -516,7 +516,7 @@ def retrieve_trait_info(trait, dataset, get_qtl_info=False):
             # If the dataset is confidential and the user has access to confidential
             # phenotype traits, then display the pre-publication description instead
             # of the post-publication description
-            if trait.confidential:
+            if not trait.pubmed_id:
                 trait.abbreviation = trait.pre_publication_abbreviation
                 trait.description_display = trait.pre_publication_description
             else:
diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py
new file mode 100644
index 00000000..5b621264
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py
@@ -0,0 +1,205 @@
+# test for wqflask/marker_regression/gemma_mapping.py
+import unittest
+import random
+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
+
+
+class AttributeSetter:
+    def __init__(self, obj):
+        for key, val in obj.items():
+            setattr(self, key, val)
+
+
+class MockGroup(AttributeSetter):
+    def get_samplelist(self):
+        return None
+
+
+class TestGemmaMapping(unittest.TestCase):
+
+    @mock.patch("wqflask.marker_regression.gemma_mapping.parse_loco_output")
+    def test_run_gemma_firstrun_set_false(self, mock_parse_loco):
+        """add tests for gemma function where  first run is set to false"""
+        dataset = AttributeSetter(
+            {"group": AttributeSetter({"genofile": "genofile.geno"})})
+
+        output_file = "file1"
+        mock_parse_loco.return_value = []
+        this_trait = AttributeSetter({"name": "t1"})
+
+        result = run_gemma(this_trait=this_trait, this_dataset=dataset, samples=[], vals=[
+        ], covariates="", use_loco=True, first_run=False, output_files=output_file)
+
+        expected_results = ([], "file1")
+        self.assertEqual(expected_results, result)
+
+    @mock.patch("wqflask.marker_regression.gemma_mapping.webqtlConfig.GENERATED_IMAGE_DIR", "/home/user/img")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.GEMMAOPTS", "-debug")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.GEMMA_WRAPPER_COMMAND", "ghc")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.TEMPDIR", "/home/user/data/")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.parse_loco_output")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.logger")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.flat_files")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.gen_covariates_file")
+    @mock.patch("wqflask.marker_regression.run_mapping.random.choice")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.os")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.gen_pheno_txt_file")
+    def test_run_gemma_firstrun_set_true(self, mock_gen_pheno_txt, mock_os, mock_choice, mock_gen_covar, mock_flat_files, mock_logger, mock_parse_loco):
+        """add tests for run_gemma where first run is set to true"""
+        chromosomes = []
+        for i in range(1, 5):
+            chromosomes.append(AttributeSetter({"name": f"CH{i}"}))
+        chromo = AttributeSetter({"chromosomes": chromosomes})
+        dataset_group = MockGroup(
+            {"name": "GP1", "genofile": "file_geno"})
+        dataset = AttributeSetter({"group": dataset_group, "name": "dataset1_name",
+                                   "species": AttributeSetter({"chromosomes": chromo})})
+        trait = AttributeSetter({"name": "trait1"})
+        samples = []
+        mock_gen_pheno_txt.return_value = None
+        mock_os.path.isfile.return_value = True
+        mock_gen_covar.return_value = None
+        mock_choice.return_value = "R"
+        mock_flat_files.return_value = "/home/genotype/bimbam"
+        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)
+        mock_gen_pheno_txt.assert_called_once()
+        mock_parse_loco.assert_called_once_with(dataset, "GP1_GWA_RRRRRR")
+        mock_os.path.isfile.assert_called_once_with(
+            ('/home/user/imgfile_output.assoc.txt'))
+        self.assertEqual(mock_logger.debug.call_count, 2)
+        self.assertEqual(mock_flat_files.call_count, 4)
+        self.assertEqual(results, ([], "GP1_GWA_RRRRRR"))
+
+    @mock.patch("wqflask.marker_regression.gemma_mapping.TEMPDIR", "/home/user/data")
+    def test_gen_pheno_txt_file(self):
+        """add tests for generating pheno txt file"""
+        with mock.patch("builtins.open", mock.mock_open())as mock_open:
+            gen_pheno_txt_file(this_dataset={}, genofile_name="", vals=[
+                               "x", "w", "q", "we", "R"], trait_filename="fitr.re")
+            mock_open.assert_called_once_with(
+                '/home/user/data/gn2/fitr.re.txt', 'w')
+            filehandler = mock_open()
+            values = ["x", "w", "q", "we", "R"]
+            write_calls = [mock.call('NA\n'), mock.call('w\n'), mock.call(
+                'q\n'), mock.call('we\n'), mock.call('R\n')]
+
+            filehandler.write.assert_has_calls(write_calls)
+
+    @mock.patch("wqflask.marker_regression.gemma_mapping.flat_files")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.create_trait")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.create_dataset")
+    def test_gen_covariates_file(self, create_dataset, create_trait, flat_files):
+        """add tests for generating covariates files"""
+        covariates = "X1:X2,Y1:Y2,M1:M3,V1:V2"
+        samplelist = ["X1", "X2", "X3", "X4"]
+        create_dataset_side_effect = []
+        create_trait_side_effect = []
+
+        for i in range(4):
+            create_dataset_side_effect.append(AttributeSetter({"name": f'name_{i}'}))
+            create_trait_side_effect.append(
+                AttributeSetter({"data": [f'data_{i}']}))
+
+        create_dataset.side_effect = create_trait_side_effect
+        create_trait.side_effect = create_trait_side_effect
+
+        group = MockGroup({"name": "group_X", "samplelist": samplelist})
+        this_dataset = AttributeSetter({"group": group})
+        flat_files.return_value = "Home/Genenetwork"
+
+        with mock.patch("builtins.open", mock.mock_open())as mock_open:
+            gen_covariates_file(this_dataset=this_dataset, covariates=covariates,
+                                samples=["x1", "x2", "X3"])
+
+            create_dataset.assert_has_calls(
+                [mock.call('X2'), mock.call('Y2'), mock.call('M3'), mock.call('V2')])
+            mock_calls = []
+            trait_names = ["X1", "Y1", "M1", "V1"]
+
+            for i, trait in enumerate(create_trait_side_effect):
+                mock_calls.append(
+                    mock.call(dataset=trait, name=trait_names[i], cellid=None))
+
+            create_trait.assert_has_calls(mock_calls)
+
+            flat_files.assert_called_once_with('mapping')
+            mock_open.assert_called_once_with(
+                'Home/Genenetwork/group_X_covariates.txt', 'w')
+            filehandler = mock_open()
+            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")
+    def test_parse_loco_outputfile_found(self, mock_json, mock_os):
+        """add tests for parse loco output file found"""
+        mock_json.load.return_value = {
+            "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"""
+        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)
+            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}]
+
+            self.assertEqual(expected_results, results)
+
+    @mock.patch("wqflask.marker_regression.gemma_mapping.TEMPDIR", "/home/tmp")
+    @mock.patch("wqflask.marker_regression.gemma_mapping.os")
+    def test_parse_loco_outputfile_not_found(self, mock_os):
+        """add tests for parse loco output where  output file not found"""
+
+        mock_os.path.isfile.return_value = False
+        file_to_write = """{"files":["file_1","file_2"]}"""
+
+        with mock.patch("builtins.open", mock.mock_open(read_data=file_to_write)) as mock_open:
+            results = parse_loco_output(
+                this_dataset={}, gwa_output_filename=".xw/")
+            self.assertEqual(results, [])
diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_plink_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_plink_mapping.py
new file mode 100644
index 00000000..5eec93f1
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/marker_regression/test_plink_mapping.py
@@ -0,0 +1,85 @@
+# test for wqflask/marker_regression/plink_mapping.py
+import unittest
+from unittest import mock
+from wqflask.marker_regression.plink_mapping import build_line_list
+from wqflask.marker_regression.plink_mapping import get_samples_from_ped_file
+from wqflask.marker_regression.plink_mapping import flat_files
+from wqflask.marker_regression.plink_mapping import gen_pheno_txt_file_plink
+from wqflask.marker_regression.plink_mapping import parse_plink_output
+
+
+class AttributeSetter:
+    def __init__(self, obj):
+        for key, val in obj.items():
+            setattr(self, key, val)
+class TestPlinkMapping(unittest.TestCase):
+
+
+    def test_build_line_list(self):
+        """test for building line list"""
+        line_1 = "this is line one test"
+        irregular_line = "  this     is an, irregular line     "
+        exp_line1 = ["this", "is", "line", "one", "test"]
+
+        results = build_line_list(irregular_line)
+        self.assertEqual(exp_line1, build_line_list(line_1))
+        self.assertEqual([], build_line_list())
+        self.assertEqual(["this", "is", "an,", "irregular", "line"], results)
+
+    @mock.patch("wqflask.marker_regression.plink_mapping.flat_files")
+    def test_get_samples_from_ped_file(self, mock_flat_files):
+        """test for getting samples from ped file"""
+        dataset = AttributeSetter({"group": AttributeSetter({"name": "n_1"})})
+        file_sample = """Expected_1\tline test
+Expected_2\there
+  Expected_3\tthree"""
+        mock_flat_files.return_value = "/home/user/"
+        with mock.patch("builtins.open", mock.mock_open(read_data=file_sample)) as mock_open:
+            results = get_samples_from_ped_file(dataset)
+            mock_flat_files.assert_called_once_with("mapping")
+            mock_open.assert_called_once_with("/home/user/n_1.ped", "r")
+            self.assertEqual(
+                ["Expected_1", "Expected_2", "Expected_3"], results)
+
+    @mock.patch("wqflask.marker_regression.plink_mapping.TMPDIR", "/home/user/data/")
+    @mock.patch("wqflask.marker_regression.plink_mapping.get_samples_from_ped_file")
+    def test_gen_pheno_txt_file_plink(self, mock_samples):
+        """test for getting gen_pheno txt file"""
+        mock_samples.return_value = ["Expected_1", "Expected_2", "Expected_3"]
+
+        trait = AttributeSetter({"name": "TX"})
+        dataset = AttributeSetter({"group": AttributeSetter({"name": "n_1"})})
+        vals = ["value=K1", "value=K2", "value=K3"]
+        with mock.patch("builtins.open", mock.mock_open()) as mock_open:
+            results = gen_pheno_txt_file_plink(this_trait=trait, dataset=dataset,
+                                               vals=vals, pheno_filename="ph_file")
+            mock_open.assert_called_once_with(
+                "/home/user/data/ph_file.txt", "wb")
+            filehandler = mock_open()
+            calls_expected = [mock.call('FID\tIID\tTX\n'),
+                              mock.call('Expected_1\tExpected_1\tK1\nExpected_2\tExpected_2\tK2\nExpected_3\tExpected_3\tK3\n')]
+
+            filehandler.write.assert_has_calls(calls_expected)
+
+            filehandler.close.assert_called_once()
+
+    @mock.patch("wqflask.marker_regression.plink_mapping.TMPDIR", "/home/user/data/")
+    @mock.patch("wqflask.marker_regression.plink_mapping.build_line_list")
+    def test_parse_plink_output(self, mock_line_list):
+        """test for parsing plink output"""
+        chromosomes = [0, 34, 110, 89, 123, 23, 2]
+        species = AttributeSetter(
+            {"name": "S1", "chromosomes": AttributeSetter({"chromosomes": chromosomes})})
+
+        fake_file = """0 AACCAT T98.6  0.89\n2  AATA  B45  0.3\n121  ACG  B56.4 NA"""
+
+        mock_line_list.side_effect = [["0", "AACCAT", "T98.6", "0.89"], [
+            "2", "AATA", "B45", "0.3"], ["121", "ACG", "B56.4", "NA"]]
+        with mock.patch("builtins.open", mock.mock_open(read_data=fake_file)) as mock_open:
+            parse_results = parse_plink_output(
+                output_filename="P1_file", species=species)
+            mock_open.assert_called_once_with(
+                "/home/user/data/P1_file.qassoc", "rb")
+            expected = (2, {'AACCAT': 0.89, 'AATA': 0.3})
+
+            self.assertEqual(parse_results, expected)
diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_qtlreaper_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_qtlreaper_mapping.py
new file mode 100644
index 00000000..b47f877a
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/marker_regression/test_qtlreaper_mapping.py
@@ -0,0 +1,21 @@
+import unittest
+from unittest import  mock
+from wqflask.marker_regression.qtlreaper_mapping import  gen_pheno_txt_file
+
+#issues some methods in genofile object are not defined
+#modify samples should equal to vals
+class TestQtlReaperMapping(unittest.TestCase):
+	@mock.patch("wqflask.marker_regression.qtlreaper_mapping.TEMPDIR", "/home/user/data")
+	def  test_gen_pheno_txt_file(self):                   
+		vals=["V1","x","V4","V3","x"]
+		samples=["S1","S2","S3","S4","S5"]
+		trait_filename="trait_file"
+		with mock.patch("builtins.open", mock.mock_open())as mock_open:
+			gen_pheno_txt_file(samples=samples,vals=vals,trait_filename=trait_filename)
+			mock_open.assert_called_once_with("/home/user/data/gn2/trait_file.txt","w")
+			filehandler=mock_open()
+			write_calls= [mock.call('Trait\t'),mock.call('S1\tS3\tS4\n'),mock.call('T1\t'),mock.call('V1\tV4\tV3')]
+
+			filehandler.write.assert_has_calls(write_calls)
+
+	                                                                                                                    
diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_rqtl_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_rqtl_mapping.py
new file mode 100644
index 00000000..c585f1df
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/marker_regression/test_rqtl_mapping.py
@@ -0,0 +1,48 @@
+import unittest
+from unittest import mock
+from wqflask import app
+from wqflask.marker_regression.rqtl_mapping import get_trait_data_type
+from wqflask.marker_regression.rqtl_mapping import sanitize_rqtl_phenotype
+from wqflask.marker_regression.rqtl_mapping import sanitize_rqtl_names
+
+class TestRqtlMapping(unittest.TestCase):
+
+	def setUp(self):
+		self.app_context=app.app_context()
+		self.app_context.push()
+
+	def tearDown(self):
+		self.app_context.pop()
+
+
+	@mock.patch("wqflask.marker_regression.rqtl_mapping.g")
+	@mock.patch("wqflask.marker_regression.rqtl_mapping.logger")
+	def test_get_trait_data(self,mock_logger,mock_db):
+		"""test for getting trait data_type return True"""
+		query_value="""SELECT value FROM TraitMetadata WHERE type='trait_data_type'"""
+		mock_db.db.execute.return_value.fetchone.return_value=["""{"type":"trait_data_type","name":"T1","traid_id":"fer434f"}"""]
+		results=get_trait_data_type("traid_id")
+		mock_db.db.execute.assert_called_with(query_value)
+		self.assertEqual(results,"fer434f")
+
+	def test_sanitize_rqtl_phenotype(self):
+		"""test for sanitizing rqtl phenotype"""
+		vals=['f',"x","r","x","x"]
+		results=sanitize_rqtl_phenotype(vals)
+		expected_phenotype_string='c(f,NA,r,NA,NA)'
+
+		self.assertEqual(results,expected_phenotype_string)
+
+	def test_sanitize_rqtl_names(self):
+		"""test for sanitzing rqtl names"""
+		vals=['f',"x","r","x","x"]
+		expected_sanitized_name="c('f',NA,'r',NA,NA)"
+		results=sanitize_rqtl_names(vals)
+		self.assertEqual(expected_sanitized_name,results)
+
+
+		
+		
+
+
+
diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py
new file mode 100644
index 00000000..4129cc0c
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py
@@ -0,0 +1,284 @@
+import unittest
+import datetime
+from unittest import mock
+
+from wqflask.marker_regression.run_mapping import get_genofile_samplelist
+from wqflask.marker_regression.run_mapping import geno_db_exists
+from wqflask.marker_regression.run_mapping import write_input_for_browser
+from wqflask.marker_regression.run_mapping import export_mapping_results
+from wqflask.marker_regression.run_mapping import trim_markers_for_figure
+from wqflask.marker_regression.run_mapping import get_perm_strata
+from wqflask.marker_regression.run_mapping import get_chr_lengths
+
+
+class AttributeSetter:
+    def __init__(self, obj):
+        for k, v in obj.items():
+            setattr(self, k, v)
+
+
+class MockGroup(AttributeSetter):
+
+    def get_genofiles(self):
+        return [{"location": "~/genofiles/g1_file", "sample_list": ["S1", "S2", "S3", "S4"]}]
+
+
+class TestRunMapping(unittest.TestCase):
+    def setUp(self):
+
+        self.group = MockGroup(
+            {"genofile": "~/genofiles/g1_file", "name": "GP1_", "species": "Human"})
+        chromosomes = {
+            "3": AttributeSetter({
+                "name": "C1",
+                "length": "0.04"
+            }),
+            "4": AttributeSetter({
+                "name": "C2",
+                "length": "0.03"
+            }),
+            "5": AttributeSetter({
+                "name": "C4",
+                "length": "0.01"
+            })
+        }
+        self.dataset = AttributeSetter(
+            {"fullname": "dataser_1", "group": self.group, "type": "ProbeSet"})
+
+        self.chromosomes = AttributeSetter({"chromosomes": chromosomes})
+        self.trait = AttributeSetter(
+            {"symbol": "IGFI", "chr": "X1", "mb": 123313})
+
+    def tearDown(self):
+        self.dataset = AttributeSetter(
+            {"group": {"location": "~/genofiles/g1_file"}})
+
+    def test_get_genofile_samplelist(self):
+
+        results_1 = get_genofile_samplelist(self.dataset)
+        self.assertEqual(results_1, ["S1", "S2", "S3", "S4"])
+        self.group.genofile = "~/genofiles/g2_file"
+        result_2 = get_genofile_samplelist(self.dataset)
+        self.assertEqual(result_2, [])
+
+    @mock.patch("wqflask.marker_regression.run_mapping.data_set")
+    def test_if_geno_db_exists(self, mock_data_set):
+        mock_data_set.create_dataset.side_effect = [
+            AttributeSetter({}), Exception()]
+        results_no_error = geno_db_exists(self.dataset)
+        results_with_error = geno_db_exists(self.dataset)
+
+        self.assertEqual(mock_data_set.create_dataset.call_count, 2)
+        self.assertEqual(results_with_error, "False")
+        self.assertEqual(results_no_error, "True")
+
+    def test_trim_markers_for_figure(self):
+
+        markers = [{
+            "name": "MK1",
+            "chr": "C1",
+            "cM": "1",
+            "Mb": "12000",
+            "genotypes": [],
+            "dominance":"TT",
+            "additive":"VA",
+            "lod_score":0.5
+        },
+            {
+            "name": "MK2",
+            "chr": "C2",
+            "cM": "15",
+            "Mb": "10000",
+            "genotypes": [],
+            "lod_score":0.7
+        },
+            {
+            "name": "MK1",
+            "chr": "C3",
+            "cM": "45",
+            "Mb": "1",
+            "genotypes": [],
+            "dominance":"Tt",
+            "additive":"VE",
+            "lod_score":1
+        }]
+
+        marker_2 = [{
+            "name": "MK1",
+            "chr": "C1",
+            "cM": "1",
+            "Mb": "12000",
+            "genotypes": [],
+            "dominance":"TT",
+            "additive":"VA",
+            "p_wald":4.6
+        }]
+        results = trim_markers_for_figure(markers)
+        result_2 = trim_markers_for_figure(marker_2)
+        expected = [
+            {
+                "name": "MK1",
+                "chr": "C1",
+                "cM": "1",
+                "Mb": "12000",
+                "genotypes": [],
+                "dominance":"TT",
+                "additive":"VA",
+                "lod_score":0.5
+            },
+            {
+                "name": "MK1",
+                "chr": "C3",
+                "cM": "45",
+                "Mb": "1",
+                "genotypes": [],
+                "dominance":"Tt",
+                "additive":"VE",
+                "lod_score":1
+            }
+
+        ]
+        self.assertEqual(results, expected)
+        self.assertEqual(result_2, marker_2)
+
+    def test_export_mapping_results(self):
+        """test for exporting mapping results"""
+        datetime_mock = mock.Mock(wraps=datetime.datetime)
+        datetime_mock.now.return_value = datetime.datetime(
+            2019, 9, 1, 10, 12, 12)
+
+        markers = [{
+            "name": "MK1",
+            "chr": "C1",
+            "cM": "1",
+            "Mb": "12000",
+            "genotypes": [],
+            "dominance":"TT",
+            "additive":"VA",
+            "lod_score":3
+        },
+            {
+            "name": "MK2",
+            "chr": "C2",
+            "cM": "15",
+            "Mb": "10000",
+            "genotypes": [],
+            "lod_score":7
+        },
+            {
+            "name": "MK1",
+            "chr": "C3",
+            "cM": "45",
+            "Mb": "1",
+            "genotypes": [],
+            "dominance":"Tt",
+            "additive":"VE",
+            "lod_score":7
+        }]
+
+        with mock.patch("builtins.open", mock.mock_open()) as mock_open:
+
+            with mock.patch("wqflask.marker_regression.run_mapping.datetime.datetime", new=datetime_mock):
+                export_mapping_results(dataset=self.dataset, trait=self.trait, markers=markers,
+                                       results_path="~/results", mapping_scale="physic", score_type="-log(p)")
+
+                write_calls = [
+                    mock.call('Time/Date: 09/01/19 / 10:12:12\n'),
+                    mock.call('Population: Human GP1_\n'), mock.call(
+                        'Data Set: dataser_1\n'),
+                    mock.call('Gene Symbol: IGFI\n'), mock.call(
+                        'Location: X1 @ 123313 Mb\n'),
+                    mock.call('\n'), mock.call('Name,Chr,'),
+                    mock.call('Mb,-log(p)'), mock.call('Cm,-log(p)'),
+                    mock.call(',Additive'), mock.call(',Dominance'),
+                    mock.call('\n'), mock.call('MK1,C1,'),
+                    mock.call('12000,'), mock.call('1,'),
+                    mock.call('3'), mock.call(',VA'),
+                    mock.call(',TT'), mock.call('\n'),
+                    mock.call('MK2,C2,'), mock.call('10000,'),
+                    mock.call('15,'), mock.call('7'),
+                    mock.call('\n'), mock.call('MK1,C3,'),
+                    mock.call('1,'), mock.call('45,'),
+                    mock.call('7'), mock.call(',VE'),
+                    mock.call(',Tt')
+
+                ]
+                mock_open.assert_called_once_with("~/results", "w+")
+                filehandler = mock_open()
+                filehandler.write.assert_has_calls(write_calls)
+
+    @mock.patch("wqflask.marker_regression.run_mapping.random.choice")
+    def test_write_input_for_browser(self, mock_choice):
+        """test for writing input for browser"""
+        mock_choice.side_effect = ["F", "i", "l", "e", "s", "x"]
+        with mock.patch("builtins.open", mock.mock_open()) as mock_open:
+            expected = ['GP1__Filesx_GWAS', 'GP1__Filesx_ANNOT']
+
+            results = write_input_for_browser(
+                this_dataset=self.dataset, gwas_results={}, annotations={})
+            self.assertEqual(results, expected)
+
+    def test_get_perm_strata(self):
+        categorical_vars = ["C1", "C2", "W1"]
+        used_samples = ["S1", "S2"]
+        sample_list = AttributeSetter({"sample_attribute_values": {
+            "S1": {
+                "C1": "c1_value",
+                "C2": "c2_value",
+                "W1": "w1_value"
+
+            },
+            "S2": {
+                "W1": "w2_value",
+                "W2": "w2_value"
+
+            },
+            "S3": {
+
+                "C1": "c1_value",
+                "C2": "c2_value"
+
+            },
+
+        }})
+
+        results = get_perm_strata(this_trait={}, sample_list=sample_list,
+                                  categorical_vars=categorical_vars, used_samples=used_samples)
+        self.assertEqual(results, [2, 1])
+
+    def test_get_chr_length(self):
+        """test for getting chromosome length"""
+        chromosomes = AttributeSetter({"chromosomes": self.chromosomes})
+        dataset = AttributeSetter({"species": chromosomes})
+        results = get_chr_lengths(
+            mapping_scale="physic", mapping_method="reaper", dataset=dataset, qtl_results=[])
+        chr_lengths = []
+        for key, chromo in self.chromosomes.chromosomes.items():
+            chr_lengths.append({"chr": chromo.name, "size": chromo.length})
+
+        self.assertEqual(chr_lengths, results)
+
+        qtl_results = [{
+            "chr": "16",
+            "cM": "0.2"
+        },
+            {
+            "chr": "12",
+            "cM": "0.5"
+        },
+            {
+            "chr": "18",
+            "cM": "0.1"
+        },
+            {
+            "chr": "22",
+            "cM": "0.4"
+        },
+        ]
+
+        result_with_other_mapping_scale = get_chr_lengths(
+            mapping_scale="other", mapping_method="reaper", dataset=dataset, qtl_results=qtl_results)
+        expected_value = [{'chr': '1', 'size': '0'}, {
+            'chr': '16', 'size': '500000.0'}, {'chr': '18', 'size': '400000.0'}]
+
+        self.assertEqual(result_with_other_mapping_scale, expected_value)
diff --git a/wqflask/wqflask/correlation/show_corr_results.py b/wqflask/wqflask/correlation/show_corr_results.py
index 4c2b64ba..51aa1622 100644
--- a/wqflask/wqflask/correlation/show_corr_results.py
+++ b/wqflask/wqflask/correlation/show_corr_results.py
@@ -484,75 +484,79 @@ def generate_corr_json(corr_results, this_trait, dataset, target_dataset, for_ap
         if trait.view == False:
             continue
         results_dict = {}
-        if not for_api:
-            results_dict['checkbox'] = "<INPUT TYPE='checkbox' NAME='searchResult' class='checkbox trait_checkbox' style='padding-right: 0px;' VALUE='" + hmac.hmac_creation('{}:{}'.format(trait.name, trait.dataset.name)) + "'>"
-            results_dict['index'] = i + 1
-            results_dict['trait_id'] = "<a href='/show_trait?trait_id="+str(trait.name)+"&dataset="+str(dataset.name)+"'>"+str(trait.name)+"</a>"
-        else:
-            results_dict['trait_id'] = trait.name
+        results_dict['index'] = i + 1
+        results_dict['trait_id'] = trait.name
+        results_dict['dataset'] = trait.dataset.name
+        results_dict['hmac'] = hmac.data_hmac('{}:{}'.format(trait.name, trait.dataset.name))
         if target_dataset.type == "ProbeSet":
             results_dict['symbol'] = trait.symbol
-            results_dict['description'] = trait.description_display
+            results_dict['description'] = "N/A"
             results_dict['location'] = trait.location_repr
-            results_dict['mean'] = float(trait.mean)
+            results_dict['mean'] = "N/A"
+            results_dict['lrs_score'] = "N/A"
+            results_dict['additive'] = "N/A"
+            if bool(trait.description_display):
+                results_dict['description'] = trait.description_display
+            if bool(trait.mean):
+                results_dict['mean'] = float(trait.mean)
             if trait.LRS_score_repr != "N/A":
-                results_dict['lrs_score'] = "%.1f" % float(trait.LRS_score_repr)
-            else:
-                results_dict['lrs_score'] = "N/A"
+                results_dict['lrs_score'] = f"{float(trait.LRS_score_repr):.1f}"
             results_dict['lrs_location'] = trait.LRS_location_repr
-            if trait.additive != "":
-                results_dict['additive'] = "%0.3f" % float(trait.additive)
-            else:
-                results_dict['additive'] = "N/A"
-            if for_api:
-                results_dict['sample_r'] = "%0.3f" % float(trait.sample_r)
-            else:
-                results_dict['sample_r'] = "<a target='_blank' href='corr_scatter_plot?dataset_1=" + str(dataset.name) + "&dataset_2=" + str(trait.dataset.name) + "&trait_1=" + str(this_trait.name) + "&trait_2=" + str(trait.name) + "'>" + "%0.3f" % float(trait.sample_r) + "</a>"
+            if bool(trait.additive):
+                results_dict['additive'] = f"{float(trait.additive):.3f}"
+            results_dict['sample_r'] = f"{float(trait.sample_r):.3f}"
             results_dict['num_overlap'] = trait.num_overlap
-            results_dict['sample_p'] = "%0.3e" % float(trait.sample_p)
-            if trait.lit_corr == "" or trait.lit_corr == 0:
-                results_dict['lit_corr'] = "--"
-            else:
-                results_dict['lit_corr'] = "%0.3f" % float(trait.lit_corr)
-            if trait.tissue_corr == "" or trait.tissue_corr == 0:
-                results_dict['tissue_corr'] = "--"
-            else:
-                results_dict['tissue_corr'] = "%0.3f" % float(trait.tissue_corr)
+            results_dict['sample_p'] = f"{float(trait.sample_p):.3e}"
+            results_dict['lit_corr'] = "--"
+            results_dict['tissue_corr'] = "--"
+            results_dict['tissue_pvalue'] = "--"
+            if bool(trait.lit_corr):
+                results_dict['lit_corr'] = f"{float(trait.lit_corr):.3f}"
+            if bool(trait.tissue_corr):
+                results_dict['tissue_corr'] = f"{float(trait.tissue_corr):.3f}"
+                results_dict['tissue_pvalue'] = f"{float(trait.tissue_pvalue):.3e}"
         elif target_dataset.type == "Publish":
-            results_dict['description'] = trait.description_display
-            results_dict['authors'] = trait.authors
-            if trait.pubmed_id:
+            results_dict['abbreviation_display'] = "N/A"
+            results_dict['description'] = "N/A"
+            results_dict['authors_display'] = "N/A"
+            results_dict['additive'] = "N/A"
+            if for_api:
+                results_dict['pubmed_id'] = "N/A"
+                results_dict['year'] = "N/A"
+            else:
+                results_dict['pubmed_link'] = "N/A"
+                results_dict['pubmed_text'] = "N/A"
+
+            if bool(trait.abbreviation):
+                results_dict['abbreviation_display'] = trait.abbreviation
+            if bool(trait.description_display):
+                results_dict['description'] = trait.description_display
+            if bool(trait.authors):
+                authors_list = trait.authors.split(',')
+                if len(authors_list) > 6:
+                    results_dict['authors_display'] = ", ".join(authors_list[:6]) + ", et al."
+                else:
+                    results_dict['authors_display'] = trait.authors
+            if bool(trait.pubmed_id):
                 if for_api:
                     results_dict['pubmed_id'] = trait.pubmed_id
                     results_dict['year'] = trait.pubmed_text
                 else:
-                    results_dict['pubmed'] = "<a href='" + trait.pubmed_link + "'> " + trait.pubmed_text + "</a>"
-            else:
-                if for_api:
-                    results_dict['pubmed_id'] = "N/A"
-                    results_dict['year'] = "N/A"
-                else:
-                    results_dict['pubmed'] = "N/A"
+                    results_dict['pubmed_link'] = trait.pubmed_link
+                    results_dict['pubmed_text'] = trait.pubmed_text
+
             results_dict['lrs_score'] = trait.LRS_score_repr
             results_dict['lrs_location'] = trait.LRS_location_repr
-            if trait.additive != "":
-                results_dict['additive'] = "%0.3f" % float(trait.additive)
-            else:
-                results_dict['additive'] = "N/A"
-            if for_api:
-                results_dict['sample_r'] = "%0.3f" % trait.sample_r
-            else:
-                results_dict['sample_r'] = "<a target='_blank' href='corr_scatter_plot?dataset_1=" + str(dataset.name) + "&dataset_2=" + str(trait.dataset.name) + "&trait_1=" + str(this_trait.name) + "&trait_2=" + str(trait.name) + "'>" + "%0.3f" % trait.sample_r + "</a>"
+            if bool(trait.additive):
+                results_dict['additive'] = f"{float(trait.additive):.3f}"
+            results_dict['sample_r'] = f"{float(trait.sample_r):.3f}"
             results_dict['num_overlap'] = trait.num_overlap
-            results_dict['sample_p'] = "%0.3e" % float(trait.sample_p)
+            results_dict['sample_p'] = f"{float(trait.sample_p):.3e}"
         else:
-            results_dict['lrs_location'] = trait.LRS_location_repr
-            if for_api:
-                results_dict['sample_r'] = "%0.3f" % trait.sample_r
-            else:
-                results_dict['sample_r'] = "<a target='_blank' href='corr_scatter_plot?dataset_1=" + str(dataset.name) + "&dataset_2=" + str(trait.dataset.name) + "&trait_1=" + str(this_trait.name) + "&trait_2=" + str(trait.name) + "'>" + "%0.3f" % float(trait.sample_r) + "</a>"
+            results_dict['location'] = trait.location_repr
+            results_dict['sample_r'] = f"{float(trait.sample_r):.3f}"
             results_dict['num_overlap'] = trait.num_overlap
-            results_dict['sample_p'] = "%0.3e" % float(trait.sample_p)
+            results_dict['sample_p'] = f"{float(trait.sample_p):.3e}"
 
         results_list.append(results_dict)
 
diff --git a/wqflask/wqflask/export_traits.py b/wqflask/wqflask/export_traits.py
index 3a886537..6fb760e0 100644
--- a/wqflask/wqflask/export_traits.py
+++ b/wqflask/wqflask/export_traits.py
@@ -44,7 +44,7 @@ def export_search_results_csv(targs):
         if targs['filter_term'] != "None":
             metadata.append(["Search Filter Terms: " + targs['filter_term']])
     metadata.append(["Exported Row Number: " + str(len(table_rows))])
-    metadata.append(["Funding for The GeneNetwork: NIAAA (U01AA13499, U24AA13513), NIDA, NIMH, and NIAAA (P20-DA21131), NCI MMHCC (U01CA105417), and NCRR (U01NR 105417)"])
+    metadata.append(["Funding for The GeneNetwork: NIGMS (R01 GM123489, 2017-2021), NIDA (P30 DA044223, 2017-2022), NIA (R01AG043930, 2013-2018), NIAAA (U01 AA016662, U01 AA013499, U24 AA013513, U01 AA014425, 2006-2017), NIDA/NIMH/NIAAA (P20-DA 21131, 2001-2012), NCI MMHCC (U01CA105417), NCRR/BIRN (U24 RR021760)"])
     metadata.append([])
 
     trait_list = []
@@ -54,7 +54,7 @@ def export_search_results_csv(targs):
         trait_ob = retrieve_trait_info(trait_ob, trait_ob.dataset, get_qtl_info=True)
         trait_list.append(trait_ob)
 
-    table_headers = ['Species', 'Group', 'Dataset', 'Record ID', 'Symbol', 'Description', 'ProbeTarget', 'PubMed_ID', 'Chr', 'Mb', 'Alias', 'Gene_ID', 'Homologene_ID', 'UniGene_ID', 'Strand_Probe', 'Probe_set_specificity', 'Probe_set_BLAT_score', 'Probe_set_BLAT_Mb_start', 'Probe_set_BLAT_Mb_end', 'QTL_Chr', 'QTL_Mb', 'Locus_at_Peak', 'Max_LRS', 'P_value_of_MAX', 'Mean_Expression']
+    table_headers = ['Index', 'URL', 'Species', 'Group', 'Dataset', 'Record ID', 'Symbol', 'Description', 'ProbeTarget', 'PubMed_ID', 'Chr', 'Mb', 'Alias', 'Gene_ID', 'Homologene_ID', 'UniGene_ID', 'Strand_Probe', 'Probe_set_specificity', 'Probe_set_BLAT_score', 'Probe_set_BLAT_Mb_start', 'Probe_set_BLAT_Mb_end', 'QTL_Chr', 'QTL_Mb', 'Locus_at_Peak', 'Max_LRS', 'P_value_of_MAX', 'Mean_Expression']
 
     traits_by_group = sort_traits_by_group(trait_list)
 
@@ -77,7 +77,7 @@ def export_search_results_csv(targs):
 
         csv_rows.append(full_headers)
 
-        for trait in group_traits:
+        for i, trait in enumerate(group_traits):
             if getattr(trait, "symbol", None):
                 trait_symbol = getattr(trait, "symbol")
             elif getattr(trait, "abbreviation", None):
@@ -85,6 +85,8 @@ def export_search_results_csv(targs):
             else:
                 trait_symbol = "N/A"
             row_contents = [
+                i + 1,
+                "https://genenetwork.org/show_trait?trait_id=" + str(trait.name) + "&dataset=" + str(trait.dataset.name),
                 trait.dataset.group.species,
                 trait.dataset.group.name,
                 trait.dataset.name,
diff --git a/wqflask/wqflask/marker_regression/gemma_mapping.py b/wqflask/wqflask/marker_regression/gemma_mapping.py
index 68a8d5ba..02f91a32 100644
--- a/wqflask/wqflask/marker_regression/gemma_mapping.py
+++ b/wqflask/wqflask/marker_regression/gemma_mapping.py
@@ -31,16 +31,11 @@ def run_gemma(this_trait, this_dataset, samples, vals, covariates, use_loco, maf
       gwa_output_filename = this_dataset.group.name + "_GWA_" + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
 
       this_chromosomes = this_dataset.species.chromosomes.chromosomes
-      chr_list_string = ""
-      for i in range(len(this_chromosomes)):
-          if i < (len(this_chromosomes) - 1):
-              chr_list_string += this_chromosomes[i+1].name + ","
-          else:
-              chr_list_string += this_chromosomes[i+1].name
+      this_chromosomes_name=[chromosome.name for chromosome in this_chromosomes]
 
+      chr_list_string=",".join(this_chromosomes_name)
       if covariates != "":
           gen_covariates_file(this_dataset, covariates, samples)
-
       if use_loco == "True":
           generate_k_command = GEMMA_WRAPPER_COMMAND + ' --json --loco ' + chr_list_string + ' -- ' + GEMMAOPTS + ' -g %s/%s_geno.txt -p %s/gn2/%s.txt -a %s/%s_snps.txt -gk > %s/gn2/%s.json' % (flat_files('genotype/bimbam'),
                                                                                           genofile_name,
diff --git a/wqflask/wqflask/marker_regression/plink_mapping.py b/wqflask/wqflask/marker_regression/plink_mapping.py
index fd91b6ca..5d675c38 100644
--- a/wqflask/wqflask/marker_regression/plink_mapping.py
+++ b/wqflask/wqflask/marker_regression/plink_mapping.py
@@ -9,11 +9,11 @@ import utility.logger
 logger = utility.logger.getLogger(__name__ )
 
 def run_plink(this_trait, dataset, species, vals, maf):
-    plink_output_filename = webqtlUtil.genRandStr("%s_%s_"%(dataset.group.name, this_trait.name))
+    plink_output_filename = webqtlUtil.genRandStr(f"{dataset.group.name}_{this_trait.name}_")
     gen_pheno_txt_file(dataset, vals)
 
-    plink_command = PLINK_COMMAND + ' --noweb --bfile %s/%s --no-pheno --no-fid --no-parents --no-sex --maf %s --out %s%s --assoc ' % (
-        flat_files('mapping'), dataset.group.name, maf, TMPDIR, plink_output_filename)
+    
+    plink_command = f"{PLINK_COMMAND}  --noweb --bfile {flat_files('mapping')}/{dataset.group.name} --no-pheno --no-fid --no-parents --no-sex --maf {maf} --out { TMPDIR}{plink_output_filename} --assoc "
     logger.debug("plink_command:", plink_command)
 
     os.system(plink_command)
@@ -29,12 +29,12 @@ def gen_pheno_txt_file(this_dataset, vals):
     """Generates phenotype file for GEMMA/PLINK"""
 
     current_file_data = []
-    with open("{}/{}.fam".format(flat_files('mapping'), this_dataset.group.name), "r") as outfile:
+    with open(f"{flat_files('mapping')}/{this_dataset.group.name}.fam", "r") as outfile:
         for i, line in enumerate(outfile):
             split_line = line.split()
             current_file_data.append(split_line)
 
-    with open("{}/{}.fam".format(flat_files('mapping'), this_dataset.group.name), "w") as outfile:
+    with open(f"{flat_files('mapping')}/{this_dataset.group.name}.fam","w") as outfile:
         for i, line in enumerate(current_file_data):
             if vals[i] == "x":
                 this_val = -9
@@ -44,8 +44,8 @@ def gen_pheno_txt_file(this_dataset, vals):
 
 def gen_pheno_txt_file_plink(this_trait, dataset, vals, pheno_filename = ''):
     ped_sample_list = get_samples_from_ped_file(dataset)
-    output_file = open("%s%s.txt" % (TMPDIR, pheno_filename), "wb")
-    header = 'FID\tIID\t%s\n' % this_trait.name
+    output_file = open(f"{TMPDIR}{pheno_filename}.txt", "wb")
+    header = f"FID\tIID\t{this_trait.name}\n"
     output_file.write(header)
 
     new_value_list = []
@@ -65,7 +65,7 @@ def gen_pheno_txt_file_plink(this_trait, dataset, vals, pheno_filename = ''):
     for i, sample in enumerate(ped_sample_list):
         j = i+1
         value = new_value_list[i]
-        new_line += '%s\t%s\t%s\n'%(sample, sample, value)
+        new_line += f"{sample}\t{sample}\t{value}\n"
 
         if j%1000 == 0:
             output_file.write(newLine)
@@ -78,7 +78,7 @@ def gen_pheno_txt_file_plink(this_trait, dataset, vals, pheno_filename = ''):
 
 # get strain name from ped file in order
 def get_samples_from_ped_file(dataset):
-    ped_file= open("{}{}.ped".format(flat_files('mapping'), dataset.group.name), "r")
+    ped_file= open(f"{flat_files('mapping')}{dataset.group.name}.ped","r")
     line = ped_file.readline()
     sample_list=[]
 
@@ -98,7 +98,7 @@ def parse_plink_output(output_filename, species):
 
     threshold_p_value = 1
 
-    result_fp = open("%s%s.qassoc"% (TMPDIR, output_filename), "rb")
+    result_fp = open(f"{TMPDIR}{output_filename}.qassoc","rb")
 
     line = result_fp.readline()
 
@@ -154,7 +154,7 @@ def parse_plink_output(output_filename, species):
 # function: convert line from str to list;
 # output: lineList list
 #######################################################
-def build_line_list(line=None):
+def build_line_list(line=""):
     line_list = line.strip().split(' ')# irregular number of whitespaces between columns
     line_list = [item for item in line_list if item !='']
     line_list = [item.strip() for item in line_list]
diff --git a/wqflask/wqflask/marker_regression/qtlreaper_mapping.py b/wqflask/wqflask/marker_regression/qtlreaper_mapping.py
index 78b1f7b0..505ae295 100644
--- a/wqflask/wqflask/marker_regression/qtlreaper_mapping.py
+++ b/wqflask/wqflask/marker_regression/qtlreaper_mapping.py
@@ -17,22 +17,29 @@ def run_reaper(this_trait, this_dataset, samples, vals, json_data, num_perm, boo
         else:
             genofile_name = this_dataset.group.name
 
-        trait_filename = str(this_trait.name) + "_" + str(this_dataset.name) + "_pheno"
+        trait_filename =f"{str(this_trait.name)}_{str(this_dataset.name)}_pheno"
         gen_pheno_txt_file(samples, vals, trait_filename)
 
-        output_filename = this_dataset.group.name + "_GWA_" + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
+        output_filename = (f"{this_dataset.group.name}_GWA_"+
+            ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
+            )
         bootstrap_filename = None
         permu_filename = None
 
         opt_list = []
         if boot_check and num_bootstrap > 0:
-            bootstrap_filename = this_dataset.group.name + "_BOOTSTRAP_" + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
+            bootstrap_filename = (f"{this_dataset.group.name}_BOOTSTRAP_" + 
+                ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
+                )
 
             opt_list.append("-b")
-            opt_list.append("--n_bootstrap " + str(num_bootstrap))
-            opt_list.append("--bootstrap_output " + webqtlConfig.GENERATED_IMAGE_DIR + bootstrap_filename + ".txt")
+            opt_list.append(f"--n_bootstrap{str(num_bootstrap)}")
+            opt_list.append(f"--bootstrap_output{webqtlConfig.GENERATED_IMAGE_DIR}{bootstrap_filename}.txt")
         if num_perm > 0:
-            permu_filename = this_dataset.group.name + "_PERM_" + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
+            permu_filename =("{this_dataset.group.name}_PERM_" + 
+            ''.join(random.choice(string.ascii_uppercase + 
+                string.digits) for _ in range(6))
+            )
             opt_list.append("-n " + str(num_perm))
             opt_list.append("--permu_output " + webqtlConfig.GENERATED_IMAGE_DIR + permu_filename + ".txt")
         if control_marker != "" and do_control == "true":
@@ -40,13 +47,15 @@ def run_reaper(this_trait, this_dataset, samples, vals, json_data, num_perm, boo
         if manhattan_plot != True:
             opt_list.append("--interval 1")
 
-        reaper_command = REAPER_COMMAND + ' --geno {0}/{1}.geno --traits {2}/gn2/{3}.txt {4} -o {5}{6}.txt'.format(flat_files('genotype'),
-                                                                                                                genofile_name,
-                                                                                                                TEMPDIR,
-                                                                                                                trait_filename,
-                                                                                                                " ".join(opt_list),
-                                                                                                                webqtlConfig.GENERATED_IMAGE_DIR,
-                                                                                                                output_filename)
+        reaper_command = (REAPER_COMMAND + 
+        ' --geno {0}/{1}.geno --traits {2}/gn2/{3}.txt {4} -o {5}{6}.txt'.format(flat_files('genotype'),
+
+                                                                              genofile_name,
+                                                                              TEMPDIR,
+                                                                              trait_filename,
+                                                                              " ".join(opt_list),
+                                                                              webqtlConfig.GENERATED_IMAGE_DIR,
+                                                                            output_filename))
 
         logger.debug("reaper_command:" + reaper_command)
         os.system(reaper_command)
@@ -61,12 +70,13 @@ def run_reaper(this_trait, this_dataset, samples, vals, json_data, num_perm, boo
         suggestive = permu_vals[int(num_perm*0.37-1)]
         significant = permu_vals[int(num_perm*0.95-1)]
 
-    return marker_obs, permu_vals, suggestive, significant, bootstrap_vals, [output_filename, permu_filename, bootstrap_filename]
+    return (marker_obs, permu_vals, suggestive, significant, bootstrap_vals, 
+        [output_filename, permu_filename, bootstrap_filename])
 
 def gen_pheno_txt_file(samples, vals, trait_filename):
     """Generates phenotype file for GEMMA"""
 
-    with open("{}/gn2/{}.txt".format(TEMPDIR, trait_filename), "w") as outfile:
+    with open(f"{TEMPDIR}/gn2/{trait_filename}.txt","w") as outfile:
         outfile.write("Trait\t")
 
         filtered_sample_list = []
@@ -90,7 +100,7 @@ def parse_reaper_output(gwa_filename, permu_filename, bootstrap_filename):
     only_cm = False
     only_mb = False
 
-    with open("{}{}.txt".format(webqtlConfig.GENERATED_IMAGE_DIR, gwa_filename)) as output_file:
+    with open(f"{webqtlConfig.GENERATED_IMAGE_DIR}{gwa_filename}.txt") as output_file:
         for line in output_file:
             if line.startswith("ID\t"):
                 if len(line.split("\t")) < 8:
@@ -137,13 +147,13 @@ def parse_reaper_output(gwa_filename, permu_filename, bootstrap_filename):
 
     permu_vals = []
     if permu_filename:
-        with open("{}{}.txt".format(webqtlConfig.GENERATED_IMAGE_DIR, permu_filename)) as permu_file:
+        with open(f"{webqtlConfig.GENERATED_IMAGE_DIR}{permu_filename}.txt") as permu_file:
             for line in permu_file:
                 permu_vals.append(float(line))
 
     bootstrap_vals = []
     if bootstrap_filename:
-        with open("{}{}.txt".format(webqtlConfig.GENERATED_IMAGE_DIR, bootstrap_filename)) as bootstrap_file:
+        with open(f"{webqtlConfig.GENERATED_IMAGE_DIR}{bootstrap_filename}.txt") as bootstrap_file:
             for line in bootstrap_file:
                 bootstrap_vals.append(int(line))
 
diff --git a/wqflask/wqflask/static/new/css/show_trait.css b/wqflask/wqflask/static/new/css/show_trait.css
index 5e1a279b..39c6ba53 100644
--- a/wqflask/wqflask/static/new/css/show_trait.css
+++ b/wqflask/wqflask/static/new/css/show_trait.css
@@ -145,11 +145,11 @@ input.corr-location {
   display: inline;
 }
 
-div.block-by-index-div {
+div.block-div {
   margin-bottom: 10px;
 }
 
-div.block-by-attribute-div {
+div.block-div-2 {
   margin-top:10px;
   margin-bottom:10px;
 }
diff --git a/wqflask/wqflask/static/new/css/trait_list.css b/wqflask/wqflask/static/new/css/trait_list.css
index 691dcb12..b83655da 100644
--- a/wqflask/wqflask/static/new/css/trait_list.css
+++ b/wqflask/wqflask/static/new/css/trait_list.css
@@ -1,12 +1,20 @@
-div.tool-button-container {

-    min-width: 950px;

-}

-

-div.collection-table-options {

-    min-width: 1100px;

-}

-

-div.show-hide-container {

-    margin-bottom: 5px;

-    margin-top: 10px;

-}
\ No newline at end of file
+div.tool-button-container {
+    min-width: 950px;
+}
+
+div.collection-table-options {
+    min-width: 1100px;
+}
+
+div.show-hide-container {
+    margin-bottom: 5px;
+    margin-top: 10px;
+}
+
+button.active {
+    background: #e5e5e5;
+    -webkit-box-shadow: inset 0px 0px 5px #c1c1c1;
+       -moz-box-shadow: inset 0px 0px 5px #c1c1c1;
+            box-shadow: inset 0px 0px 5px #c1c1c1;
+     outline: none;
+  }
\ No newline at end of file
diff --git a/wqflask/wqflask/static/new/javascript/lodheatmap.js b/wqflask/wqflask/static/new/javascript/lodheatmap.js
index 965a1d53..b82c95ad 100644
--- a/wqflask/wqflask/static/new/javascript/lodheatmap.js
+++ b/wqflask/wqflask/static/new/javascript/lodheatmap.js
@@ -44,7 +44,9 @@ lodheatmap = function() {
       _ref = data.chrnames;
       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
         chr = _ref[_i];
-        xLR[chr[0]] = getLeftRight(data.posByChr[chr[0]]);
+        if (data.posByChr[chr[0]].length > 0){
+          xLR[chr[0]] = getLeftRight(data.posByChr[chr[0]]);
+        }
       }
       zmin = 0;
       zmax = 0;
@@ -144,7 +146,7 @@ lodheatmap = function() {
       }).attr("stroke", "none").attr("stroke-width", "1").on("mouseover.paneltip", function(d) {
         yaxis.select("text#yaxis" + d.lodindex).attr("opacity", 1);
         d3.select(this).attr("stroke", "black");
-        return celltip.show(d);
+        return celltip.show(d, this);
       }).on("mouseout.paneltip", function(d) {
         yaxis.select("text#yaxis" + d.lodindex).attr("opacity", 0);
         d3.select(this).attr("stroke", "none");
diff --git a/wqflask/wqflask/static/new/javascript/panelutil.js b/wqflask/wqflask/static/new/javascript/panelutil.js
index 3c715c81..ea55a7cf 100644
--- a/wqflask/wqflask/static/new/javascript/panelutil.js
+++ b/wqflask/wqflask/static/new/javascript/panelutil.js
@@ -159,7 +159,6 @@ chrscales = function(data, width, chrGap, leftMargin, pad4heatmap, mappingScale)
 
     if (mappingScale == "morgan") {
         max_pos = d3.max(data.posByChr[chr[0]])
-        console.log("max_pos:", max_pos)
         data.xscale[chr[0]] = d3.scale.linear().domain([chrStart[i], max_pos]).range([data.chrStart[i], data.chrEnd[i]]);
     }
     else {
diff --git a/wqflask/wqflask/static/new/javascript/search_results.js b/wqflask/wqflask/static/new/javascript/search_results.js
index 86660126..9ffef4f8 100644
--- a/wqflask/wqflask/static/new/javascript/search_results.js
+++ b/wqflask/wqflask/static/new/javascript/search_results.js
@@ -1,42 +1,87 @@
+change_buttons = function() {
+  var button, buttons, item, num_checked, text, _i, _j, _k, _l, _len, _len2, _len3, _len4, _results, _results2;
+  buttons = ["#add", "#remove"];
+
+  num_checked = 0
+  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){
+      num_checked += 1
+    }
+  }
+
+  if (num_checked === 0) {
+    for (_i = 0, _len = buttons.length; _i < _len; _i++) {
+      button = buttons[_i];
+      $(button).prop("disabled", true);
+    }
+  } else {
+    for (_j = 0, _len2 = buttons.length; _j < _len2; _j++) {
+      button = buttons[_j];
+      $(button).prop("disabled", false);
+    }
+  }
+};
+
 $(function() {
-  var add, change_buttons, checked_traits, deselect_all, invert, remove, removed_traits, select_all;
+  var add, checked_traits, deselect_all, invert, remove, removed_traits, select_all;
 
   checked_traits = null;
   select_all = function() {
-    console.log("selected_all");
-    $(".trait_checkbox").each(function() {
-        $(this).prop('checked', true);
-        if (!$(this).closest('tr').hasClass('selected')) {
-            $(this).closest('tr').addClass('selected')
-        }
-    });
+    table_api = $('#trait_table').DataTable();
+
+    check_cells = table_api.column(0).nodes().to$();
+    for (let i = 0; i < check_cells.length; i++) {
+      check_cells[i].childNodes[0].checked = true;
+    }
+
+    check_rows = table_api.rows().nodes();
+    for (let i =0; i < check_rows.length; i++) {
+      check_rows[i].classList.add("selected");
+    }
+
+    change_buttons();
   };
 
   deselect_all = function() {
-    $(".trait_checkbox").each(function() {
-        $(this).prop('checked', false);
-        if ($(this).closest('tr').hasClass('selected')) {
-            $(this).closest('tr').removeClass('selected')
-        }
-    });
+    table_api = $('#trait_table').DataTable();
+
+    check_cells = table_api.column(0).nodes().to$();
+    for (let i = 0; i < check_cells.length; i++) {
+      check_cells[i].childNodes[0].checked = false;
+    }
+
+    check_rows = table_api.rows().nodes();
+    for (let i =0; i < check_rows.length; i++) {
+      check_rows[i].classList.remove("selected")
+    }
+
+    change_buttons();
   };
 
   invert = function() {
-    $(".trait_checkbox").each(function() {
-        if ($(this).prop('checked') == true) {
-            $(this).prop('checked', false)
-        }
-        else {
-            $(this).prop('checked', true)
-        }
-
-        if ($(this).closest('tr').hasClass('selected')) {
-            $(this).closest('tr').removeClass('selected')
-        }
-        else {
-            $(this).closest('tr').addClass('selected')
-        }
-    });
+    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){
+        check_cells[i].childNodes[0].checked = false;
+      } else {
+        check_cells[i].childNodes[0].checked = true;
+      }
+    }
+
+    check_rows = table_api.rows().nodes();
+    for (let i =0; i < check_rows.length; i++) {
+      if (check_rows[i].classList.contains("selected")){
+        check_rows[i].classList.remove("selected")
+      } else {
+        check_rows[i].classList.add("selected")
+      }
+    }
+
+    change_buttons();
   };
 
   $('#searchbox').keyup(function(){
@@ -77,22 +122,6 @@ $(function() {
       change_buttons();
   });
 
-  $('.trait_checkbox:checkbox').change(function() {
-      change_buttons()
-
-      if ($(this).is(":checked")) {
-          if (!$(this).closest('tr').hasClass('selected')) {
-              $(this).closest('tr').addClass('selected')
-          }
-      }
-      else {
-          if ($(this).closest('tr').hasClass('selected')) {
-              $(this).closest('tr').removeClass('selected')
-          }
-      }
-
-  });
-
   add_to_collection = function() {
     var traits;
     traits = $("#trait_table input:checked").map(function() {
@@ -117,25 +146,8 @@ $(function() {
   };
 
   removed_traits = function() {
-    console.log('in removed_traits with checked_traits:', checked_traits);
     return checked_traits.closest("tr").fadeOut();
   };
-  change_buttons = function() {
-    var button, buttons, item, num_checked, text, _i, _j, _k, _l, _len, _len2, _len3, _len4, _results, _results2;
-    buttons = ["#add", "#remove"];
-    num_checked = $('.trait_checkbox:checked').length;
-    if (num_checked === 0) {
-      for (_i = 0, _len = buttons.length; _i < _len; _i++) {
-        button = buttons[_i];
-        $(button).prop("disabled", true);
-      }
-    } else {
-      for (_j = 0, _len2 = buttons.length; _j < _len2; _j++) {
-        button = buttons[_j];
-        $(button).prop("disabled", false);
-      }
-    }
-  };
 
   submit_bnw = function() {
     trait_data = submit_traits_to_export_or_bnw("trait_table", "submit_bnw")
@@ -157,18 +169,23 @@ $(function() {
     });
     table_dict['headers'] = headers;
 
-    rows = [];
-    trait_table.find('tbody tr').each(function (i, tr) {
-      if (trait_table.find('input[name="searchResult"]:checked').length > 0) {
-        if ($(this).find('input[name="searchResult"]').is(':checked')){
-          rows.push($(this).find('input[name="searchResult"]:checked').val())
-        }
-      }
-      else {
-        rows.push($(this).find('input[name="searchResult"]').val())
+    selected_rows = [];
+    all_rows = []; //ZS: If no rows are checked, export all
+    table_api = $('#' + table_name).DataTable();
+    check_cells = table_api.column(0).nodes().to$();
+    for (let i = 0; i < check_cells.length; i++) {
+      this_node = check_cells[i].childNodes[0];
+      all_rows.push(this_node.value)
+      if (this_node.checked){
+        selected_rows.push(this_node.value)
       }
-    });
-    table_dict['rows'] = rows;
+    }
+
+    if (selected_rows.length > 0){
+      table_dict['rows'] = selected_rows;
+    } else {
+      table_dict['rows'] = all_rows;
+    }
 
     json_table_dict = JSON.stringify(table_dict);
     $('input[name=export_data]').val(json_table_dict);
@@ -253,8 +270,6 @@ $(function() {
   $("#add").click(add_to_collection);
   $("#submit_bnw").click(submit_bnw);
   $("#export_traits").click(export_traits);
-  $('.trait_checkbox, .btn').click(change_buttons);
-
 
   let naturalAsc = $.fn.dataTableExt.oSort["natural-ci-asc"]
   let naturalDesc = $.fn.dataTableExt.oSort["natural-ci-desc"]
diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index a34811f8..87c35984 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -568,14 +568,29 @@ create_value_dropdown = function(value) {
 populate_sample_attributes_values_dropdown = function() {
   var attribute_info, key, sample_attributes, selected_attribute, value, _i, _len, _ref, _ref1, _results;
   $('#attribute_values').empty();
-  sample_attributes = {};
-  attr_keys = Object.keys(js_data.attributes).sort();
-  for (i=0; i < attr_keys.length; i++) {
-    attribute_info = js_data.attributes[attr_keys[i]];
-    sample_attributes[attribute_info.name] = attribute_info.distinct_values;
-  }
-  selected_attribute = $('#exclude_menu').val().replace("_", " ");
-  _ref1 = sample_attributes[selected_attribute];
+  sample_attributes = [];
+
+  var attributes_as_list = Object.keys(js_data.attributes).map(function(key) {
+    return [key, js_data.attributes[key].name];
+  });
+
+  attributes_as_list.sort(function(first, second) {
+    if (second[1] > first[1]){
+      return -1
+    }
+    if (first[1] > second[1]){
+      return 1
+    }
+    return 0
+  });
+
+  for (i=0; i < attributes_as_list.length; i++) {
+    attribute_info = js_data.attributes[attributes_as_list[i][0]]
+    sample_attributes.push(attribute_info.distinct_values);
+  }
+
+  selected_attribute = $('#exclude_column').val()
+  _ref1 = sample_attributes[selected_attribute - 1];
   _results = [];
   for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
     value = _ref1[_i];
@@ -590,25 +605,37 @@ if (Object.keys(js_data.attributes).length){
   populate_sample_attributes_values_dropdown();
 }
 
-$('#exclude_menu').change(populate_sample_attributes_values_dropdown);
+$('#exclude_column').change(populate_sample_attributes_values_dropdown);
 block_by_attribute_value = function() {
   var attribute_name, cell_class, exclude_by_value;
-  attribute_name = $('#exclude_menu').val();
+
+  let exclude_group = $('#exclude_by_attr_group').val();
+  let exclude_column = $('#exclude_column').val();
+
+  if (exclude_group === "other") {
+    var table_api = $('#samples_other').DataTable();
+  } else {
+    var table_api = $('#samples_primary').DataTable();
+  }
+
   exclude_by_value = $('#attribute_values').val();
-  cell_class = ".column_name-" + attribute_name;
-  return $(cell_class).each((function(_this) {
-    return function(index, element) {
-      var row;
-      if ($.trim($(element).text()) === exclude_by_value) {
-        row = $(element).parent('tr');
-        return $(row).find(".trait-value-input").val("x");
-      }
-    };
-  })(this));
+
+  let val_nodes = table_api.column(3).nodes().to$();
+  let exclude_val_nodes = table_api.column(attribute_start_pos + parseInt(exclude_column)).nodes().to$();
+
+  for (i = 0; i < exclude_val_nodes.length; i++) {
+    let this_col_value = exclude_val_nodes[i].childNodes[0].data;
+    let this_val_node = val_nodes[i].childNodes[0];
+
+    if (this_col_value == exclude_by_value){
+      this_val_node.value = "x";
+    }
+  }
 };
-$('#exclude_group').click(block_by_attribute_value);
+$('#exclude_by_attr').click(block_by_attribute_value);
+
 block_by_index = function() {
-  var end_index, error, index, index_list, index_set, index_string, start_index, _i, _j, _k, _len, _len1, _ref, _results;
+  var end_index, error, index, index_list, index_set, index_string, start_index, _i, _j, _k, _len, _len1, _ref;
   index_string = $('#remove_samples_field').val();
   index_list = [];
   _ref = index_string.split(",");
@@ -630,7 +657,7 @@ block_by_index = function() {
       index_list.push(index);
     }
   }
-  _results = [];
+
   let block_group = $('#block_group').val();
   if (block_group === "other") {
     table_api = $('#samples_other').DataTable();
@@ -645,6 +672,65 @@ block_by_index = function() {
   }
 };
 
+filter_by_value = function() {
+  let filter_logic = $('#filter_logic').val();
+  let filter_column = $('#filter_column').val();
+  let filter_value = $('#filter_value').val();
+  let block_group = $('#filter_group').val();
+
+  if (block_group === "other") {
+    var table_api = $('#samples_other').DataTable();
+  } else {
+    var table_api = $('#samples_primary').DataTable();
+  }
+
+  let val_nodes = table_api.column(3).nodes().to$();
+  if (filter_column == "value"){
+    var filter_val_nodes = table_api.column(3).nodes().to$();
+  }
+  else if (filter_column == "stderr"){
+    var filter_val_nodes = table_api.column(5).nodes().to$();
+  }
+  else if (!isNaN(filter_column)){
+    var filter_val_nodes = table_api.column(attribute_start_pos + parseInt(filter_column)).nodes().to$();
+  }
+  else {
+    return false
+  }
+
+  for (i = 0; i < filter_val_nodes.length; i++) {
+    if (filter_column == "value" || filter_column == "stderr"){
+      var this_col_value = filter_val_nodes[i].childNodes[0].value;
+    } else {
+      var this_col_value = filter_val_nodes[i].childNodes[0].data;
+    }
+    let this_val_node = val_nodes[i].childNodes[0];
+
+    if(!isNaN(this_col_value) && !isNaN(filter_value)) {
+      if (filter_logic == "greater_than"){
+        if (parseFloat(this_col_value) <= parseFloat(filter_value)){
+          this_val_node.value = "x";
+        }
+      }
+      else if (filter_logic == "less_than"){
+        if (parseFloat(this_col_value) >= parseFloat(filter_value)){
+          this_val_node.value = "x";
+        }
+      }
+      else if (filter_logic == "greater_or_equal"){
+        if (parseFloat(this_col_value) < parseFloat(filter_value)){
+          this_val_node.value = "x";
+        }
+      }
+      else if (filter_logic == "less_or_equal"){
+        if (parseFloat(this_col_value) > parseFloat(filter_value)){
+          this_val_node.value = "x";
+        }
+      }
+    }
+  }
+};
+
 hide_no_value = function() {
   return $('.value_se').each((function(_this) {
     return function(_index, element) {
@@ -1528,6 +1614,12 @@ $('#block_by_index').click(function(){
   block_by_index();
   edit_data_change();
 });
+
+$('#filter_by_value').click(function(){
+  filter_by_value();
+  edit_data_change();
+})
+
 $('#exclude_group').click(edit_data_change);
 $('#block_outliers').click(edit_data_change);
 $('#reset').click(edit_data_change);
diff --git a/wqflask/wqflask/templates/collections/view.html b/wqflask/wqflask/templates/collections/view.html
index e37f8104..ccec495b 100644
--- a/wqflask/wqflask/templates/collections/view.html
+++ b/wqflask/wqflask/templates/collections/view.html
@@ -73,7 +73,7 @@
                 <form id="export_form" method="POST" action="/export_traits_csv">
                     <button class="btn btn-default" id="select_all" type="button"><span class="glyphicon glyphicon-ok"></span> Select All</button>
                     <button class="btn btn-default" id="invert" type="button"><span class="glyphicon glyphicon-ok"></span> Invert</button>
-                    <button class="btn btn-success" id="add" disabled="disabled" type="button"><i class="icon-plus-sign"></i> Copy</button>
+                    <button class="btn btn-success" id="add" type="button" disabled><i class="icon-plus-sign"></i> Copy</button>
                     <input type="hidden" name="database_name" id="database_name" value="None">
                     <input type="hidden" name="export_data" id="export_data" value="">
                     <input type="hidden" name="file_name" id="file_name" value="collection_table">
@@ -81,7 +81,7 @@
                     <input type="text" id="searchbox" class="form-control" style="width: 200px; display: inline; padding-bottom: 9px;" placeholder="Search Table For ...">
                     <input type="text" id="select_top" class="form-control" style="width: 200px; display: inline; padding-bottom: 9px;" placeholder="Select Top ...">
                     <button class="btn btn-default" id="deselect_all" type="button"><span class="glyphicon glyphicon-remove"></span> Deselect</button>
-                    <button id="remove" class="btn btn-danger" data-url="/collections/remove" disabled="disabled" type="button"><i class="icon-minus-sign"></i> Delete Rows</button>
+                    <button id="remove" class="btn btn-danger" data-url="/collections/remove" type="button" disabled><i class="icon-minus-sign"></i> Delete Rows</button>
                     <button id="delete" class="btn btn-danger submit_special" data-url="/collections/delete" title="Delete this collection" > Delete Collection</button>
                 </form>
             </div>
@@ -109,10 +109,7 @@
                     <tbody>
                     {% for this_trait in trait_obs %}
                         <TR id="trait:{{ this_trait.name }}:{{ this_trait.dataset.name }}">
-                            <TD align="center" style="padding: 0px;">
-                                <INPUT TYPE="checkbox" NAME="searchResult" class="checkbox trait_checkbox"
-                                       VALUE="{{ data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name)) }}">
-                            </TD>
+                            <TD align="center" style="padding: 0px;"><INPUT TYPE="checkbox" NAME="searchResult" class="checkbox trait_checkbox" VALUE="{{ data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name)) }}"></TD>
                             <TD data-export="{{ loop.index }}" align="right">{{ loop.index }}</TD>
                             <TD title="{{ this_trait.dataset.fullname }}" data-export="{{ this_trait.dataset.fullname }}">{{ this_trait.dataset.fullname }}</TD>
                             <TD data-export="{{ this_trait.name }}">
@@ -178,15 +175,21 @@
 
     <script language="javascript" type="text/javascript">
         $(document).ready( function () {
-
-            $('#trait_table tr').click(function(event) {
-                if (event.target.type !== 'checkbox') {
-                    $(':checkbox', this).trigger('click');
-                }
-            });
-
-            console.time("Creating table");
             $('#trait_table').dataTable( {
+                'drawCallback': function( settings ) {
+                      $('#trait_table tr').off().on("click", function(event) {
+                        if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') {
+                          var obj =$(this).find('input');
+                          obj.prop('checked', !obj.is(':checked'));
+                        }
+                        if ($(this).hasClass("selected")){
+                          $(this).removeClass("selected")
+                        } else {
+                          $(this).addClass("selected")
+                        }
+                        change_buttons()
+                      });
+                },
                 "columns": [
                     {
                         "orderDataType": "dom-checkbox",
@@ -220,7 +223,7 @@
                 "paging": false,
                 "orderClasses": true
             } );
-            console.timeEnd("Creating table");
+
 
             submit_special = function(url) {
                 $("#collection_form").attr("action", url);
diff --git a/wqflask/wqflask/templates/correlation_page.html b/wqflask/wqflask/templates/correlation_page.html
index bc0b592c..aa74abf5 100644
--- a/wqflask/wqflask/templates/correlation_page.html
+++ b/wqflask/wqflask/templates/correlation_page.html
@@ -2,9 +2,11 @@
 {% block title %}Correlation Results{% endblock %}
 {% 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="/static/new/css/show_trait.css" />
     <link rel="stylesheet" type="text/css" href="{{ url_for('js', filename='DataTablesExtensions/buttonsBootstrap/css/buttons.bootstrap.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/trait_list.css" />
+    <link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" />
 {% endblock %}
 {% block content %}
     <div class="container" style="min-width: 1250px;">
@@ -73,6 +75,7 @@
         <div>
             <form id="export_form" method="POST" action="/export_traits_csv">
                 <button class="btn btn-default" id="select_all" type="button"><span class="glyphicon glyphicon-ok"></span> Select All</button>
+                <button class="btn btn-default" id="invert" type="button"><span class="glyphicon glyphicon-adjust"></span> Invert</button>
                 <button class="btn btn-success" id="add" type="button" disabled><span class="glyphicon glyphicon-plus-sign"></span> Add</button>
                 <input type="hidden" name="database_name" id="database_name" value="None">
                 <input type="hidden" name="export_data" id="export_data" value="">
@@ -112,10 +115,38 @@
             </div>
             {% endif %}
         </div>
-        <div style="margin-bottom: 5px;">
-            <b>Show/Hide Columns:</b>
+        <div class="show-hide-container">
+          <b>Show/Hide Columns:</b>
+          <br>
+          <button class="toggle-vis" data-column="1">Index</button>
+          <button class="toggle-vis" data-column="2">Record</button>
+          {% if target_dataset.type == 'ProbeSet' %}
+          <button class="toggle-vis" data-column="3">Symbol</button>
+          <button class="toggle-vis" data-column="4">Description</button>
+          <button class="toggle-vis" data-column="5">Location</button>
+          <button class="toggle-vis" data-column="6">Mean</button>
+          <button class="toggle-vis" data-column="7">High P</button>
+          <button class="toggle-vis" data-column="8">Peak Location</button>
+          <button class="toggle-vis" data-column="9">Effect Size</button>
+          {% 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">High P</button>
+          <button class="toggle-vis" data-column="11">Peak Location</button>
+          <button class="toggle-vis" data-column="12">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>
+          <button class="toggle-vis" data-column="5">N</button>
+          <button class="toggle-vis" data-column="6">Sample p({% if corr_method == 'pearson' %}r{% else %}rho{% endif %})</button>
+          {% endif %}
         </div>
-        <div style="width: 100%; min-width: {% if target_dataset.type == "ProbeSet" %}1700px{% elif target_dataset.type == "Publish" %}1600px{% else %}600px{% endif %};">
+        <div style="width: 100%; {% if target_dataset.type == "ProbeSet" %}min-width: 1700px;{% elif target_dataset.type == "Publish" %}min-width: 1600px;{% else %}width: 650px;{% endif %}">
             <table id="trait_table" class="table-hover table-striped cell-border" style="float: left;">
                 <thead>
                     <tr>
@@ -127,77 +158,7 @@
                 </thead>
 
                 <tbody>
-                {% for trait in correlation_results %}
-                    <tr>
-                        <td><INPUT TYPE="checkbox" NAME="searchResult" class="checkbox trait_checkbox" style="padding-right: 0px;" VALUE="{{ data_hmac('{}:{}'.format(trait.name, trait.dataset.name)) }}"></td>
-                        <td data-export="{{ loop.index }}" style="padding-left: 8px; padding-right: 0px; padding-top: 4px; align: right;">{{ loop.index }}</td>
-                        <td data-export="{{ trait.name }}">
-                            <a href="{{ url_for('show_trait_page',
-                                    trait_id = trait.name,
-                                    dataset = trait.dataset.name
-                                    )}}">
-                                {{ trait.name }}
-                            </a>
-                        </td>
-                      {% if target_dataset.type == 'ProbeSet' %}
-                        <td data-export="{{ trait.symbol }}">{{ trait.symbol }}</td>
-                        <td data-export="{{ trait.description_display }}">{{ trait.description_display }}</TD>
-                        <td data-export="{{ trait.location_repr }}" style="white-space: nowrap;">{{ trait.location_repr }}</td>
-                        <td data-export="{{ '%0.3f' % trait.mean|float }}" align="right">{{ '%0.3f' % trait.mean|float }}</td>
-                        <td data-export="{{ '%0.3f'|format(trait.sample_r) }}"" align="right"><a target="_blank" href="corr_scatter_plot?dataset_1={% if dataset.name == 'Temp' %}Temp_{{ dataset.group.name }}{% else %}{{ dataset.name }}{% endif %}&dataset_2={% if trait.dataset.name == 'Temp' %}Temp_{{ trait.dataset.group.name }}{% else %}{{ trait.dataset.name }}{% endif %}&trait_1={{ this_trait.name }}&trait_2={{ trait.name }}">{{ '%0.3f'|format(trait.sample_r) }}</a></td>
-                        <td data-export="{{ trait.num_overlap }}" align="right">{{ trait.num_overlap }}</td>
-                        <td data-export="{{ '%0.3e'|format(trait.sample_p) }}" align="right">{{ '%0.3e'|format(trait.sample_p) }}</td>
-                        {% if trait.lit_corr == "" or trait.lit_corr == 0.000 %}
-                        <td data-export="--" align="right">--</td>
-                        {% else %}
-                        <td data-export="{{ '%0.3f'|format(trait.lit_corr) }}" align="right">{{ '%0.3f'|format(trait.lit_corr) }}</td>
-                        {% endif %}
-                        {% if trait.tissue_corr == "" or trait.tissue_corr == 0.000 %}
-                        <td data-export="--" align="right">--</td>
-                        <td data-export="--" align="right">--</td>
-                        {% else %}
-                        <td data-export="{{ '%0.3f'|format(trait.tissue_corr) }}" align="right">{{ '%0.3f'|format(trait.tissue_corr) }}</td>
-                        <td data-export="{{ '%0.3e'|format(trait.tissue_pvalue) }}" align="right">{{ '%0.3e'|format(trait.tissue_pvalue) }}</td>
-                        {% endif %}
-                        <td data-export={% if trait.LRS_score_repr != "N/A" %}"{{ '%0.1f' % trait.LRS_score_repr|float }}"{% else %}"N/A"{% endif %} align="right">{% if trait.LRS_score_repr != "N/A" %}{{ '%0.1f' % trait.LRS_score_repr|float }}{% else %}N/A{% endif %}</td>
-                        <td data-export="{{ trait.LRS_location_repr }}" align="right">{{ trait.LRS_location_repr }}</td>
-                        <td data-export={% if trait.additive != "" %}"{{ '%0.3f' % trait.additive|float }}"{% else %}"N/A"{% endif %} align="right">{% if trait.additive != "" %}{{ '%0.3f' % trait.additive|float }}{% else %}N/A{% endif %}</td>
-                      {% elif target_dataset.type == "Publish" %}
-                        {% if trait.abbreviation %}
-                        <td title="{{ trait.abbreviation }}" data-export="{{ trait.abbreviation }}">{% if trait.abbreviation|length > 20 %}{{ trait.abbreviation[:20] }}...{% else %}{{ trait.abbreviation }}{% endif %}</td>
-                        {% else %}
-                        <td data-export="N/A">N/A</td>
-                        {% endif %}
-                        <td data-export="{{ trait.description_display }}">{% if trait.description_display|length > 70 %}{{ trait.description_display[:70] }}...{% else %}{{ trait.description_display }}{% endif %}</td>
-                        {% if trait.authors %}
-                        {% set authors_list = trait.authors.split(',') %}
-                        <td data-export="{{ trait.authors }}">{% if authors_list|length > 6 %}{{ authors_list[:6]|join(', ') }}, et al.{% else %}{{ trait.authors }}{% endif %}</td>
-                        {% else %}
-                        <td data-export="N/A">N/A</td>
-                        {% endif %}
-                        <td data-export="{{ trait.pubmed_text }}">
-                            {% if trait.pubmed_text != "N/A" %}
-                            <a href="{{ trait.pubmed_link }}">
-                                {{ trait.pubmed_text }}
-                            </a>
-                            {% else %}
-                            {{ trait.pubmed_text }}
-                            {% endif %}
-                        </td>
-                        <td data-export="{{ '%0.3f'|format(trait.sample_r) }}"" align="right"><a target="_blank" href="corr_scatter_plot?dataset_1={% if dataset.name == 'Temp' %}Temp_{{ dataset.group.name }}{% else %}{{ dataset.name }}{% endif %}&dataset_2={{ trait.dataset.name }}&trait_1={{ this_trait.name }}&trait_2={{ trait.name }}">{{ '%0.3f'|format(trait.sample_r) }}</a></td>
-                        <td data-export="{{ trait.num_overlap }}" align="right">{{ trait.num_overlap }}</td>
-                        <td data-export="{{ '%0.3e'|format(trait.sample_p) }}" align="right">{{ '%0.3e'|format(trait.sample_p) }}</td>
-                        <td data-export="{{ trait.LRS_score_repr }}" align="right">{{ trait.LRS_score_repr }}</td>
-                        <td data-export="{{ trait.LRS_location_repr }}" align="right">{{ trait.LRS_location_repr }}</td>
-                        <td data-export={% if trait.additive != "" %}"{{ '%0.3f' % trait.additive|float }}"{% else %}"N/A"{% endif %} align="right">{% if trait.additive != "" %}{{ '%0.3f' % trait.additive|float }}{% else %}N/A{% endif %}</td>
-                      {% elif target_dataset.type == "Geno" %}
-                        <td data-export="{{ trait.location_repr }}" align="right">{{ trait.location_repr }}</TD>
-                        <td data-export="{{ '%0.3f'|format(trait.sample_r) }}"" align="right"><a target="_blank" href="corr_scatter_plot?dataset_1={% if dataset.name == 'Temp' %}Temp_{{ dataset.group.name }}{% else %}{{ dataset.name }}{% endif %}&dataset_2={{ trait.dataset.name }}&trait_1={{ this_trait.name }}&trait_2={{ trait.name }}">{{ '%0.3f'|format(trait.sample_r) }}</a></td>
-                        <td data-export="{{ trait.num_overlap }}" align="right">{{ trait.num_overlap }}</td>
-                        <td data-export="{{ '%0.3e'|format(trait.sample_p) }}" align="right">{{ '%0.3e'|format(trait.sample_p) }}</td>
-                      {% endif %}
-                    </tr>
-                {% endfor %}
+                    <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td>
                 </tbody>
             </table>
         </div>
@@ -215,6 +176,8 @@
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/buttons/js/dataTables.buttons.min.js') }}"></script>
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/buttons/js/buttons.colVis.min.js') }}"></script>
     <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/plugins/sorting/natural.js') }}"></script>
+    <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/js/all.min.js"></script>
+    <script language="javascript" type="text/javascript" src="https://cdn.datatables.net/scroller/2.0.2/js/dataTables.scroller.min.js"></script>
 
     <script type="text/javascript" charset="utf-8">
         var table_json = {{ json_results | safe }}
@@ -294,51 +257,7 @@
         {% endif %}
 
         $(document).ready( function () {
-
-            $('#trait_table tr').click(function(event) {
-                if (event.target.type !== 'checkbox') {
-                    $(':checkbox', this).trigger('click');
-                }
-            });
-
-            function change_buttons() {
-                buttons = ["#add", "#remove"];
-                num_checked = $('.trait_checkbox:checked').length;
-                if (num_checked === 0) {
-                    for (_i = 0, _len = buttons.length; _i < _len; _i++) {
-                        button = buttons[_i];
-                        $(button).prop("disabled", true);
-                    }
-                } else {
-                    for (_j = 0, _len2 = buttons.length; _j < _len2; _j++) {
-                        button = buttons[_j];
-                        $(button).prop("disabled", false);
-                    }
-                }
-                if ($(this).is(":checked")) {
-                    if (!$(this).closest('tr').hasClass('selected')) {
-                        $(this).closest('tr').addClass('selected')
-                    }
-                }
-                else {
-                    if ($(this).closest('tr').hasClass('selected')) {
-                        $(this).closest('tr').removeClass('selected')
-                    }
-                }
-            }
-
-            console.time("Creating table");
-
-            {% if target_dataset.type == "ProbeSet" %}
             table_conf = {
-                "drawCallback": function( settings ) {
-                     $('#trait_table tr').click(function(event) {
-                         if (event.target.type !== 'checkbox') {
-                             $(':checkbox', this).trigger('click');
-                         }
-                     });
-                     $('.trait_checkbox:checkbox').on("change", change_buttons);
-                },
                 buttons: [
                     {
                         extend: 'columnsToggle',
@@ -352,135 +271,306 @@
                         postfixButtons: [ 'colvisRestore' ]
                     }
                 ],
+                '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")
+                        }
+                      });
+                      $('.trait_checkbox:checkbox').on("change", change_buttons);
+                },
+                "data": table_json,
+                "columns": [
+                    {
+                      'data': null,
+                      'width': "25px",
+                      'orderDataType': "dom-checkbox",
+                      'orderSequence': [ "desc", "asc"],
+                      'render': function(data, type, row, meta) {
+                        return '<input type="checkbox" name="searchResult" class="checkbox trait_checkbox" value="' + data.hmac + '">'
+                      }
+                    },
+                    {
+                      'title': "Index",
+                      'type': "natural",
+                      'width': "30px",
+                      'data': "index"
+                    },
+                    {
+                      'title': "Record",
+                      'type': "natural-minus-na",
+                      'data': null,
+                      'width': "60px",
+                      'render': function(data, type, row, meta) {
+                        return '<a target="_blank" href="/show_trait?trait_id=' + data.trait_id + '&dataset=' + data.dataset + '">' + data.trait_id + '</a>'
+                      }
+                    }{% if target_dataset.type == 'ProbeSet' %},
+                    {
+                      'title': "Symbol",
+                      'type': "natural",
+                      'width': "120px",
+                      'data': "symbol"
+                    },
+                    {
+                      'title': "Description",
+                      'type': "natural",
+                      'data': null,
+                      'render': function(data, type, row, meta) {
+                        try {
+                          return decodeURIComponent(escape(data.description))
+                        } catch(err){
+                          return escape(data.description)
+                        }
+                      }
+                    },
+                    {
+                      'title': "Location",
+                      'type': "natural-minus-na",
+                      'width': "125px",
+                      'data': "location"
+                    },
+                    {
+                      'title': "Mean",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "mean",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "Sample {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "sample_r",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "N",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "num_overlap",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "Sample p({% if corr_method == 'pearson' %}r{% else %}rho{% endif %})",
+                      'type': "natural-minus-na",
+                      'width': "65px",
+                      'data': "sample_p",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "Lit {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "lit_corr",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "Tissue {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "tissue_corr",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "Tissue p({% if corr_method == 'pearson' %}r{% else %}rho{% endif %})",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "tissue_pvalue",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "High P<a href=\"http://gn1.genenetwork.org/glossary.html#LRS\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>",
+                      'type': "natural-minus-na",
+                      'data': "lrs_score",
+                      'width': "60px",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "Peak Location",
+                      'type': "natural-minus-na",
+                      'width': "125px",
+                      'data': "lrs_location"
+                    },
+                    {
+                      'title': "Effect Size<a href=\"http://gn1.genenetwork.org/glossary.html#A\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>",
+                      'type': "natural-minus-na",
+                      'data': "additive",
+                      'width': "85px",
+                      'orderSequence': [ "desc", "asc"]
+                    }{% elif target_dataset.type == 'Publish' %},
+                    {
+                      'title': "Abbreviation",
+                      'type': "natural",
+                      'width': "200px",
+                      'data': null,
+                      'render': function(data, type, row, meta) {
+			                  try {
+                          return decodeURIComponent(escape(data.abbreviation_display))
+			                  } catch(err){
+			                    return data.abbreviation_display
+                        }
+                      }
+                    },
+                    {
+                      'title': "Description",
+                      'type': "natural",
+                      'data': null,
+                      'render': function(data, type, row, meta) {
+			                  try {
+                          return decodeURIComponent(escape(data.description))
+			                  } catch(err){
+			                    return data.description
+                        }
+                      }
+                    },
+                    {
+                      'title': "Authors",
+                      'type': "natural",
+                      'width': "400px",
+                      'data': null,
+                      'render': function(data, type, row, meta) {
+			                  try {
+                          return decodeURIComponent(escape(data.authors_display))
+			                  } catch(err){
+			                    return data.authors_display
+                        }
+                      }
+                    },
+                    {
+                      'title': "Year",
+                      'type': "natural-minus-na",
+                      'data': null,
+                      'width': "80px",
+                      'render': function(data, type, row, meta) {
+                        if (data.pubmed_id != "N/A"){
+                          return '<a href="' + data.pubmed_link + '">' + data.pubmed_text + '</a>'
+                        } else {
+                          return data.pubmed_text
+                        }
+                      },
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "Sample {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "sample_r",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "N",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "num_overlap",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "Sample p({% if corr_method == 'pearson' %}r{% else %}rho{% endif %})",
+                      'type': "natural-minus-na",
+                      'width': "65px",
+                      'data': "sample_p",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "High P<a href=\"http://gn1.genenetwork.org/glossary.html#LRS\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>",
+                      'type': "natural-minus-na",
+                      'data': "lrs_score",
+                      'width': "60px",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "Peak Location",
+                      'type': "natural-minus-na",
+                      'width': "125px",
+                      'data': "lrs_location"
+                    },
+                    {
+                      'title': "Effect Size<a href=\"http://gn1.genenetwork.org/glossary.html#A\" target=\"_blank\" style=\"color: white;\">&nbsp;<i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>",
+                      'type': "natural-minus-na",
+                      'data': "additive",
+                      'width': "85px",
+                      'orderSequence': [ "desc", "asc"]
+                    }{% elif target_dataset.type == 'Geno' %},
+                    {
+                      'title': "Location",
+                      'type': "natural-minus-na",
+                      'width': "120px",
+                      'data': "location"
+                    }, 
+                    {
+                      'title': "Sample {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "sample_r",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "N",
+                      'type': "natural-minus-na",
+                      'width': "40px",
+                      'data': "num_overlap",
+                      'orderSequence': [ "desc", "asc"]
+                    },
+                    {
+                      'title': "Sample p({% if corr_method == 'pearson' %}r{% else %}rho{% endif %})",
+                      'type': "natural-minus-na",
+                      'width': "65px",
+                      'data': "sample_p",
+                      'orderSequence': [ "desc", "asc"]
+                    }{% endif %}
+                ],
                 "columnDefs": [ {
                     "targets": 0,
                     "orderable": false
                 } ],
-                "columns": [
-                    { "type": "natural" },
-                    { "type": "natural" },
-                    { "type": "natural" },
-                    { "type": "natural" },
-                    { "type": "natural", "width": "15%" },
-                    { "type": "natural" },
-                    { "type": "natural" },
-                    { "orderDataType": "dom-innertext", 'orderSequence': [ "desc", "asc"] },
-                    { "type": "natural" },
-                    { "type": "scientific" },
-                    { "type": "natural-minus-na", 'orderSequence': [ "desc", "asc"] },
-                    { "type": "natural-minus-na", 'orderSequence': [ "desc", "asc"] },
-                    { "type": "scientific" },
-                    { "type": "natural-minus-na" },
-                    { "type": "natural-minus-na" },
-                    { "type": "natural-minus-na" }
-                ],
-                "createdRow": function ( row, data, index ) {
-                    $('td', row).eq(4).attr('title', $('td', row).eq(4).text());
-                    if ($('td', row).eq(4).text().length > 40) {
-                        $('td', row).eq(4).text($('td', row).eq(4).text().substring(0, 40));
-                        $('td', row).eq(4).text($('td', row).eq(4).text() + '...')
-                    }
-                },
+                {% if target_dataset.type == 'Geno' %}
+                "order": [[6, "asc" ]],
+                {% else %}
                 "order": [[9, "asc" ]],
-                "sDom": "Btir",
-                "iDisplayLength": -1,
-                "autoWidth": false,
-                "deferRender": true,
+                {% endif %}
+                "sDom": "itir",
+                "autoWidth": true,
                 "bSortClasses": false,
-                "paging": false,
-                "orderClasses": true
+                "scrollY": "100vh",
+                "scroller":  true,
+                "scrollCollapse": true
             }
 
-            {% elif target_dataset.type == "Publish" %}
-            table_conf =  {
-                "drawCallback": function( settings ) {
-                     $('#trait_table tr').click(function(event) {
-                         if (event.target.type !== 'checkbox') {
-                             $(':checkbox', this).trigger('click');
-                         }
-                     });
-                     $('.trait_checkbox:checkbox').on("change", change_buttons);
-                },
-                "buttons": [
-                    {
-                        extend: 'columnsToggle',
-                        columns: function( idx, data, node ) {
-                          if (idx != 0) {
-                            return true;
-                          } else {
-                            return false;
-                          }
-                        },
-                        postfixButtons: [ 'colvisRestore' ]
-                    }
-                ],
-                "columnDefs": [ 
-                    { "targets": 0, "orderable": false }
-                ],  
-                "columns": [
-                    { "type": "natural" },
-                    { "type": "natural" },
-                    { "type": "natural" },
-                    { "type": "natural" },
-                    { "type": "natural", "width": "20%" },
-                    { "type": "natural", "width": "12%" },
-                    { "type": "natural-minus-na" },
-                    { "orderDataType": "dom-innertext", 'orderSequence': [ "desc", "asc"] },
-                    { "type": "natural" },
-                    { "type": "scientific" },
-                    { "type": "natural-minus-na" },
-                    { "type": "natural-minus-na" },
-                    { "type": "natural-minus-na" }
-                ],
-                "order": [[9, "asc" ]],
-                "sDom": "Btir",
-                "iDisplayLength": -1,
-                "autoWidth": false,
-                "deferRender": true,
-                "bSortClasses": false,
-                "paging": false,
-                "orderClasses": true,
-            }
-            {% elif target_dataset.type == "Geno" %}
-            table_conf = {
-                "paging": false,
-                buttons: [
-                    {
-                        extend: 'columnsToggle',
-                        columns: function( idx, data, node ) {
-                          if (idx != 0) {
-                            return true;
-                          } else {
-                            return false;
-                          }
-                        },
-                        postfixButtons: [ 'colvisRestore' ]
-                    }
-                ],
-                "columnDefs": [ 
-                    { "targets": 0, "orderable": false }
-                ],  
-                "columns": [
-                    { "type": "natural" },
-                    { "type": "natural" },
-                    { "type": "natural" },
-                    { "type": "natural" },
-                    { "orderDataType": "dom-innertext", 'orderSequence': [ "desc", "asc"] },
-                    { "type": "natural-minus-na" },
-                    { "type": "scientific" }
-                ],
-                "order": [[6, "asc" ]],
-                "sDom": "Btir",
-                "autoWidth": false,
-                "bDeferRender": true,
-                "scrollY": "800px",
-                "scrollCollapse": false
-            }
-            {% endif %}
+            trait_table = $('#trait_table').DataTable(table_conf);
+
+            trait_table.on( 'order.dt search.dt draw.dt', function () {
+                trait_table.column(1, {search:'applied', order:'applied'}).nodes().each( function (cell, i) {
+                cell.innerHTML = i+1;
+                } );
+            } ).draw();
+
+            $('.toggle-vis').on('click', function (e) {
+              e.preventDefault();
 
-            the_table = $('#trait_table').DataTable(table_conf);
+              // Get the column API object
+              var column = trait_table.column( $(this).attr('data-column') );
 
-            console.timeEnd("Creating table");
+              // Toggle the visibility
+              column.visible( ! column.visible() );
+
+              if (column.visible()){
+                $(this).removeClass("active");
+              } else {
+                $(this).addClass("active");
+              }
+            } );
+
+            $('#redraw').on('click', function (e) {
+              e.preventDefault();
+              trait_table.columns().visible( true );
+              $('.toggle-vis.active').removeClass('active');
+            });
 
             submit_special = function(url) {
                 $("#correlation_form").attr("action", url);
@@ -498,7 +588,7 @@
 
             $("#select_traits").click(function() {
                 console.log("redrawing")
-                the_table.draw();
+                trait_table.draw();
             });
         });
     </script>
diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index 9a28a78e..87c97c50 100644
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -5,6 +5,7 @@
     <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/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" />
     <link rel="stylesheet" type="text/css" href="static/new/css/trait_list.css" />
 {% endblock %}
@@ -128,6 +129,7 @@
               {% endif %}
               <input type="hidden" name="export_data" id="export_data" value="">
               <button class="btn btn-default" id="select_all" type="button"><span class="glyphicon glyphicon-ok"></span> Select</button>
+              <button class="btn btn-default" id="invert" type="button"><span class="glyphicon glyphicon-adjust"></span> Invert</button>
               <button class="btn btn-success" id="add" type="button" disabled><span class="glyphicon glyphicon-plus-sign"></span> Add</button>
               <button class="btn btn-default" id="export_traits">Download <span class="glyphicon glyphicon-download"></span></button>
               <input type="text" id="searchbox" class="form-control" style="width: 200px; display: inline;" placeholder="Search This Table For ...">
@@ -202,42 +204,21 @@
                 }
             });
 
-            function change_buttons() {
-                buttons = ["#add", "#remove"];
-                num_checked = $('.trait_checkbox:checked').length;
-                if (num_checked === 0) {
-                    for (_i = 0, _len = buttons.length; _i < _len; _i++) {
-                        button = buttons[_i];
-                        $(button).prop("disabled", true);
-                    }
-                } else {
-                    for (_j = 0, _len2 = buttons.length; _j < _len2; _j++) {
-                        button = buttons[_j];
-                        $(button).prop("disabled", false);
-                    }
-                }
-                         //});
-                if ($(this).is(":checked")) {
-                    if (!$(this).closest('tr').hasClass('selected')) {
-                        $(this).closest('tr').addClass('selected')
-                    }
-                }
-                else {
-                    if ($(this).closest('tr').hasClass('selected')) {
-                        $(this).closest('tr').removeClass('selected')
-                    }
-                }
-            }
-
             //ZS: Need to make sort by symbol, also need to make sure blank symbol fields at the bottom and symbols starting with numbers below letters
             trait_table = $('#trait_table').DataTable( {
                 'drawCallback': function( settings ) {
-                     $('#trait_table tr').click(function(event) {
-                         if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') {
-                             $(':checkbox', this).trigger('click');
-                         }
-                     });
-                     $('.trait_checkbox:checkbox').on("change", change_buttons);
+                      $('#trait_table tr').off().on("click", function(event) {
+                        if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') {
+                          var obj =$(this).find('input');
+                          obj.prop('checked', !obj.is(':checked'));
+                        }
+                        if ($(this).hasClass("selected")){
+                          $(this).removeClass("selected")
+                        } else {
+                          $(this).addClass("selected")
+                        }
+                        change_buttons()
+                      });
                 },
                 'createdRow': function ( row, data, index ) {
                     $('td', row).eq(0).attr("style", "text-align: center; padding: 0px 10px 2px 10px;");
diff --git a/wqflask/wqflask/templates/show_trait_transform_and_filter.html b/wqflask/wqflask/templates/show_trait_transform_and_filter.html
index 0418d972..d7eac378 100644
--- a/wqflask/wqflask/templates/show_trait_transform_and_filter.html
+++ b/wqflask/wqflask/templates/show_trait_transform_and_filter.html
@@ -4,7 +4,7 @@
         <strong>Reset</strong> option as
         needed.
     </p>
-    <div id="blockMenuSpan" class="input-append block-by-index-div">
+    <div id="blockMenuSpan" class="input-append block-div">
         <label for="remove_samples_field">Block samples by index:</label>
         <input type="text" id="remove_samples_field" placeholder="Example: 3, 5-10, 12">
         <select id="block_group" size="1">
@@ -21,19 +21,64 @@
           Please check that your input is formatted correctly, e.g. <strong>3, 5-10, 12</strong>
     </div>
     {% if sample_groups[0].attributes %}
-    <div class="input-append block-by-attribute-div">
-        <label for="exclude_menu">Block samples by group:</label>
-        <select id="exclude_menu" size=1>
+    <div class="input-append block-div-2">
+        <label for="exclude_column">Block samples by group:</label>
+        <select id="exclude_column" size=1>
           {% for attribute in sample_groups[0].attributes %}
-          <option value="{{ sample_groups[0].attributes[attribute].name.replace(' ', '_') }}">
-              {{ sample_groups[0].attributes[attribute].name }}</option>
+          {% if sample_groups[0].attributes[attribute].distinct_values|length <= 10 %}
+          <option value="{{ loop.index }}">
+              {{ sample_groups[0].attributes[attribute].name }}
+          </option>
+          {% endif %}
           {% endfor %}
         </select>
         <select id="attribute_values" size=1>
         </select>
-        <input type="button" id="exclude_group" class="btn" value="Block">
+        <select id="exclude_by_attr_group" size="1">
+          <option value="primary">
+            {{ sample_group_types['samples_primary'] }}
+          </option>
+          <option value="other">
+            {{ sample_group_types['samples_other'] }}
+          </option>
+        </select>
+        <input type="button" id="exclude_by_attr" class="btn btn-danger" value="Block">
     </div>
     {% endif %}
+    <div id="filterMenuSpan" class="input-append block-div-2">
+      <label for="filter_samples_field">Filter samples by {% if not sample_groups[0].attributes %}value{% endif %} </label>
+      {% if sample_groups[0].attributes %}
+      <select id="filter_column">
+        <option value="value">Value</option>
+        {% if js_data.se_exists %}
+        <option value="stderr">SE</option>
+        {% endif %}
+        {% for attribute in sample_groups[0].attributes %}
+
+        <option value="{{ loop.index }}">
+          {{ sample_groups[0].attributes[attribute].name }}
+        </option>
+
+        {% endfor %}
+      </select>
+      {% endif %}
+      <select id="filter_logic" size="1">
+        <option value="greater_than">></option>
+        <option value="less_than"><</option>
+        <option value="greater_or_equal">≥</option>
+        <option value="less_or_equal">≤</option>
+      </select>
+      <input type="text" id="filter_value" placeholder="Example: 3, 10, 15">
+      <select id="filter_group" size="1">
+        <option value="primary">
+          {{ sample_group_types['samples_primary'] }}
+        </option>
+        <option value="other">
+          {{ sample_group_types['samples_other'] }}
+        </option>
+      </select>
+      <input type="button" id="filter_by_value" class="btn btn-danger" value="Filter">
+    </div>
     <div>
       <input type="button" id="hide_no_value" class="btn btn-default" value="Hide No Value">
       <input type="button" id="block_outliers" class="btn btn-default" value="Block Outliers">