about summary refs log tree commit diff
path: root/wqflask
diff options
context:
space:
mode:
authorZachary Sloan2014-06-06 22:00:30 +0000
committerZachary Sloan2014-06-06 22:00:30 +0000
commit0bdeca3490c1ddbb7fa29165893a97f90eeefba7 (patch)
tree3ea8786848218f459fd8101f6b49a1b7587e08fc /wqflask
parent515662ecabd5d3a90eef6987aa5f8d4dbe63611f (diff)
downloadgenenetwork2-0bdeca3490c1ddbb7fa29165893a97f90eeefba7.tar.gz
Implimented Karl Broman's lodchart code for the interval mapping function.
Suggestive/significant bars and additive effect curve added
Diffstat (limited to 'wqflask')
-rwxr-xr-xwqflask/base/data_set.py85
-rwxr-xr-xwqflask/base/mrna_assay_tissue_data.py11
-rwxr-xr-xwqflask/base/trait.py4
-rwxr-xr-xwqflask/wqflask/correlation/show_corr_results.py53
-rwxr-xr-xwqflask/wqflask/interval_mapping/interval_mapping.py38
-rwxr-xr-xwqflask/wqflask/marker_regression/marker_regression.py216
-rw-r--r--wqflask/wqflask/static/new/css/panelutil.css87
-rwxr-xr-xwqflask/wqflask/static/new/javascript/bar_chart.coffee7
-rwxr-xr-xwqflask/wqflask/static/new/javascript/bar_chart.js7
-rwxr-xr-xwqflask/wqflask/static/new/javascript/chr_manhattan_plot.coffee45
-rwxr-xr-xwqflask/wqflask/static/new/javascript/chr_manhattan_plot.js32
-rw-r--r--wqflask/wqflask/static/new/javascript/interval_map_new.coffee71
-rw-r--r--wqflask/wqflask/static/new/javascript/interval_map_new.js48
-rw-r--r--wqflask/wqflask/static/new/javascript/lod_chart.coffee550
-rw-r--r--wqflask/wqflask/static/new/javascript/lod_chart.js562
-rwxr-xr-xwqflask/wqflask/static/new/javascript/marker_regression.coffee48
-rwxr-xr-xwqflask/wqflask/static/new/javascript/marker_regression.js36
-rw-r--r--wqflask/wqflask/static/new/javascript/panelutil.coffee205
-rw-r--r--wqflask/wqflask/static/new/javascript/panelutil.js324
-rw-r--r--wqflask/wqflask/static/new/javascript/scatterplot.coffee407
-rw-r--r--wqflask/wqflask/static/new/javascript/scatterplot.js406
-rwxr-xr-xwqflask/wqflask/static/new/javascript/show_trait_mapping_tools.coffee10
-rwxr-xr-xwqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js10
-rw-r--r--wqflask/wqflask/static/new/js_external/d3-tip.min.js1
-rwxr-xr-xwqflask/wqflask/templates/correlation_page.html26
-rwxr-xr-xwqflask/wqflask/templates/interval_mapping.html9
-rwxr-xr-xwqflask/wqflask/templates/show_trait_details.html4
-rwxr-xr-xwqflask/wqflask/templates/show_trait_mapping_tools.html4
-rwxr-xr-xwqflask/wqflask/templates/show_trait_progress_bar.html13
-rwxr-xr-xwqflask/wqflask/templates/show_trait_statistics_new.html8
-rwxr-xr-xwqflask/wqflask/user_manager.py5
-rwxr-xr-xwqflask/wqflask/views.py2
32 files changed, 3156 insertions, 178 deletions
diff --git a/wqflask/base/data_set.py b/wqflask/base/data_set.py
index f4ca3ae0..a2b13748 100755
--- a/wqflask/base/data_set.py
+++ b/wqflask/base/data_set.py
@@ -167,28 +167,56 @@ class Markers(object):
             marker['Mb'] = float(marker['Mb'])
             
         self.markers = markers
-        print("self.markers:", self.markers)
+        #print("self.markers:", self.markers)
     
     def add_pvalues(self, p_values):
         print("length of self.markers:", len(self.markers))
         print("length of p_values:", len(p_values))
         
-        # THIS IS only needed for the case when we are limiting the number of p-values calculated
-        if len(self.markers) < len(p_values):
-            self.markers = self.markers[:len(p_values)]
-        
-        for marker, p_value in itertools.izip(self.markers, p_values):
-            if not p_value:
-                continue
-            marker['p_value'] = float(p_value)
-            if math.isnan(marker['p_value']) or marker['p_value'] <= 0:
-                marker['lod_score'] = 0
-                marker['lrs_value'] = 0
-            else:
-                marker['lod_score'] = -math.log10(marker['p_value'])
-                #Using -log(p) for the LRS; need to ask Rob how he wants to get LRS from p-values
-                marker['lrs_value'] = -math.log10(marker['p_value']) * 4.61
+        if type(p_values) is list:
+            # THIS IS only needed for the case when we are limiting the number of p-values calculated
+            #if len(self.markers) > len(p_values):
+            #    self.markers = self.markers[:len(p_values)]
+            
+            for marker, p_value in itertools.izip(self.markers, p_values):
+                if not p_value:
+                    continue
+                marker['p_value'] = float(p_value)
+                if math.isnan(marker['p_value']) or marker['p_value'] <= 0:
+                    marker['lod_score'] = 0
+                    marker['lrs_value'] = 0
+                else:
+                    marker['lod_score'] = -math.log10(marker['p_value'])
+                    #Using -log(p) for the LRS; need to ask Rob how he wants to get LRS from p-values
+                    marker['lrs_value'] = -math.log10(marker['p_value']) * 4.61
+        elif type(p_values) is dict:
+            filtered_markers = []
+            for marker in self.markers:
+                #print("marker[name]", marker['name'])
+                #print("p_values:", p_values)
+                if marker['name'] in p_values:
+                    #print("marker {} IS in p_values".format(i))
+                    marker['p_value'] = p_values[marker['name']]
+                    if math.isnan(marker['p_value']) or (marker['p_value'] <= 0):
+                        marker['lod_score'] = 0
+                        marker['lrs_value'] = 0
+                    else:
+                        marker['lod_score'] = -math.log10(marker['p_value'])
+                        #Using -log(p) for the LRS; need to ask Rob how he wants to get LRS from p-values
+                        marker['lrs_value'] = -math.log10(marker['p_value']) * 4.61
+                    filtered_markers.append(marker)
+                #else:
+                    #print("marker {} NOT in p_values".format(i))
+                    #self.markers.remove(marker)
+                    #del self.markers[i]
+            self.markers = filtered_markers
+            
 
+        #for i, marker in enumerate(self.markers):
+        #    if not 'p_value' in marker:
+        #        #print("self.markers[i]", self.markers[i])
+        #        del self.markers[i]
+        #        #self.markers.remove(self.markers[i])
 
 class HumanMarkers(Markers):
     
@@ -226,15 +254,15 @@ class HumanMarkers(Markers):
         #    #Using -log(p) for the LRS; need to ask Rob how he wants to get LRS from p-values
         #    marker['lrs_value'] = -math.log10(marker['p_value']) * 4.61
         
-        print("p_values2:", p_values)
+        #print("p_values2:", pf(p_values))
         super(HumanMarkers, self).add_pvalues(p_values)
         
-        with Bench("deleting markers"):
-            markers = []
-            for marker in self.markers:
-                if not marker['Mb'] <= 0 and not marker['chr'] == 0:
-                    markers.append(marker)
-            self.markers = markers
+        #with Bench("deleting markers"):
+        #    markers = []
+        #    for marker in self.markers:
+        #        if not marker['Mb'] <= 0 and not marker['chr'] == 0:
+        #            markers.append(marker)
+        #    self.markers = markers
         
     
 
@@ -254,7 +282,7 @@ class DatasetGroup(object):
             self.name = "BXD"
         
         self.f1list = None
-        self.parlist = None        
+        self.parlist = None
         self.get_f1_parent_strains()
         #print("parents/f1s: {}:{}".format(self.parlist, self.f1list))
         
@@ -476,8 +504,9 @@ class DataSet(object):
         else:
             self.samplelist = self.group.samplelist
             
-        if (self.group.parlist + self.group.f1list) in self.samplelist:
-            self.samplelist += self.group.parlist + self.group.f1list
+        if self.group.parlist != None and self.group.f1list != None:
+            if (self.group.parlist + self.group.f1list) in self.samplelist:
+                self.samplelist += self.group.parlist + self.group.f1list
         
         query = """
             SELECT Strain.Name, Strain.Id FROM Strain, Species
@@ -547,7 +576,11 @@ class DataSet(object):
                         order by {}.Id
                         """.format(*mescape(self.type, self.type, self.type, self.type,
                                    self.name, dataset_type, self.type, self.type, dataset_type))
+                        
+            #print("trait data query: ", query)
+            
             results = g.db.execute(query).fetchall()
+            #print("query results:", results)
             trait_sample_data.append(results)
 
         trait_count = len(trait_sample_data[0])
diff --git a/wqflask/base/mrna_assay_tissue_data.py b/wqflask/base/mrna_assay_tissue_data.py
index be5df657..1a05fce7 100755
--- a/wqflask/base/mrna_assay_tissue_data.py
+++ b/wqflask/base/mrna_assay_tissue_data.py
@@ -19,6 +19,8 @@ class MrnaAssayTissueData(object):
         if self.gene_symbols == None:
             self.gene_symbols = []
         
+        print("self.gene_symbols:", self.gene_symbols)
+        
         self.data = collections.defaultdict(Bunch)
             
         #self.gene_id_dict ={}
@@ -28,7 +30,7 @@ class MrnaAssayTissueData(object):
         #self.desc_dict = {}
         #self.probe_target_desc_dict = {}
         
-        query =  '''select t.Symbol, t.GeneId, t.DataId,t.Chr, t.Mb, t.description, t.Probe_Target_Description
+        query =  '''select t.Symbol, t.GeneId, t.DataId, t.Chr, t.Mb, t.description, t.Probe_Target_Description
                         from (
                         select Symbol, max(Mean) as maxmean
                         from TissueProbeSetXRef
@@ -53,6 +55,7 @@ class MrnaAssayTissueData(object):
                     '''.format(in_clause)
 
         results = g.db.execute(query).fetchall()
+        
         for result in results:
             symbol = result[0]
             if symbol in gene_symbols:
@@ -66,7 +69,7 @@ class MrnaAssayTissueData(object):
                 self.data[symbol].description = result.description
                 self.data[symbol].probe_target_description = result.Probe_Target_Description
 
-        #print("self.data: ", pf(self.data))
+        print("self.data: ", pf(self.data))
 
     ###########################################################################
     #Input: cursor, symbolList (list), dataIdDict(Dict)
@@ -79,6 +82,8 @@ class MrnaAssayTissueData(object):
     def get_symbol_values_pairs(self):
         id_list = [self.data[symbol].data_id for symbol in self.data]
 
+        print("id_list:", id_list)
+
         symbol_values_dict = {}
         
         query = """SELECT TissueProbeSetXRef.Symbol, TissueProbeSetData.value
@@ -86,6 +91,8 @@ class MrnaAssayTissueData(object):
                    WHERE TissueProbeSetData.Id IN {} and
                          TissueProbeSetXRef.DataId = TissueProbeSetData.Id""".format(db_tools.create_in_clause(id_list))
         
+        print("TISSUE QUERY:", query)
+        
         results = g.db.execute(query).fetchall()
         for result in results:
             if result.Symbol.lower() not in symbol_values_dict:
diff --git a/wqflask/base/trait.py b/wqflask/base/trait.py
index 712d9af5..3f80d4a4 100755
--- a/wqflask/base/trait.py
+++ b/wqflask/base/trait.py
@@ -40,6 +40,7 @@ class GeneralTrait(object):
         else:
             self.dataset = kw.get('dataset')
         self.name = kw.get('name')                 # Trait ID, ProbeSet ID, Published ID, etc.
+        print("THE NAME IS:", self.name)
         self.cellid = kw.get('cellid')
         self.identification = kw.get('identification', 'un-named trait')
         self.haveinfo = kw.get('haveinfo', False)
@@ -295,6 +296,9 @@ class GeneralTrait(object):
                             PublishXRef.InbredSetId = PublishFreeze.InbredSetId AND
                             PublishFreeze.Id = %s
                     """ % (self.name, self.dataset.id)
+            
+            print("query is:", query)        
+        
             trait_info = g.db.execute(query).fetchone()
         #XZ, 05/08/2009: Xiaodong add this block to use ProbeSet.Id to find the probeset instead of just using ProbeSet.Name
         #XZ, 05/08/2009: to avoid the problem of same probeset name from different platforms.
diff --git a/wqflask/wqflask/correlation/show_corr_results.py b/wqflask/wqflask/correlation/show_corr_results.py
index 0b66bc61..1cc932a0 100755
--- a/wqflask/wqflask/correlation/show_corr_results.py
+++ b/wqflask/wqflask/correlation/show_corr_results.py
@@ -93,8 +93,13 @@ class CorrelationResults(object):
         # get trait list from db (database name)
         # calculate correlation with Base vector and targets
         
+        print("TESTING...")
+        
         with Bench("Doing correlations"):
             helper_functions.get_species_dataset_trait(self, start_vars)
+            
+            print("TRAIT SYMBOL:", self.this_trait.symbol)
+            
             self.dataset.group.read_genotype_file()
 
             corr_samples_group = start_vars['corr_samples_group']
@@ -108,9 +113,11 @@ class CorrelationResults(object):
             #The two if statements below append samples to the sample list based upon whether the user
             #rselected Primary Samples Only, Other Samples Only, or All Samples
 
-            primary_samples = (self.dataset.group.parlist +
-                               self.dataset.group.f1list +
-                               self.dataset.group.samplelist)
+            primary_samples = self.dataset.group.samplelist
+            if self.dataset.group.parlist != None:
+                primary_samples += self.dataset.group.parlist
+            if self.dataset.group.f1list != None:
+                primary_samples += self.dataset.group.f1list
 
             #If either BXD/whatever Only or All Samples, append all of that group's samplelist
             if corr_samples_group != 'samples_other':
@@ -156,6 +163,7 @@ class CorrelationResults(object):
 
 
             for _trait_counter, trait in enumerate(self.correlation_data.keys()[:self.return_number]):
+                print("trait name:", trait)
                 trait_object = GeneralTrait(dataset=self.dataset, name=trait, get_qtl_info=True)
                 
                 (trait_object.sample_r,
@@ -329,8 +337,8 @@ class CorrelationResults(object):
                                                            key=lambda t: -abs(t[1][1])))
             
             return tissue_corr_data
-                    
-                    
+
+
     def do_lit_correlation_for_trait_list(self):
 
         input_trait_mouse_gene_id = self.convert_to_mouse_gene_id(self.dataset.group.species.lower(), self.this_trait.geneid)
@@ -348,14 +356,14 @@ class CorrelationResults(object):
                        FROM LCorrRamin3
                        WHERE GeneId1='%s' and
                              GeneId2='%s'
-                    """ % (escape(trait.mouse_gene_id), escape(input_trait_mouse_gene_id))
+                    """ % (escape(str(trait.mouse_gene_id)), escape(str(input_trait_mouse_gene_id)))
                 ).fetchone()
                 if not result:
                     result = g.db.execute("""SELECT value
                        FROM LCorrRamin3
                        WHERE GeneId2='%s' and
                              GeneId1='%s'
-                    """ % (escape(trait.mouse_gene_id), escape(input_trait_mouse_gene_id))
+                    """ % (escape(str(trait.mouse_gene_id)), escape(str(input_trait_mouse_gene_id)))
                     ).fetchone()
                 
                 if result:
@@ -419,20 +427,30 @@ class CorrelationResults(object):
             mouse_gene_id = gene_id
             
         elif species == 'rat':
-            mouse_gene_id = g.db.execute(
-                """SELECT mouse
+            
+            query = """SELECT mouse
                    FROM GeneIDXRef
-                   WHERE rat='%d'
-                """, escape(int(gene_id))).fetchone().mouse
+                   WHERE rat='%s'""" % escape(gene_id)
+            
+            print("GENE_ID QUERY: ", query)
+            
+            result = g.db.execute(query).fetchone()
+            if result != None:
+                mouse_gene_id = result.mouse
             
         elif species == 'human':
-            mouse_gene_id = g.db.execute(
-                """SELECT mouse
+           
+            query = """SELECT mouse
                    FROM GeneIDXRef
-                   WHERE human='%d'
-                """, escape(int(gene_id))).fetchone().mouse
+                   WHERE human='%s'""" % escape(gene_id)
+            
+            print("GENE_ID QUERY: ", query)
+            
+            result = g.db.execute(query).fetchone()
+            if result != None:
+                mouse_gene_id = result.mouse
 
-        #print("mouse_geneid:", mouse_geneid)
+        print("mouse_geneid:", mouse_gene_id)
         
         return mouse_gene_id        
     
@@ -456,6 +474,8 @@ class CorrelationResults(object):
                 this_trait_vals.append(sample_value)
                 target_vals.append(target_sample_value)
 
+        print("trait:", trait)
+
         this_trait_vals, target_vals, num_overlap = corr_result_helpers.normalize_values(
             this_trait_vals, target_vals)
 
@@ -1010,6 +1030,7 @@ class CorrelationResults(object):
                     values_2.append(target_value)
             correlation = calCorrelation(values_1, values_2)
             self.correlation_data[trait] = correlation
+        
 
         """
         correlations = []
diff --git a/wqflask/wqflask/interval_mapping/interval_mapping.py b/wqflask/wqflask/interval_mapping/interval_mapping.py
index f0985cc2..d28cb24b 100755
--- a/wqflask/wqflask/interval_mapping/interval_mapping.py
+++ b/wqflask/wqflask/interval_mapping/interval_mapping.py
@@ -23,6 +23,7 @@ from base.trait import GeneralTrait
 from base import data_set
 from base import species
 from base import webqtlConfig
+from utility import webqtlUtil
 from wqflask.my_pylmm.data import prep_data
 from wqflask.my_pylmm.pyLMM import lmm
 from wqflask.my_pylmm.pyLMM import input
@@ -55,7 +56,10 @@ class IntervalMapping(object):
  
         self.set_options(start_vars)
  
+        self.json_data = {}
+ 
         if self.method == "qtl_reaper":
+            self.json_data['lodnames'] = ['lod.hk']
             self.gen_reaper_results(tempdata)
         else:
             self.gen_pylmm_results(tempdata)
@@ -63,14 +67,24 @@ class IntervalMapping(object):
 
         #Get chromosome lengths for drawing the interval map plot
         chromosome_mb_lengths = {}
+        self.json_data['chrnames'] = []
         for key in self.species.chromosomes.chromosomes.keys():
+            self.json_data['chrnames'].append(self.species.chromosomes.chromosomes[key].name)
+            
             chromosome_mb_lengths[key] = self.species.chromosomes.chromosomes[key].mb_length
         
         #print("self.qtl_results:", self.qtl_results)
         
+        print("JSON DATA:", self.json_data)
+        
+        #os.chdir(webqtlConfig.TMPDIR)
+        json_filename = webqtlUtil.genRandStr(prefix="intmap_")
+        json.dumps(self.json_data, webqtlConfig.TMPDIR + json_filename)
+        
         self.js_data = dict(
             chromosomes = chromosome_mb_lengths,
             qtl_results = self.qtl_results,
+            json_data = self.json_data
             #lrs_lod = self.lrs_lod,
         )
 
@@ -144,8 +158,18 @@ class IntervalMapping(object):
 
         #Need to convert the QTL objects that qtl reaper returns into a json serializable dictionary
         self.qtl_results = []
+        self.json_data['chr'] = []
+        self.json_data['pos'] = []
+        self.json_data['lod.hk'] = []
+        self.json_data['additive'] = []
+        self.json_data['markernames'] = []
         for qtl in reaper_results:
             reaper_locus = qtl.locus
+            self.json_data['chr'].append(reaper_locus.chr)
+            self.json_data['pos'].append(reaper_locus.Mb)
+            self.json_data['lod.hk'].append(qtl.lrs)
+            self.json_data['markernames'].append(reaper_locus.name)
+            self.json_data['additive'].append(qtl.additive)
             locus = {"name":reaper_locus.name, "chr":reaper_locus.chr, "cM":reaper_locus.cM, "Mb":reaper_locus.Mb}
             qtl = {"lrs": qtl.lrs, "locus": locus, "additive": qtl.additive}
             self.qtl_results.append(qtl)
@@ -166,8 +190,11 @@ class IntervalMapping(object):
         self.lrs_array = genotype.permutation(strains = trimmed_samples,
                                                    trait = trimmed_values, 
                                                    nperm= self.num_permutations)
+        
         self.suggestive = self.lrs_array[int(self.num_permutations*0.37-1)]
         self.significant = self.lrs_array[int(self.num_permutations*0.95-1)]
+        self.json_data['suggestive'] = self.suggestive
+        self.json_data['significant'] = self.significant
 
         print("samples:", trimmed_samples)
 
@@ -179,10 +206,21 @@ class IntervalMapping(object):
             reaper_results = genotype.regression(strains = trimmed_samples,
                                                           trait = trimmed_values)
 
+        self.json_data['chr'] = []
+        self.json_data['pos'] = []
+        self.json_data['lod.hk'] = []
+        self.json_data['additive'] = []
+        self.json_data['markernames'] = []
+
         #Need to convert the QTL objects that qtl reaper returns into a json serializable dictionary
         self.qtl_results = []
         for qtl in reaper_results:
             reaper_locus = qtl.locus
+            self.json_data['chr'].append(reaper_locus.chr)
+            self.json_data['pos'].append(reaper_locus.Mb)
+            self.json_data['lod.hk'].append(qtl.lrs)
+            self.json_data['markernames'].append(reaper_locus.name)
+            self.json_data['additive'].append(qtl.additive)
             locus = {"name":reaper_locus.name, "chr":reaper_locus.chr, "cM":reaper_locus.cM, "Mb":reaper_locus.Mb}
             qtl = {"lrs_value": qtl.lrs, "chr":reaper_locus.chr, "Mb":reaper_locus.Mb,
                    "cM":reaper_locus.cM, "name":reaper_locus.name, "additive":qtl.additive}
diff --git a/wqflask/wqflask/marker_regression/marker_regression.py b/wqflask/wqflask/marker_regression/marker_regression.py
index c220d2c9..525a2253 100755
--- a/wqflask/wqflask/marker_regression/marker_regression.py
+++ b/wqflask/wqflask/marker_regression/marker_regression.py
@@ -22,6 +22,8 @@ import simplejson as json
 from redis import Redis
 Redis = Redis()
 
+from flask import Flask, g
+
 from base.trait import GeneralTrait
 from base import data_set
 from base import species
@@ -60,18 +62,20 @@ class MarkerRegression(object):
             qtl_results = self.run_gemma()
         elif self.mapping_method == "plink":
             qtl_results = self.run_plink()
+            #print("qtl_results:", pf(qtl_results))
         elif self.mapping_method == "pylmm":
             #self.qtl_results = self.gen_data(tempdata)
             qtl_results = self.gen_data(str(temp_uuid))
         
-        self.lod_cutoff = self.get_lod_score_cutoff()
+        self.lod_cutoff = 2
         self.filtered_markers = []
         for marker in qtl_results:
-            #if marker['lod_score'] > self.lod_cutoff:
-            if marker['lod_score'] > 1:
+            if marker['chr'] > 0:
                 self.filtered_markers.append(marker)
+            #if marker['lod_score'] > self.lod_cutoff:
+
                 
-        print("filtered_markers:", self.filtered_markers)
+        #print("filtered_markers:", self.filtered_markers)
 
         #Get chromosome lengths for drawing the manhattan plot
         chromosome_mb_lengths = {}
@@ -86,6 +90,8 @@ class MarkerRegression(object):
     def run_gemma(self):
         """Generates p-values for each marker using GEMMA"""
         
+        self.dataset.group.get_markers()
+        
         #filename = webqtlUtil.genRandStr("{}_{}_".format(self.dataset.group.name, self.this_trait.name))
         self.gen_pheno_txt_file()
 
@@ -156,6 +162,205 @@ class MarkerRegression(object):
     def run_plink(self):
     
         os.chdir("/home/zas1024/plink")
+        
+        self.dataset.group.get_markers()
+        
+        plink_output_filename = webqtlUtil.genRandStr("%s_%s_"%(self.dataset.group.name, self.this_trait.name))
+        
+        self.gen_pheno_txt_file_plink(pheno_filename = plink_output_filename)
+        
+        plink_command = './plink --noweb --ped %s.ped --no-fid --no-parents --no-sex --no-pheno --map %s.map --pheno %s/%s.txt --pheno-name %s --missing-phenotype -9999 --out %s%s --assoc ' % (self.dataset.group.name, self.dataset.group.name, webqtlConfig.TMPDIR, plink_output_filename, self.this_trait.name, webqtlConfig.TMPDIR, plink_output_filename)
+        
+        os.system(plink_command)
+
+        count, p_values = self.parse_plink_output(plink_output_filename)
+        #gemma_command = './gemma -bfile %s -k output_%s.cXX.txt -lmm 1 -o %s_output' % (
+        #                                                                                         self.dataset.group.name,
+        #                                                                                         self.dataset.group.name,
+        #                                                                                         self.dataset.group.name)
+        #print("gemma_command:" + gemma_command)
+        #
+        #os.system(gemma_command)
+        #
+        #included_markers, p_values = self.parse_gemma_output()
+        #
+        #self.dataset.group.get_specified_markers(markers = included_markers)
+        
+        #for marker in self.dataset.group.markers.markers:
+        #    if marker['name'] not in included_markers:
+        #        print("marker:", marker)
+        #        self.dataset.group.markers.markers.remove(marker)
+        #        #del self.dataset.group.markers.markers[marker]
+        
+        print("p_values:", pf(p_values))
+        
+        self.dataset.group.markers.add_pvalues(p_values)
+
+        return self.dataset.group.markers.markers
+    
+    
+    def gen_pheno_txt_file_plink(self, pheno_filename = ''):
+        ped_sample_list = self.get_samples_from_ped_file()	
+        output_file = open("%s%s.txt" % (webqtlConfig.TMPDIR, pheno_filename), "wb")
+        header = 'FID\tIID\t%s\n' % self.this_trait.name
+        output_file.write(header)
+    
+        new_value_list = []
+        
+        #if valueDict does not include some strain, value will be set to -9999 as missing value
+        for i, sample in enumerate(ped_sample_list):
+            try:
+                value = self.vals[i]
+                value = str(value).replace('value=','')
+                value = value.strip()
+            except:
+                value = -9999
+    
+            new_value_list.append(value)
+            
+            
+        new_line = ''
+        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)
+            
+            if j%1000 == 0:
+                output_file.write(newLine)
+                new_line = ''
+        
+        if new_line:
+            output_file.write(new_line)
+            
+        output_file.close()
+    
+    # get strain name from ped file in order
+    def get_samples_from_ped_file(self):
+        
+        os.chdir("/home/zas1024/plink")
+        
+        ped_file= open("{}.ped".format(self.dataset.group.name),"r")
+        line = ped_file.readline()
+        sample_list=[]
+        
+        while line:
+            lineList = string.split(string.strip(line), '\t')
+            lineList = map(string.strip, lineList)
+            
+            sample_name = lineList[0]
+            sample_list.append(sample_name)
+            
+            line = ped_file.readline()
+        
+        return sample_list
+    
+    ################################################################
+    # Generate Chr list, Chr OrderId and Retrieve Length Information 
+    ################################################################		
+    #def getChrNameOrderIdLength(self,RISet=''):
+    #    try:
+    #        query = """
+    #            Select
+    #                Chr_Length.Name,Chr_Length.OrderId,Length from Chr_Length, InbredSet
+    #            where
+    #                Chr_Length.SpeciesId = InbredSet.SpeciesId AND
+    #                InbredSet.Name = '%s' 
+    #            Order by OrderId
+    #            """ % (self.dataset.group.name)
+    #        results =g.db.execute(query).fetchall()
+    #        ChrList=[]
+    #        ChrLengthMbList=[]
+    #        ChrNameOrderIdDict={}
+    #        ChrOrderIdNameDict={}
+    #        
+    #        for item in results:
+    #            ChrList.append(item[0])
+    #            ChrNameOrderIdDict[item[0]]=item[1] # key is chr name, value is orderId
+    #            ChrOrderIdNameDict[item[1]]=item[0] # key is orderId, value is chr name
+    #            ChrLengthMbList.append(item[2])				
+    #            
+    #    except:
+    #        ChrList=[]
+    #        ChrNameOrderIdDict={}
+    #        ChrLengthMbList=[]
+    #        
+    #    return ChrList,ChrNameOrderIdDict,ChrOrderIdNameDict,ChrLengthMbList
+    
+    
+    def parse_plink_output(self, output_filename):
+        plink_results={}
+    
+        threshold_p_value = 0.01
+    
+        result_fp = open("%s%s.qassoc"% (webqtlConfig.TMPDIR, output_filename), "rb")
+        
+        header_line = result_fp.readline()# read header line
+        line = result_fp.readline()
+        
+        value_list = [] # initialize value list, this list will include snp, bp and pvalue info
+        p_value_dict = {}
+        count = 0
+        
+        while line:
+            #convert line from str to list
+            line_list = self.build_line_list(line=line)
+    
+            # only keep the records whose chromosome name is in db
+            if self.species.chromosomes.chromosomes.has_key(int(line_list[0])) and line_list[-1] and line_list[-1].strip()!='NA':
+    
+                chr_name = self.species.chromosomes.chromosomes[int(line_list[0])]
+                snp = line_list[1]
+                BP = line_list[2]
+                p_value = float(line_list[-1])
+                if threshold_p_value >= 0 and threshold_p_value <= 1:
+                    if p_value < threshold_p_value:
+                        p_value_dict[snp] = p_value
+                
+                if plink_results.has_key(chr_name):
+                    value_list = plink_results[chr_name]
+                    
+                    # pvalue range is [0,1]
+                    if threshold_p_value >=0 and threshold_p_value <= 1:
+                        if p_value < threshold_p_value:
+                            value_list.append((snp, BP, p_value))
+                            count += 1
+                    
+                    plink_results[chr_name] = value_list
+                    value_list = []
+                else:
+                    if threshold_p_value >= 0 and threshold_p_value <= 1:
+                        if p_value < threshold_p_value:
+                            value_list.append((snp, BP, p_value))
+                            count += 1
+
+                    if value_list:
+                        plink_results[chr_name] = value_list
+
+                    value_list=[]
+
+                line = result_fp.readline()
+            else:
+                line = result_fp.readline()
+
+        #if p_value_list:
+        #    min_p_value = min(p_value_list)
+        #else:
+        #    min_p_value = 0
+            
+        return count, p_value_dict
+    
+    ######################################################
+    # input: line: str,one line read from file
+    # function: convert line from str to list; 
+    # output: lineList list
+    #######################################################
+    def build_line_list(self, line=None):
+        
+        line_list = string.split(string.strip(line),' ')# irregular number of whitespaces between columns
+        line_list = [item for item in line_list if item <>'']
+        line_list = map(string.strip, line_list)
+    
+        return line_list
     
     #def gen_data(self, tempdata):
     def gen_data(self, temp_uuid):
@@ -238,7 +443,7 @@ class MarkerRegression(object):
 
         self.dataset.group.markers.add_pvalues(p_values)
         
-        self.get_lod_score_cutoff()
+        #self.get_lod_score_cutoff()
         
         return self.dataset.group.markers.markers
 
@@ -309,6 +514,7 @@ class MarkerRegression(object):
         return p_values, t_stats
 
     def get_lod_score_cutoff(self):
+        print("INSIDE GET LOD CUTOFF")
         high_qtl_count = 0
         for marker in self.dataset.group.markers.markers:
             if marker['lod_score'] > 1:
diff --git a/wqflask/wqflask/static/new/css/panelutil.css b/wqflask/wqflask/static/new/css/panelutil.css
new file mode 100644
index 00000000..d02c47d5
--- /dev/null
+++ b/wqflask/wqflask/static/new/css/panelutil.css
@@ -0,0 +1,87 @@
+body {

+  font-family: sans-serif;

+}

+

+text {

+  font-family: sans-serif;

+  font-size: 11pt;

+}

+

+.title text {

+  dominant-baseline: middle;

+  fill: blue;

+  text-anchor: middle;

+}

+

+.y.axis text {

+  dominant-baseline: middle;

+  text-anchor: end;

+}

+

+.y.axis text.title {

+  text-anchor: middle;

+  fill: slateblue;

+}

+

+.x.axis text {

+  dominant-baseline: hanging;

+  text-anchor: middle;

+}

+

+.x.axis text.title {

+  fill: slateblue;

+}

+

+line.axis.grid {

+  fill: none;

+  stroke-width: 1;

+  pointer-events: none;

+}

+

+line.x.axis.grid {

+  stroke: rgb(200, 200, 200);

+  stroke-width: 3;

+}

+

+line.y.axis.grid {

+  stroke: white;

+}

+

+.extent {

+  fill: #cac;

+  opacity: 0.3;

+}

+

+circle.selected {

+  fill: hotpink;

+  opacity: 1;

+}

+

+.caption {

+  margin-left: 60px;

+  width: 600px;

+}

+

+.d3-tip {

+  background: darkslateblue;

+  color: #fff;

+  stroke: none;

+  font-weight: bold;

+  font-size: 16px;

+  font-family: sans-serif;

+  padding: 5px;

+}

+

+.d3-tip.e:after {

+  color: darkslateblue;

+}

+

+a {

+  color: #08c;

+  text-decoration: none;

+}

+

+a:hover {

+  color: #333;

+  text-decoration: underline;

+}

diff --git a/wqflask/wqflask/static/new/javascript/bar_chart.coffee b/wqflask/wqflask/static/new/javascript/bar_chart.coffee
index beaeb0a7..a48718de 100755
--- a/wqflask/wqflask/static/new/javascript/bar_chart.coffee
+++ b/wqflask/wqflask/static/new/javascript/bar_chart.coffee
@@ -13,7 +13,8 @@ class Bar_Chart
         longest_sample_name = d3.max(sample.length for sample in @sample_names)
         
         @margin = {top: 20, right: 20, bottom: longest_sample_name * 7, left: 40}
-        @plot_width = @sample_vals.length * 16 - @margin.left - @margin.right
+        @plot_width = @sample_vals.length * 20 - @margin.left - @margin.right
+        @range = @sample_vals.length * 20
         @plot_height = 500 - @margin.top - @margin.bottom
 
         @x_buffer = @plot_width/20
@@ -172,7 +173,7 @@ class Bar_Chart
         console.log("sample_names2:", sample_names)
         x_scale = d3.scale.ordinal()
             .domain(sample_names)
-            .rangeBands([0, @plot_width], .1)
+            .rangeRoundBands([0, @range], 0.1, 0)
         $('.bar_chart').find('.x.axis').remove()
         @add_x_axis(x_scale)
 
@@ -283,7 +284,7 @@ class Bar_Chart
     create_scales: () ->
         @x_scale = d3.scale.ordinal()
             .domain(@sample_names)
-            .rangeBands([0, @plot_width], 0.3)
+            .rangeRoundBands([0, @range], 0.1, 0)
 
         @y_scale = d3.scale.linear()
             .domain([@y_min * 0.75, @y_max])
diff --git a/wqflask/wqflask/static/new/javascript/bar_chart.js b/wqflask/wqflask/static/new/javascript/bar_chart.js
index c5802a6d..6f9b27e0 100755
--- a/wqflask/wqflask/static/new/javascript/bar_chart.js
+++ b/wqflask/wqflask/static/new/javascript/bar_chart.js
@@ -35,7 +35,8 @@
         bottom: longest_sample_name * 7,
         left: 40
       };
-      this.plot_width = this.sample_vals.length * 16 - this.margin.left - this.margin.right;
+      this.plot_width = this.sample_vals.length * 20 - this.margin.left - this.margin.right;
+      this.range = this.sample_vals.length * 20;
       this.plot_height = 500 - this.margin.top - this.margin.bottom;
       this.x_buffer = this.plot_width / 20;
       this.y_buffer = this.plot_height / 20;
@@ -124,7 +125,7 @@
         return _results;
       })();
       console.log("sample_names2:", sample_names);
-      x_scale = d3.scale.ordinal().domain(sample_names).rangeBands([0, this.plot_width], .1);
+      x_scale = d3.scale.ordinal().domain(sample_names).rangeRoundBands([0, this.range], 0.1, 0);
       $('.bar_chart').find('.x.axis').remove();
       return this.add_x_axis(x_scale);
     };
@@ -306,7 +307,7 @@
     };
 
     Bar_Chart.prototype.create_scales = function() {
-      this.x_scale = d3.scale.ordinal().domain(this.sample_names).rangeBands([0, this.plot_width], 0.3);
+      this.x_scale = d3.scale.ordinal().domain(this.sample_names).rangeRoundBands([0, this.range], 0.1, 0);
       return this.y_scale = d3.scale.linear().domain([this.y_min * 0.75, this.y_max]).range([this.plot_height, this.y_buffer]);
     };
 
diff --git a/wqflask/wqflask/static/new/javascript/chr_manhattan_plot.coffee b/wqflask/wqflask/static/new/javascript/chr_manhattan_plot.coffee
index 74eb2e88..8b27caa1 100755
--- a/wqflask/wqflask/static/new/javascript/chr_manhattan_plot.coffee
+++ b/wqflask/wqflask/static/new/javascript/chr_manhattan_plot.coffee
@@ -73,12 +73,12 @@ class Chr_Manhattan_Plot
                 high_qtl_count += 1

         console.log("high_qtl_count:", high_qtl_count)

         

-        if high_qtl_count > 10000

-            @y_axis_filter = 2

-        else if high_qtl_count > 1000

-            @y_axis_filter = 1

-        else

-            @y_axis_filter = 0

+        #if high_qtl_count > 10000

+        @y_axis_filter = 2

+        #else if high_qtl_count > 1000

+        #    @y_axis_filter = 1

+        #else

+        #    @y_axis_filter = 0

 

     create_coordinates: () ->

         for result in @these_results

@@ -108,7 +108,6 @@ class Chr_Manhattan_Plot
             return @y_max/2

         else

             return 2

-        

 

     create_graph: () ->

         @add_border()

@@ -216,16 +215,16 @@ class Chr_Manhattan_Plot
                 return @y_scale(d[1])

             )

             .attr("r", (d) =>

-                if d[1] > 2

-                    return 3

-                else

-                    return 2

+                #if d[1] > 2

+                #    return 3

+                #else

+                return 2

             )

             .attr("fill", (d) =>

-                if d[1] > 2

-                    return "white"

-                else

-                    return "black"

+                #if d[1] > 2

+                #    return "white"

+                #else

+                return "black"

             )

             .attr("stroke", "black")

             .attr("stroke-width", "1")

@@ -247,16 +246,16 @@ class Chr_Manhattan_Plot
                 this_id = "point_" + String(d[2])

                 d3.select("#" + this_id).classed("d3_highlight", false)

                     .attr("r", (d) =>

-                        if d[1] > 2

-                            return 3

-                        else

-                            return 2

+                        #if d[1] > 2

+                        #    return 3

+                        #else

+                        return 2

                     )

                     .attr("fill", (d) =>

-                        if d[1] > 2

-                            return "white"

-                        else

-                            return "black"

+                        #if d[1] > 2

+                        #    return "white"

+                        #else

+                        return "black"

                     )

                     .attr("stroke", "black")

                     .attr("stroke-width", "1")

diff --git a/wqflask/wqflask/static/new/javascript/chr_manhattan_plot.js b/wqflask/wqflask/static/new/javascript/chr_manhattan_plot.js
index a38cfe5d..b7f64094 100755
--- a/wqflask/wqflask/static/new/javascript/chr_manhattan_plot.js
+++ b/wqflask/wqflask/static/new/javascript/chr_manhattan_plot.js
@@ -93,13 +93,7 @@
         }
       }
       console.log("high_qtl_count:", high_qtl_count);
-      if (high_qtl_count > 10000) {
-        return this.y_axis_filter = 2;
-      } else if (high_qtl_count > 1000) {
-        return this.y_axis_filter = 1;
-      } else {
-        return this.y_axis_filter = 0;
-      }
+      return this.y_axis_filter = 2;
     };
 
     Chr_Manhattan_Plot.prototype.create_coordinates = function() {
@@ -193,17 +187,9 @@
       }).attr("cy", function(d) {
         return _this.y_scale(d[1]);
       }).attr("r", function(d) {
-        if (d[1] > 2) {
-          return 3;
-        } else {
-          return 2;
-        }
+        return 2;
       }).attr("fill", function(d) {
-        if (d[1] > 2) {
-          return "white";
-        } else {
-          return "black";
-        }
+        return "black";
       }).attr("stroke", "black").attr("stroke-width", "1").attr("id", function(d) {
         return "point_" + String(d[2]);
       }).classed("circle", true).on("mouseover", function(d) {
@@ -216,17 +202,9 @@
         var this_id;
         this_id = "point_" + String(d[2]);
         return d3.select("#" + this_id).classed("d3_highlight", false).attr("r", function(d) {
-          if (d[1] > 2) {
-            return 3;
-          } else {
-            return 2;
-          }
+          return 2;
         }).attr("fill", function(d) {
-          if (d[1] > 2) {
-            return "white";
-          } else {
-            return "black";
-          }
+          return "black";
         }).attr("stroke", "black").attr("stroke-width", "1");
       }).append("svg:title").text(function(d) {
         return d[2];
diff --git a/wqflask/wqflask/static/new/javascript/interval_map_new.coffee b/wqflask/wqflask/static/new/javascript/interval_map_new.coffee
new file mode 100644
index 00000000..898df6d1
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/interval_map_new.coffee
@@ -0,0 +1,71 @@
+h = 500

+w = 1200

+margin = {left:60, top:40, right:40, bottom: 40, inner:5}

+halfh = (h+margin.top+margin.bottom)

+totalh = halfh*2

+totalw = (w+margin.left+margin.right)

+

+# simplest use

+#d3.json "data.json", (data) ->

+mychart = lodchart().lodvarname("lod.hk")

+                    .height(h)

+                    .width(w)

+                    .margin(margin)

+

+data = js_data.json_data

+

+d3.select("div#topchart")

+  .datum(data)

+  .call(mychart)

+

+# grab chromosome rectangles; color pink on hover

+chrrect = mychart.chrSelect()

+chrrect.on "mouseover", ->

+            d3.select(this).attr("fill", "#E9CFEC")

+       .on "mouseout", (d,i) ->

+            d3.select(this).attr("fill", ->

+                  return "#F1F1F9"  if i % 2

+                  "#FBFBFF")

+

+# animate points at markers on click

+mychart.markerSelect()

+          .on "click", (d) ->

+                r = d3.select(this).attr("r")

+                d3.select(this)

+                  .transition().duration(500).attr("r", r*3)

+                  .transition().duration(500).attr("r", r)

+

+# two LOD charts within one SVG

+#d3.json "data.json", (data) ->

+#  mychart_em = lodchart().lodvarname("lod.em")

+#                         .height(h)

+#                         .width(w)

+#                         .margin(margin)

+#                         .ylab("LOD score (by EM)")

+#                         .pointsize(1)

+#                         .nyticks(9)

+#                         .title("Standard interval mapping")

+#  mychart_hk = lodchart().lodvarname("lod.hk")

+#                         .height(h)

+#                         .width(w)

+#                         .margin(margin)

+#                         .ylab("LOD score (by H-K)")

+#                         .linecolor("Crimson")

+#                         .yticks([0, 1, 2, 4, 6, 8])

+#                         .title("Haley-Knott regression")

+#

+#  svg = d3.select("div#bottomchart")

+#          .append("svg")

+#          .attr("height", totalh)

+#          .attr("width", totalw)

+#

+#  chart1 = svg.append("g").attr("id", "chart1")

+#

+#  chart2 = svg.append("g").attr("id", "chart2")

+#              .attr("transform", "translate(0, #{halfh})")

+#

+#  chart1.datum(data)

+#    .call(mychart_em)

+#

+#  chart2.datum(data)

+#    .call(mychart_hk)
\ No newline at end of file
diff --git a/wqflask/wqflask/static/new/javascript/interval_map_new.js b/wqflask/wqflask/static/new/javascript/interval_map_new.js
new file mode 100644
index 00000000..8861419c
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/interval_map_new.js
@@ -0,0 +1,48 @@
+// Generated by CoffeeScript 1.6.1
+(function() {
+  var chrrect, data, h, halfh, margin, mychart, totalh, totalw, w;
+
+  h = 500;
+
+  w = 1200;
+
+  margin = {
+    left: 60,
+    top: 40,
+    right: 40,
+    bottom: 40,
+    inner: 5
+  };
+
+  halfh = h + margin.top + margin.bottom;
+
+  totalh = halfh * 2;
+
+  totalw = w + margin.left + margin.right;
+
+  mychart = lodchart().lodvarname("lod.hk").height(h).width(w).margin(margin);
+
+  data = js_data.json_data;
+
+  d3.select("div#topchart").datum(data).call(mychart);
+
+  chrrect = mychart.chrSelect();
+
+  chrrect.on("mouseover", function() {
+    return d3.select(this).attr("fill", "#E9CFEC");
+  }).on("mouseout", function(d, i) {
+    return d3.select(this).attr("fill", function() {
+      if (i % 2) {
+        return "#F1F1F9";
+      }
+      return "#FBFBFF";
+    });
+  });
+
+  mychart.markerSelect().on("click", function(d) {
+    var r;
+    r = d3.select(this).attr("r");
+    return d3.select(this).transition().duration(500).attr("r", r * 3).transition().duration(500).attr("r", r);
+  });
+
+}).call(this);
diff --git a/wqflask/wqflask/static/new/javascript/lod_chart.coffee b/wqflask/wqflask/static/new/javascript/lod_chart.coffee
new file mode 100644
index 00000000..fb11eeae
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/lod_chart.coffee
@@ -0,0 +1,550 @@
+root = exports ? this

+

+lodchart = () ->

+    width = 800

+    height = 500

+    margin = {left:60, top:40, right:40, bottom: 40, inner:5}

+    axispos = {xtitle:25, ytitle:30, xlabel:5, ylabel:5}

+    titlepos = 20

+    ylim = null

+    additive_ylim = null

+    nyticks = 5

+    yticks = null

+    additive_yticks = null

+    chrGap = 8

+    darkrect = "#F1F1F9"

+    lightrect = "#FBFBFF" 

+    lodlinecolor = "darkslateblue"

+    additivelinecolor = "red"

+    linewidth = 2

+    suggestivecolor = "gainsboro"

+    significantcolor = "#EBC7C7"

+    pointcolor = "#E9CFEC" # pink

+    pointsize = 0 # default = no visible points at markers

+    pointstroke = "black"

+    title = ""

+    xlab = "Chromosome"

+    ylab = "LRS score"

+    additive_ylab = "Additive Effect"

+    rotate_ylab = null

+    yscale = d3.scale.linear()

+    additive_yscale = d3.scale.linear()

+    xscale = null

+    pad4heatmap = false

+    lodcurve = null

+    lodvarname = null

+    markerSelect = null

+    chrSelect = null

+    pointsAtMarkers = true

+  

+    ## the main function

+    chart = (selection) ->

+      selection.each (data) ->

+        lodvarname = lodvarname ? data.lodnames[0]

+        data[lodvarname] = (Math.abs(x) for x in data[lodvarname]) # take absolute values

+        data['additive'] = (Math.abs(x) for x in data['additive'])

+        ylim = ylim ? [0, d3.max(data[lodvarname])]

+        additive_ylim = additive_ylim ? [0, d3.max(data['additive'])]

+        lodvarnum = data.lodnames.indexOf(lodvarname)

+  

+        # Select the svg element, if it exists.

+        svg = d3.select(this).selectAll("svg").data([data])

+  

+        # Otherwise, create the skeletal chart.

+        gEnter = svg.enter().append("svg").append("g")

+  

+        # Update the outer dimensions.

+        svg.attr("width", width+margin.left+margin.right)

+           .attr("height", height+margin.top+margin.bottom)

+  

+        # Update the inner dimensions.

+        g = svg.select("g")

+  

+        # box

+        g.append("rect")

+         .attr("x", margin.left)

+         .attr("y", margin.top)

+         .attr("height", height)

+         .attr("width", width)

+         .attr("fill", darkrect)

+         .attr("stroke", "none")

+  

+        yscale.domain(ylim)

+              .range([height+margin.top, margin.top+margin.inner])

+              

+        additive_yscale.domain(additive_ylim)

+              .range([height+margin.top, margin.top+margin.inner + height/2])

+  

+        # if yticks not provided, use nyticks to choose pretty ones

+        yticks = yticks ? yscale.ticks(nyticks)

+        additive_yticks = additive_yticks ? additive_yscale.ticks(nyticks)

+  

+        # reorganize lod,pos by chromosomes

+        data = reorgLodData(data, lodvarname)

+  

+        # add chromosome scales (for x-axis)

+        data = chrscales(data, width, chrGap, margin.left, pad4heatmap)

+        xscale = data.xscale

+  

+        # chr rectangles

+        chrSelect =

+                  g.append("g").attr("class", "chrRect")

+                   .selectAll("empty")

+                   .data(data.chrnames)

+                   .enter()

+                   .append("rect")

+                   .attr("id", (d) -> "chrrect#{d}")

+                   .attr("x", (d,i) ->

+                     return data.chrStart[i] if i==0 and pad4heatmap

+                     data.chrStart[i]-chrGap/2)

+                   .attr("width", (d,i) ->

+                      return data.chrEnd[i] - data.chrStart[i]+chrGap/2 if (i==0 or i+1 == data.chrnames.length) and pad4heatmap

+                      data.chrEnd[i] - data.chrStart[i]+chrGap)

+                   .attr("y", margin.top)

+                   .attr("height", height)

+                   .attr("fill", (d,i) ->

+                      return darkrect if i % 2

+                      lightrect)

+                   .attr("stroke", "none")

+  

+        # x-axis labels

+        xaxis = g.append("g").attr("class", "x axis")

+        xaxis.selectAll("empty")

+             .data(data.chrnames)

+             .enter()

+             .append("text")

+             .text((d) -> d)

+             .attr("x", (d,i) -> (data.chrStart[i]+data.chrEnd[i])/2)

+             .attr("y", margin.top+height+axispos.xlabel)

+        xaxis.append("text").attr("class", "title")

+             .attr("y", margin.top+height+axispos.xtitle)

+             .attr("x", margin.left+width/2)

+             .text(xlab)

+  

+        # y-axis

+        rotate_ylab = rotate_ylab ? (ylab.length > 1)

+        yaxis = g.append("g").attr("class", "y axis")

+        yaxis.selectAll("empty")

+             .data(yticks)

+             .enter()

+             .append("line")

+             .attr("y1", (d) -> yscale(d))

+             .attr("y2", (d) -> yscale(d))

+             .attr("x1", margin.left)

+             .attr("x2", margin.left+7)

+             .attr("fill", "none")

+             .attr("stroke", "white")

+             .attr("stroke-width", 1)

+             .style("pointer-events", "none")

+             

+        yaxis.selectAll("empty")

+             .data(yticks)

+             .enter()

+             .append("text")

+             .attr("y", (d) -> yscale(d))

+             .attr("x", margin.left-axispos.ylabel)

+             .attr("fill", "blue")

+             .text((d) -> formatAxis(yticks)(d))

+             

+        yaxis.append("text").attr("class", "title")

+             .attr("y", margin.top+height/2)

+             .attr("x", margin.left-axispos.ytitle)

+             .text(ylab)

+             .attr("transform", if rotate_ylab then "rotate(270,#{margin.left-axispos.ytitle},#{margin.top+height/2})" else "")

+  

+        rotate_additive_ylab = rotate_additive_ylab ? (additive_ylab.length > 1)

+        additive_yaxis = g.append("g").attr("class", "y axis")

+        additive_yaxis.selectAll("empty")

+             .data(additive_yticks)

+             .enter()

+             .append("line")

+             .attr("y1", (d) -> additive_yscale(d))

+             .attr("y2", (d) -> additive_yscale(d))

+             .attr("x1", margin.left + width)

+             .attr("x2", margin.left + width - 7)

+             .attr("fill", "none")

+             .attr("stroke", "white")

+             .attr("stroke-width", 1)

+             .style("pointer-events", "none")

+    

+        additive_yaxis.selectAll("empty")

+             .data(additive_yticks)

+             .enter()

+             .append("text")

+             .attr("y", (d) -> additive_yscale(d))

+             .attr("x", (d) -> margin.left + width + axispos.ylabel + 20)

+             .attr("fill", "green")

+             .text((d) -> formatAxis(additive_yticks)(d))

+             

+        additive_yaxis.append("text").attr("class", "title")

+             .attr("y", margin.top+1.5*height)

+             .attr("x", margin.left + width + axispos.ytitle)

+             .text(additive_ylab)

+             .attr("transform", if rotate_additive_ylab then "rotate(270,#{margin.left + width + axispos.ytitle}, #{margin.top+height*1.5})" else "")

+  

+  

+        suggestive_bar = g.append("g").attr("class", "suggestive")

+        suggestive_bar.selectAll("empty")

+             .data([data.suggestive])

+             .enter()

+             .append("line")

+             .attr("y1", (d) -> yscale(d))

+             .attr("y2", (d) -> yscale(d))

+             .attr("x1", margin.left)

+             .attr("x2", margin.left+width)

+             .attr("fill", "none")

+             .attr("stroke", suggestivecolor)

+             .attr("stroke-width", 5)

+             .style("pointer-events", "none")

+

+        suggestive_bar = g.append("g").attr("class", "significant")

+        suggestive_bar.selectAll("empty")

+             .data([data.significant])

+             .enter()

+             .append("line")

+             .attr("y1", (d) -> yscale(d))

+             .attr("y2", (d) -> yscale(d))

+             .attr("x1", margin.left)

+             .attr("x2", margin.left+width)

+             .attr("fill", "none")

+             .attr("stroke", significantcolor)

+             .attr("stroke-width", 5)

+             .style("pointer-events", "none")

+  

+        # lod curves by chr

+        lodcurve = (chr, lodcolumn) ->

+            d3.svg.line()

+              .x((d) -> xscale[chr](d))

+              .y((d,i) -> yscale(data.lodByChr[chr][i][lodcolumn]))

+              

+        additivecurve = (chr, lodcolumn) ->

+            d3.svg.line()

+              .x((d) -> xscale[chr](d))

+              .y((d,i) -> additive_yscale(data.additiveByChr[chr][i][lodcolumn]))

+  

+        curves = g.append("g").attr("id", "curves")

+  

+        for chr in data.chrnames

+          curves.append("path")

+                .datum(data.posByChr[chr])

+                .attr("d", lodcurve(chr, lodvarnum))

+                .attr("stroke", lodlinecolor)

+                .attr("fill", "none")

+                .attr("stroke-width", linewidth)

+                .style("pointer-events", "none")

+                

+        for chr in data.chrnames

+          curves.append("path")

+                .datum(data.posByChr[chr])

+                .attr("d", additivecurve(chr, lodvarnum))

+                .attr("stroke", additivelinecolor)

+                .attr("fill", "none")

+                .attr("stroke-width", 1)

+                .style("pointer-events", "none")

+  

+        # points at markers

+        if pointsize > 0

+          markerpoints = g.append("g").attr("id", "markerpoints_visible")

+          markerpoints.selectAll("empty")

+                      .data(data.markers)

+                      .enter()

+                      .append("circle")

+                      .attr("cx", (d) -> xscale[d.chr](d.pos))

+                      .attr("cy", (d) -> yscale(d.lod))

+                      .attr("r", pointsize)

+                      .attr("fill", pointcolor)

+                      .attr("stroke", pointstroke)

+                      .attr("pointer-events", "hidden")

+  

+        if pointsAtMarkers

+          # these hidden points are what gets selected...a bit larger

+          hiddenpoints = g.append("g").attr("id", "markerpoints_hidden")

+  

+          markertip = d3.tip()

+                        .attr('class', 'd3-tip')

+                        .html((d) ->

+                          [d.name, " LRS = #{d3.format('.2f')(d.lod)}"])

+                        .direction("e")

+                        .offset([0,10])

+          svg.call(markertip)

+  

+          markerSelect =

+            hiddenpoints.selectAll("empty")

+                        .data(data.markers)

+                        .enter()

+                        .append("circle")

+                        .attr("cx", (d) -> xscale[d.chr](d.pos))

+                        .attr("cy", (d) -> yscale(d.lod))

+                        .attr("id", (d) -> d.name)

+                        .attr("r", d3.max([pointsize*2, 3]))

+                        .attr("opacity", 0)

+                        .attr("fill", pointcolor)

+                        .attr("stroke", pointstroke)

+                        .attr("stroke-width", "1")

+                        .on "mouseover.paneltip", (d) ->

+                           d3.select(this).attr("opacity", 1)

+                           markertip.show(d)

+                        .on "mouseout.paneltip", ->

+                           d3.select(this).attr("opacity", 0)

+                                          .call(markertip.hide)

+  

+        # title

+        titlegrp = g.append("g").attr("class", "title")

+         .append("text")

+         .attr("x", margin.left+width/2)

+         .attr("y", margin.top-titlepos)

+         .text(title)

+  

+        # another box around edge

+        g.append("rect")

+         .attr("x", margin.left)

+         .attr("y", margin.top)

+         .attr("height", height)

+         .attr("width", () ->

+            return(data.chrEnd[-1..][0]-margin.left) if pad4heatmap

+            data.chrEnd[-1..][0]-margin.left+chrGap/2)

+         .attr("fill", "none")

+         .attr("stroke", "black")

+         .attr("stroke-width", "none")

+  

+    ## configuration parameters

+    chart.width = (value) ->

+      return width unless arguments.length

+      width = value

+      chart

+  

+    chart.height = (value) ->

+      return height unless arguments.length

+      height = value

+      chart

+  

+    chart.margin = (value) ->

+      return margin unless arguments.length

+      margin = value

+      chart

+  

+    chart.titlepos = (value) ->

+      return titlepos unless arguments.length

+      titlepos

+      chart

+  

+    chart.axispos = (value) ->

+      return axispos unless arguments.length

+      axispos = value

+      chart

+  

+    chart.ylim = (value) ->

+      return ylim unless arguments.length

+      ylim = value

+      chart

+      

+    chart.additive_ylim = (value) ->

+      return additive_ylim unless arguments.length

+      additive_ylim = value

+      chart

+  

+    chart.nyticks = (value) ->

+      return nyticks unless arguments.length

+      nyticks = value

+      chart

+  

+    chart.yticks = (value) ->

+      return yticks unless arguments.length

+      yticks = value

+      chart

+  

+    chart.chrGap = (value) ->

+      return chrGap unless arguments.length

+      chrGap = value

+      chart

+  

+    chart.darkrect = (value) ->

+      return darkrect unless arguments.length

+      darkrect = value

+      chart

+  

+    chart.lightrect = (value) ->

+      return lightrect unless arguments.length

+      lightrect = value

+      chart

+  

+    chart.linecolor = (value) ->

+      return linecolor unless arguments.length

+      linecolor = value

+      chart

+  

+    chart.linewidth = (value) ->

+      return linewidth unless arguments.length

+      linewidth = value

+      chart

+  

+    chart.pointcolor = (value) ->

+      return pointcolor unless arguments.length

+      pointcolor = value

+      chart

+  

+    chart.pointsize = (value) ->

+      return pointsize unless arguments.length

+      pointsize = value

+      chart

+  

+    chart.pointstroke = (value) ->

+      return pointstroke unless arguments.length

+      pointstroke = value

+      chart

+  

+    chart.title = (value) ->

+      return title unless arguments.length

+      title = value

+      chart

+  

+    chart.xlab = (value) ->

+      return xlab unless arguments.length

+      xlab = value

+      chart

+  

+    chart.ylab = (value) ->

+      return ylab unless arguments.length

+      ylab = value

+      chart

+  

+    chart.rotate_ylab = (value) ->

+      return rotate_ylab if !arguments.length

+      rotate_ylab = value

+      chart

+  

+    chart.lodvarname = (value) ->

+      return lodvarname unless arguments.length

+      lodvarname = value

+      chart

+  

+    chart.pad4heatmap = (value) ->

+      return pad4heatmap unless arguments.length

+      pad4heatmap = value

+      chart

+  

+    chart.pointsAtMarkers = (value) ->

+      return pointsAtMarkers unless arguments.length

+      pointsAtMarkers = value

+      chart

+  

+    chart.yscale = () ->

+      return yscale

+    

+    chart.additive_yscale = () ->

+      return additive_yscale

+  

+    chart.xscale = () ->

+      return xscale

+  

+    chart.lodcurve = () ->

+      return lodcurve

+    

+    chart.additivecurve = () ->

+      return additivecurve

+  

+    chart.markerSelect = () ->

+      return markerSelect

+  

+    chart.chrSelect = () ->

+      return chrSelect

+  

+    # return the chart function

+    chart

+

+root.lodchart = lodchart

+

+# reorganize lod/pos by chromosome

+# lodvarname==null    -> case for multiple LOD columns (lodheatmap)

+# lodvarname provided -> case for one LOD column (lodchart)

+reorgLodData = (data, lodvarname=null) ->

+    data.posByChr = {}

+    data.lodByChr = {}

+    data.additiveByChr = {}

+    

+    for chr,i in data.chrnames

+      data.posByChr[chr] = []

+      data.lodByChr[chr] = []

+      data.additiveByChr[chr] = []

+      for pos, j in data.pos

+        if data.chr[j] == chr

+          data.posByChr[chr].push(pos)

+          data.lodnames = [data.lodnames] unless Array.isArray(data.lodnames)

+          additiveval = (data['additive'][j] for lodcolumn in data.lodnames)

+          lodval = (data[lodcolumn][j] for lodcolumn in data.lodnames)

+          data.additiveByChr[chr].push(additiveval)

+          data.lodByChr[chr].push(lodval)

+

+    

+    if lodvarname?

+      data.markers = []

+      for marker,i in data.markernames

+        if marker != ""

+          data.markers.push({name:marker, chr:data.chr[i], pos:data.pos[i], lod:data[lodvarname][i]})

+    

+    data

+

+

+# calculate chromosome start/end + scales, for heat map

+chrscales = (data, width, chrGap, leftMargin, pad4heatmap) ->

+    # start and end of chromosome positions

+    chrStart = []

+    chrEnd = []

+    chrLength = []

+    totalChrLength = 0

+    maxd = 0

+    for chr in data.chrnames

+      d = maxdiff(data.posByChr[chr])

+      maxd = d if d > maxd

+  

+      rng = d3.extent(data.posByChr[chr])

+      chrStart.push(rng[0])

+      chrEnd.push(rng[1])

+      L = rng[1] - rng[0]

+      chrLength.push(L)

+      totalChrLength += L

+  

+    # adjust lengths for heatmap

+    if pad4heatmap

+      data.recwidth = maxd

+      chrStart = chrStart.map (x) -> x-maxd/2

+      chrEnd = chrEnd.map (x) -> x+maxd/2

+      chrLength = chrLength.map (x) -> x+maxd

+      totalChrLength += (chrLength.length*maxd)

+  

+    # break up x axis into chromosomes by length, with gaps

+    data.chrStart = []

+    data.chrEnd = []

+    cur = leftMargin

+    cur += chrGap/2 unless pad4heatmap

+    data.xscale = {}

+    for chr,i in data.chrnames

+      data.chrStart.push(cur)

+      w = Math.round((width-chrGap*(data.chrnames.length-pad4heatmap))/totalChrLength*chrLength[i])

+      data.chrEnd.push(cur + w)

+      cur = data.chrEnd[i] + chrGap

+      # x-axis scales, by chromosome

+      data.xscale[chr] = d3.scale.linear()

+                           .domain([chrStart[i], chrEnd[i]])

+                           .range([data.chrStart[i], data.chrEnd[i]])

+  

+    # return data with new stuff added

+    data

+    

+# maximum difference between adjacent values in a vector

+maxdiff = (x) ->

+    return null if x.length < 2

+    result = x[1] - x[0]

+    return result if x.length < 3

+    for i in [2...x.length]

+      d = x[i] - x[i-1]

+      result = d if d > result

+    result

+    

+# determine rounding of axis labels

+formatAxis = (d) ->

+    d = d[1] - d[0]

+    ndig = Math.floor( Math.log(d % 10) / Math.log(10) )

+    ndig = 0 if ndig > 0

+    ndig = Math.abs(ndig)

+    d3.format(".#{ndig}f")

diff --git a/wqflask/wqflask/static/new/javascript/lod_chart.js b/wqflask/wqflask/static/new/javascript/lod_chart.js
new file mode 100644
index 00000000..14aff1a7
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/lod_chart.js
@@ -0,0 +1,562 @@
+// Generated by CoffeeScript 1.6.1
+(function() {
+  var chrscales, formatAxis, lodchart, maxdiff, reorgLodData, root;
+
+  root = typeof exports !== "undefined" && exports !== null ? exports : this;
+
+  lodchart = function() {
+    var additive_ylab, additive_ylim, additive_yscale, additive_yticks, additivelinecolor, axispos, chart, chrGap, chrSelect, darkrect, height, lightrect, linewidth, lodcurve, lodlinecolor, lodvarname, margin, markerSelect, nyticks, pad4heatmap, pointcolor, pointsAtMarkers, pointsize, pointstroke, rotate_ylab, significantcolor, suggestivecolor, title, titlepos, width, xlab, xscale, ylab, ylim, yscale, yticks;
+    width = 800;
+    height = 500;
+    margin = {
+      left: 60,
+      top: 40,
+      right: 40,
+      bottom: 40,
+      inner: 5
+    };
+    axispos = {
+      xtitle: 25,
+      ytitle: 30,
+      xlabel: 5,
+      ylabel: 5
+    };
+    titlepos = 20;
+    ylim = null;
+    additive_ylim = null;
+    nyticks = 5;
+    yticks = null;
+    additive_yticks = null;
+    chrGap = 8;
+    darkrect = "#F1F1F9";
+    lightrect = "#FBFBFF";
+    lodlinecolor = "darkslateblue";
+    additivelinecolor = "red";
+    linewidth = 2;
+    suggestivecolor = "gainsboro";
+    significantcolor = "#EBC7C7";
+    pointcolor = "#E9CFEC";
+    pointsize = 0;
+    pointstroke = "black";
+    title = "";
+    xlab = "Chromosome";
+    ylab = "LRS score";
+    additive_ylab = "Additive Effect";
+    rotate_ylab = null;
+    yscale = d3.scale.linear();
+    additive_yscale = d3.scale.linear();
+    xscale = null;
+    pad4heatmap = false;
+    lodcurve = null;
+    lodvarname = null;
+    markerSelect = null;
+    chrSelect = null;
+    pointsAtMarkers = true;
+    chart = function(selection) {
+      return selection.each(function(data) {
+        var additive_yaxis, additivecurve, chr, curves, g, gEnter, hiddenpoints, lodvarnum, markerpoints, markertip, rotate_additive_ylab, suggestive_bar, svg, titlegrp, x, xaxis, yaxis, _i, _j, _len, _len1, _ref, _ref1;
+        lodvarname = lodvarname != null ? lodvarname : data.lodnames[0];
+        data[lodvarname] = (function() {
+          var _i, _len, _ref, _results;
+          _ref = data[lodvarname];
+          _results = [];
+          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+            x = _ref[_i];
+            _results.push(Math.abs(x));
+          }
+          return _results;
+        })();
+        data['additive'] = (function() {
+          var _i, _len, _ref, _results;
+          _ref = data['additive'];
+          _results = [];
+          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+            x = _ref[_i];
+            _results.push(Math.abs(x));
+          }
+          return _results;
+        })();
+        ylim = ylim != null ? ylim : [0, d3.max(data[lodvarname])];
+        additive_ylim = additive_ylim != null ? additive_ylim : [0, d3.max(data['additive'])];
+        lodvarnum = data.lodnames.indexOf(lodvarname);
+        svg = d3.select(this).selectAll("svg").data([data]);
+        gEnter = svg.enter().append("svg").append("g");
+        svg.attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom);
+        g = svg.select("g");
+        g.append("rect").attr("x", margin.left).attr("y", margin.top).attr("height", height).attr("width", width).attr("fill", darkrect).attr("stroke", "none");
+        yscale.domain(ylim).range([height + margin.top, margin.top + margin.inner]);
+        additive_yscale.domain(additive_ylim).range([height + margin.top, margin.top + margin.inner + height / 2]);
+        yticks = yticks != null ? yticks : yscale.ticks(nyticks);
+        additive_yticks = additive_yticks != null ? additive_yticks : additive_yscale.ticks(nyticks);
+        data = reorgLodData(data, lodvarname);
+        data = chrscales(data, width, chrGap, margin.left, pad4heatmap);
+        xscale = data.xscale;
+        chrSelect = g.append("g").attr("class", "chrRect").selectAll("empty").data(data.chrnames).enter().append("rect").attr("id", function(d) {
+          return "chrrect" + d;
+        }).attr("x", function(d, i) {
+          if (i === 0 && pad4heatmap) {
+            return data.chrStart[i];
+          }
+          return data.chrStart[i] - chrGap / 2;
+        }).attr("width", function(d, i) {
+          if ((i === 0 || i + 1 === data.chrnames.length) && pad4heatmap) {
+            return data.chrEnd[i] - data.chrStart[i] + chrGap / 2;
+          }
+          return data.chrEnd[i] - data.chrStart[i] + chrGap;
+        }).attr("y", margin.top).attr("height", height).attr("fill", function(d, i) {
+          if (i % 2) {
+            return darkrect;
+          }
+          return lightrect;
+        }).attr("stroke", "none");
+        xaxis = g.append("g").attr("class", "x axis");
+        xaxis.selectAll("empty").data(data.chrnames).enter().append("text").text(function(d) {
+          return d;
+        }).attr("x", function(d, i) {
+          return (data.chrStart[i] + data.chrEnd[i]) / 2;
+        }).attr("y", margin.top + height + axispos.xlabel);
+        xaxis.append("text").attr("class", "title").attr("y", margin.top + height + axispos.xtitle).attr("x", margin.left + width / 2).text(xlab);
+        rotate_ylab = rotate_ylab != null ? rotate_ylab : ylab.length > 1;
+        yaxis = g.append("g").attr("class", "y axis");
+        yaxis.selectAll("empty").data(yticks).enter().append("line").attr("y1", function(d) {
+          return yscale(d);
+        }).attr("y2", function(d) {
+          return yscale(d);
+        }).attr("x1", margin.left).attr("x2", margin.left + 7).attr("fill", "none").attr("stroke", "white").attr("stroke-width", 1).style("pointer-events", "none");
+        yaxis.selectAll("empty").data(yticks).enter().append("text").attr("y", function(d) {
+          return yscale(d);
+        }).attr("x", margin.left - axispos.ylabel).attr("fill", "blue").text(function(d) {
+          return formatAxis(yticks)(d);
+        });
+        yaxis.append("text").attr("class", "title").attr("y", margin.top + height / 2).attr("x", margin.left - axispos.ytitle).text(ylab).attr("transform", rotate_ylab ? "rotate(270," + (margin.left - axispos.ytitle) + "," + (margin.top + height / 2) + ")" : "");
+        rotate_additive_ylab = rotate_additive_ylab != null ? rotate_additive_ylab : additive_ylab.length > 1;
+        additive_yaxis = g.append("g").attr("class", "y axis");
+        additive_yaxis.selectAll("empty").data(additive_yticks).enter().append("line").attr("y1", function(d) {
+          return additive_yscale(d);
+        }).attr("y2", function(d) {
+          return additive_yscale(d);
+        }).attr("x1", margin.left + width).attr("x2", margin.left + width - 7).attr("fill", "none").attr("stroke", "white").attr("stroke-width", 1).style("pointer-events", "none");
+        additive_yaxis.selectAll("empty").data(additive_yticks).enter().append("text").attr("y", function(d) {
+          return additive_yscale(d);
+        }).attr("x", function(d) {
+          return margin.left + width + axispos.ylabel + 20;
+        }).attr("fill", "green").text(function(d) {
+          return formatAxis(additive_yticks)(d);
+        });
+        additive_yaxis.append("text").attr("class", "title").attr("y", margin.top + 1.5 * height).attr("x", margin.left + width + axispos.ytitle).text(additive_ylab).attr("transform", rotate_additive_ylab ? "rotate(270," + (margin.left + width + axispos.ytitle) + ", " + (margin.top + height * 1.5) + ")" : "");
+        suggestive_bar = g.append("g").attr("class", "suggestive");
+        suggestive_bar.selectAll("empty").data([data.suggestive]).enter().append("line").attr("y1", function(d) {
+          return yscale(d);
+        }).attr("y2", function(d) {
+          return yscale(d);
+        }).attr("x1", margin.left).attr("x2", margin.left + width).attr("fill", "none").attr("stroke", suggestivecolor).attr("stroke-width", 5).style("pointer-events", "none");
+        suggestive_bar = g.append("g").attr("class", "significant");
+        suggestive_bar.selectAll("empty").data([data.significant]).enter().append("line").attr("y1", function(d) {
+          return yscale(d);
+        }).attr("y2", function(d) {
+          return yscale(d);
+        }).attr("x1", margin.left).attr("x2", margin.left + width).attr("fill", "none").attr("stroke", significantcolor).attr("stroke-width", 5).style("pointer-events", "none");
+        lodcurve = function(chr, lodcolumn) {
+          return d3.svg.line().x(function(d) {
+            return xscale[chr](d);
+          }).y(function(d, i) {
+            return yscale(data.lodByChr[chr][i][lodcolumn]);
+          });
+        };
+        additivecurve = function(chr, lodcolumn) {
+          return d3.svg.line().x(function(d) {
+            return xscale[chr](d);
+          }).y(function(d, i) {
+            return additive_yscale(data.additiveByChr[chr][i][lodcolumn]);
+          });
+        };
+        curves = g.append("g").attr("id", "curves");
+        _ref = data.chrnames;
+        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+          chr = _ref[_i];
+          curves.append("path").datum(data.posByChr[chr]).attr("d", lodcurve(chr, lodvarnum)).attr("stroke", lodlinecolor).attr("fill", "none").attr("stroke-width", linewidth).style("pointer-events", "none");
+        }
+        _ref1 = data.chrnames;
+        for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+          chr = _ref1[_j];
+          curves.append("path").datum(data.posByChr[chr]).attr("d", additivecurve(chr, lodvarnum)).attr("stroke", additivelinecolor).attr("fill", "none").attr("stroke-width", 1).style("pointer-events", "none");
+        }
+        if (pointsize > 0) {
+          markerpoints = g.append("g").attr("id", "markerpoints_visible");
+          markerpoints.selectAll("empty").data(data.markers).enter().append("circle").attr("cx", function(d) {
+            return xscale[d.chr](d.pos);
+          }).attr("cy", function(d) {
+            return yscale(d.lod);
+          }).attr("r", pointsize).attr("fill", pointcolor).attr("stroke", pointstroke).attr("pointer-events", "hidden");
+        }
+        if (pointsAtMarkers) {
+          hiddenpoints = g.append("g").attr("id", "markerpoints_hidden");
+          markertip = d3.tip().attr('class', 'd3-tip').html(function(d) {
+            return [d.name, " LRS = " + (d3.format('.2f')(d.lod))];
+          }).direction("e").offset([0, 10]);
+          svg.call(markertip);
+          markerSelect = hiddenpoints.selectAll("empty").data(data.markers).enter().append("circle").attr("cx", function(d) {
+            return xscale[d.chr](d.pos);
+          }).attr("cy", function(d) {
+            return yscale(d.lod);
+          }).attr("id", function(d) {
+            return d.name;
+          }).attr("r", d3.max([pointsize * 2, 3])).attr("opacity", 0).attr("fill", pointcolor).attr("stroke", pointstroke).attr("stroke-width", "1").on("mouseover.paneltip", function(d) {
+            d3.select(this).attr("opacity", 1);
+            return markertip.show(d);
+          }).on("mouseout.paneltip", function() {
+            return d3.select(this).attr("opacity", 0).call(markertip.hide);
+          });
+        }
+        titlegrp = g.append("g").attr("class", "title").append("text").attr("x", margin.left + width / 2).attr("y", margin.top - titlepos).text(title);
+        return g.append("rect").attr("x", margin.left).attr("y", margin.top).attr("height", height).attr("width", function() {
+          if (pad4heatmap) {
+            return data.chrEnd.slice(-1)[0] - margin.left;
+          }
+          return data.chrEnd.slice(-1)[0] - margin.left + chrGap / 2;
+        }).attr("fill", "none").attr("stroke", "black").attr("stroke-width", "none");
+      });
+    };
+    chart.width = function(value) {
+      if (!arguments.length) {
+        return width;
+      }
+      width = value;
+      return chart;
+    };
+    chart.height = function(value) {
+      if (!arguments.length) {
+        return height;
+      }
+      height = value;
+      return chart;
+    };
+    chart.margin = function(value) {
+      if (!arguments.length) {
+        return margin;
+      }
+      margin = value;
+      return chart;
+    };
+    chart.titlepos = function(value) {
+      if (!arguments.length) {
+        return titlepos;
+      }
+      titlepos;
+      return chart;
+    };
+    chart.axispos = function(value) {
+      if (!arguments.length) {
+        return axispos;
+      }
+      axispos = value;
+      return chart;
+    };
+    chart.ylim = function(value) {
+      if (!arguments.length) {
+        return ylim;
+      }
+      ylim = value;
+      return chart;
+    };
+    chart.additive_ylim = function(value) {
+      if (!arguments.length) {
+        return additive_ylim;
+      }
+      additive_ylim = value;
+      return chart;
+    };
+    chart.nyticks = function(value) {
+      if (!arguments.length) {
+        return nyticks;
+      }
+      nyticks = value;
+      return chart;
+    };
+    chart.yticks = function(value) {
+      if (!arguments.length) {
+        return yticks;
+      }
+      yticks = value;
+      return chart;
+    };
+    chart.chrGap = function(value) {
+      if (!arguments.length) {
+        return chrGap;
+      }
+      chrGap = value;
+      return chart;
+    };
+    chart.darkrect = function(value) {
+      if (!arguments.length) {
+        return darkrect;
+      }
+      darkrect = value;
+      return chart;
+    };
+    chart.lightrect = function(value) {
+      if (!arguments.length) {
+        return lightrect;
+      }
+      lightrect = value;
+      return chart;
+    };
+    chart.linecolor = function(value) {
+      var linecolor;
+      if (!arguments.length) {
+        return linecolor;
+      }
+      linecolor = value;
+      return chart;
+    };
+    chart.linewidth = function(value) {
+      if (!arguments.length) {
+        return linewidth;
+      }
+      linewidth = value;
+      return chart;
+    };
+    chart.pointcolor = function(value) {
+      if (!arguments.length) {
+        return pointcolor;
+      }
+      pointcolor = value;
+      return chart;
+    };
+    chart.pointsize = function(value) {
+      if (!arguments.length) {
+        return pointsize;
+      }
+      pointsize = value;
+      return chart;
+    };
+    chart.pointstroke = function(value) {
+      if (!arguments.length) {
+        return pointstroke;
+      }
+      pointstroke = value;
+      return chart;
+    };
+    chart.title = function(value) {
+      if (!arguments.length) {
+        return title;
+      }
+      title = value;
+      return chart;
+    };
+    chart.xlab = function(value) {
+      if (!arguments.length) {
+        return xlab;
+      }
+      xlab = value;
+      return chart;
+    };
+    chart.ylab = function(value) {
+      if (!arguments.length) {
+        return ylab;
+      }
+      ylab = value;
+      return chart;
+    };
+    chart.rotate_ylab = function(value) {
+      if (!arguments.length) {
+        return rotate_ylab;
+      }
+      rotate_ylab = value;
+      return chart;
+    };
+    chart.lodvarname = function(value) {
+      if (!arguments.length) {
+        return lodvarname;
+      }
+      lodvarname = value;
+      return chart;
+    };
+    chart.pad4heatmap = function(value) {
+      if (!arguments.length) {
+        return pad4heatmap;
+      }
+      pad4heatmap = value;
+      return chart;
+    };
+    chart.pointsAtMarkers = function(value) {
+      if (!arguments.length) {
+        return pointsAtMarkers;
+      }
+      pointsAtMarkers = value;
+      return chart;
+    };
+    chart.yscale = function() {
+      return yscale;
+    };
+    chart.additive_yscale = function() {
+      return additive_yscale;
+    };
+    chart.xscale = function() {
+      return xscale;
+    };
+    chart.lodcurve = function() {
+      return lodcurve;
+    };
+    chart.additivecurve = function() {
+      return additivecurve;
+    };
+    chart.markerSelect = function() {
+      return markerSelect;
+    };
+    chart.chrSelect = function() {
+      return chrSelect;
+    };
+    return chart;
+  };
+
+  root.lodchart = lodchart;
+
+  reorgLodData = function(data, lodvarname) {
+    var additiveval, chr, i, j, lodcolumn, lodval, marker, pos, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
+    if (lodvarname == null) {
+      lodvarname = null;
+    }
+    data.posByChr = {};
+    data.lodByChr = {};
+    data.additiveByChr = {};
+    _ref = data.chrnames;
+    for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
+      chr = _ref[i];
+      data.posByChr[chr] = [];
+      data.lodByChr[chr] = [];
+      data.additiveByChr[chr] = [];
+      _ref1 = data.pos;
+      for (j = _j = 0, _len1 = _ref1.length; _j < _len1; j = ++_j) {
+        pos = _ref1[j];
+        if (data.chr[j] === chr) {
+          data.posByChr[chr].push(pos);
+          if (!Array.isArray(data.lodnames)) {
+            data.lodnames = [data.lodnames];
+          }
+          additiveval = (function() {
+            var _k, _len2, _ref2, _results;
+            _ref2 = data.lodnames;
+            _results = [];
+            for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
+              lodcolumn = _ref2[_k];
+              _results.push(data['additive'][j]);
+            }
+            return _results;
+          })();
+          lodval = (function() {
+            var _k, _len2, _ref2, _results;
+            _ref2 = data.lodnames;
+            _results = [];
+            for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
+              lodcolumn = _ref2[_k];
+              _results.push(data[lodcolumn][j]);
+            }
+            return _results;
+          })();
+          data.additiveByChr[chr].push(additiveval);
+          data.lodByChr[chr].push(lodval);
+        }
+      }
+    }
+    if (lodvarname != null) {
+      data.markers = [];
+      _ref2 = data.markernames;
+      for (i = _k = 0, _len2 = _ref2.length; _k < _len2; i = ++_k) {
+        marker = _ref2[i];
+        if (marker !== "") {
+          data.markers.push({
+            name: marker,
+            chr: data.chr[i],
+            pos: data.pos[i],
+            lod: data[lodvarname][i]
+          });
+        }
+      }
+    }
+    return data;
+  };
+
+  chrscales = function(data, width, chrGap, leftMargin, pad4heatmap) {
+    var L, chr, chrEnd, chrLength, chrStart, cur, d, i, maxd, rng, totalChrLength, w, _i, _j, _len, _len1, _ref, _ref1;
+    chrStart = [];
+    chrEnd = [];
+    chrLength = [];
+    totalChrLength = 0;
+    maxd = 0;
+    _ref = data.chrnames;
+    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+      chr = _ref[_i];
+      d = maxdiff(data.posByChr[chr]);
+      if (d > maxd) {
+        maxd = d;
+      }
+      rng = d3.extent(data.posByChr[chr]);
+      chrStart.push(rng[0]);
+      chrEnd.push(rng[1]);
+      L = rng[1] - rng[0];
+      chrLength.push(L);
+      totalChrLength += L;
+    }
+    if (pad4heatmap) {
+      data.recwidth = maxd;
+      chrStart = chrStart.map(function(x) {
+        return x - maxd / 2;
+      });
+      chrEnd = chrEnd.map(function(x) {
+        return x + maxd / 2;
+      });
+      chrLength = chrLength.map(function(x) {
+        return x + maxd;
+      });
+      totalChrLength += chrLength.length * maxd;
+    }
+    data.chrStart = [];
+    data.chrEnd = [];
+    cur = leftMargin;
+    if (!pad4heatmap) {
+      cur += chrGap / 2;
+    }
+    data.xscale = {};
+    _ref1 = data.chrnames;
+    for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
+      chr = _ref1[i];
+      data.chrStart.push(cur);
+      w = Math.round((width - chrGap * (data.chrnames.length - pad4heatmap)) / totalChrLength * chrLength[i]);
+      data.chrEnd.push(cur + w);
+      cur = data.chrEnd[i] + chrGap;
+      data.xscale[chr] = d3.scale.linear().domain([chrStart[i], chrEnd[i]]).range([data.chrStart[i], data.chrEnd[i]]);
+    }
+    return data;
+  };
+
+  maxdiff = function(x) {
+    var d, i, result, _i, _ref;
+    if (x.length < 2) {
+      return null;
+    }
+    result = x[1] - x[0];
+    if (x.length < 3) {
+      return result;
+    }
+    for (i = _i = 2, _ref = x.length; 2 <= _ref ? _i < _ref : _i > _ref; i = 2 <= _ref ? ++_i : --_i) {
+      d = x[i] - x[i - 1];
+      if (d > result) {
+        result = d;
+      }
+    }
+    return result;
+  };
+
+  formatAxis = function(d) {
+    var ndig;
+    d = d[1] - d[0];
+    ndig = Math.floor(Math.log(d % 10) / Math.log(10));
+    if (ndig > 0) {
+      ndig = 0;
+    }
+    ndig = Math.abs(ndig);
+    return d3.format("." + ndig + "f");
+  };
+
+}).call(this);
diff --git a/wqflask/wqflask/static/new/javascript/marker_regression.coffee b/wqflask/wqflask/static/new/javascript/marker_regression.coffee
index a0d492c1..8038ad9a 100755
--- a/wqflask/wqflask/static/new/javascript/marker_regression.coffee
+++ b/wqflask/wqflask/static/new/javascript/marker_regression.coffee
@@ -87,12 +87,12 @@ class Manhattan_Plot
                 high_qtl_count += 1
         console.log("high_qtl_count:", high_qtl_count)
         
-        if high_qtl_count > 10000
-            @y_axis_filter = 2
-        else if high_qtl_count > 1000
-            @y_axis_filter = 1
-        else
-            @y_axis_filter = 0
+        #if high_qtl_count > 10000
+        @y_axis_filter = 2
+        #else if high_qtl_count > 1000
+        #    @y_axis_filter = 1
+        #else
+        #    @y_axis_filter = 0
 
             
     create_coordinates: () -> 
@@ -364,8 +364,8 @@ class Manhattan_Plot
             .append("text")
             .attr("class", "chr_label")
             .text((d) =>

-                if @max_chr == "24"
-                    if d[0] == 23
+                if @max_chr == 23
+                    if d[0] == "23"
                         return "X"
                     else if d[0] == "24"
                         return "X/Y"

@@ -404,16 +404,16 @@ class Manhattan_Plot
                 return @y_scale(d[1])
             )
             .attr("r", (d) =>
-                if d[1] > 3
-                    return 3
-                else
-                    return 2
+                #if d[1] > 3
+                #    return 3
+                #else
+                return 2
             )
             .attr("fill", (d) =>
-                if d[1] > 3
-                    return "white"
-                else
-                    return "black"
+                #if d[1] > 3
+                #    return "white"
+                #else
+                return "black"
             )
             .attr("stroke", "black")
             .attr("stroke-width", "1")
@@ -435,16 +435,16 @@ class Manhattan_Plot
                 this_id = "point_" + String(d[2])
                 d3.select("#" + this_id).classed("d3_highlight", false)
                     .attr("r", (d) =>
-                        if d[1] > 2
-                            return 3
-                        else
-                            return 2
+                        #if d[1] > 2
+                        #    return 3
+                        #else
+                        return 2
                     )
                     .attr("fill", (d) =>
-                        if d[1] > 2
-                            return "white"
-                        else
-                            return "black"
+                        #if d[1] > 2
+                        #    return "white"
+                        #else
+                        return "black"
                     )
                     .attr("stroke", "black")
                     .attr("stroke-width", "1")
diff --git a/wqflask/wqflask/static/new/javascript/marker_regression.js b/wqflask/wqflask/static/new/javascript/marker_regression.js
index 59b801d5..e3c316dd 100755
--- a/wqflask/wqflask/static/new/javascript/marker_regression.js
+++ b/wqflask/wqflask/static/new/javascript/marker_regression.js
@@ -94,13 +94,7 @@
         }
       }
       console.log("high_qtl_count:", high_qtl_count);
-      if (high_qtl_count > 10000) {
-        return this.y_axis_filter = 2;
-      } else if (high_qtl_count > 1000) {
-        return this.y_axis_filter = 1;
-      } else {
-        return this.y_axis_filter = 0;
-      }
+      return this.y_axis_filter = 2;
     };
 
     Manhattan_Plot.prototype.create_coordinates = function() {
@@ -299,8 +293,8 @@
       return this.svg.selectAll("text").data(chr_info, function(d) {
         return d;
       }).enter().append("text").attr("class", "chr_label").text(function(d) {
-        if (_this.max_chr === "24") {
-          if (d[0] === 23) {
+        if (_this.max_chr === 23) {
+          if (d[0] === "23") {
             return "X";
           } else if (d[0] === "24") {
             return "X/Y";
@@ -330,17 +324,9 @@
       }).attr("cy", function(d) {
         return _this.y_scale(d[1]);
       }).attr("r", function(d) {
-        if (d[1] > 3) {
-          return 3;
-        } else {
-          return 2;
-        }
+        return 2;
       }).attr("fill", function(d) {
-        if (d[1] > 3) {
-          return "white";
-        } else {
-          return "black";
-        }
+        return "black";
       }).attr("stroke", "black").attr("stroke-width", "1").attr("id", function(d) {
         return "point_" + String(d[2]);
       }).classed("circle", true).on("mouseover", function(d) {
@@ -353,17 +339,9 @@
         var this_id;
         this_id = "point_" + String(d[2]);
         return d3.select("#" + this_id).classed("d3_highlight", false).attr("r", function(d) {
-          if (d[1] > 2) {
-            return 3;
-          } else {
-            return 2;
-          }
+          return 2;
         }).attr("fill", function(d) {
-          if (d[1] > 2) {
-            return "white";
-          } else {
-            return "black";
-          }
+          return "black";
         }).attr("stroke", "black").attr("stroke-width", "1");
       }).append("svg:title").text(function(d) {
         return d[2];
diff --git a/wqflask/wqflask/static/new/javascript/panelutil.coffee b/wqflask/wqflask/static/new/javascript/panelutil.coffee
new file mode 100644
index 00000000..42636369
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/panelutil.coffee
@@ -0,0 +1,205 @@
+# A variety of utility functions used by the different panel functions

+

+root = exports ? this

+

+# determine rounding of axis labels

+formatAxis = (d) ->

+  d = d[1] - d[0]

+  ndig = Math.floor( Math.log(d % 10) / Math.log(10) )

+  ndig = 0 if ndig > 0

+  ndig = Math.abs(ndig)

+  d3.format(".#{ndig}f")

+

+# unique values of array (ignore nulls)

+unique = (x) ->

+  output = {}

+  output[v] = v for v in x when v

+  output[v] for v of output

+

+# Pull out a variable (column) from a two-dimensional array

+pullVarAsArray = (data, variable) ->

+  v = []

+  for i of data

+    v = v.concat data[i][variable]

+  v

+  

+# reorganize lod/pos by chromosome

+# lodvarname==null    -> case for multiple LOD columns (lodheatmap)

+# lodvarname provided -> case for one LOD column (lodchart)

+reorgLodData = (data, lodvarname=null) ->

+  data.posByChr = {}

+  data.lodByChr = {}

+

+  for chr,i in data.chrnames

+    data.posByChr[chr] = []

+    data.lodByChr[chr] = []

+    for pos,j in data.pos

+      if data.chr[j] == chr

+        data.posByChr[chr].push(pos)

+        data.lodnames = [data.lodnames] unless Array.isArray(data.lodnames)

+        lodval = (data[lodcolumn][j] for lodcolumn in data.lodnames)

+        data.lodByChr[chr].push(lodval)

+

+  if lodvarname?

+    data.markers = []

+    for marker,i in data.markernames

+      if marker != ""

+        data.markers.push({name:marker, chr:data.chr[i], pos:data.pos[i], lod:data[lodvarname][i]})

+

+  data

+

+# calculate chromosome start/end + scales, for heat map

+chrscales = (data, width, chrGap, leftMargin, pad4heatmap) ->

+  # start and end of chromosome positions

+  chrStart = []

+  chrEnd = []

+  chrLength = []

+  totalChrLength = 0

+  maxd = 0

+  for chr in data.chrnames

+    d = maxdiff(data.posByChr[chr])

+    maxd = d if d > maxd

+

+    rng = d3.extent(data.posByChr[chr])

+    chrStart.push(rng[0])

+    chrEnd.push(rng[1])

+    L = rng[1] - rng[0]

+    chrLength.push(L)

+    totalChrLength += L

+

+  # adjust lengths for heatmap

+  if pad4heatmap

+    data.recwidth = maxd

+    chrStart = chrStart.map (x) -> x-maxd/2

+    chrEnd = chrEnd.map (x) -> x+maxd/2

+    chrLength = chrLength.map (x) -> x+maxd

+    totalChrLength += (chrLength.length*maxd)

+

+  # break up x axis into chromosomes by length, with gaps

+  data.chrStart = []

+  data.chrEnd = []

+  cur = leftMargin

+  cur += chrGap/2 unless pad4heatmap

+  data.xscale = {}

+  for chr,i in data.chrnames

+    data.chrStart.push(cur)

+    w = Math.round((width-chrGap*(data.chrnames.length-pad4heatmap))/totalChrLength*chrLength[i])

+    data.chrEnd.push(cur + w)

+    cur = data.chrEnd[i] + chrGap

+    # x-axis scales, by chromosome

+    data.xscale[chr] = d3.scale.linear()

+                         .domain([chrStart[i], chrEnd[i]])

+                         .range([data.chrStart[i], data.chrEnd[i]])

+

+  # return data with new stuff added

+  data

+

+# Select a set of categorical colors

+# ngroup is positive integer

+# palette = "dark" or "pastel"

+selectGroupColors = (ngroup, palette) ->

+  return [] if ngroup == 0

+

+  if palette == "dark"

+    return ["slateblue"] if ngroup == 1

+    return ["MediumVioletRed", "slateblue"] if ngroup == 2

+    return colorbrewer.Set1[ngroup] if ngroup <= 9

+    return d3.scale.category20().range()[0...ngroup]

+  else

+    return [d3.rgb(190, 190, 190)] if ngroup == 1

+    return ["lightpink", "lightblue"] if ngroup == 2

+    return colorbrewer.Pastel1[ngroup] if ngroup <= 9

+    # below is rough attempt to make _big_ pastel palette

+    return ["#8fc7f4", "#fed7f8", "#ffbf8e", "#fffbb8",

+            "#8ce08c", "#d8ffca", "#f68788", "#ffd8d6",

+            "#d4a7fd", "#f5f0f5", "#cc968b", "#f4dcd4",

+            "#f3b7f2", "#f7f6f2", "#bfbfbf", "#f7f7f7",

+            "#fcfd82", "#fbfbcd", "#87feff", "#defaf5"][0...ngroup]

+

+# expand element/array (e.g., of colors) to a given length

+#     single elment -> array, then repeated to length n

+expand2vector = (input, n) ->

+  return input if Array.isArray(input) and input.length >= n

+  input = [input] unless Array.isArray(input)

+  input = (input[0] for i of d3.range(n)) if input.length == 1 and n > 1

+  input

+

+# median of a vector

+median = (x) ->

+  return null if !x? 

+  n = x.length

+  x.sort((a,b) -> a-b)

+  if n % 2 == 1

+    return x[(n-1)/2]

+  (x[n/2] + x[(n/2)-1])/2

+

+# given a vector of x's, return hash with values to left and right, and the differences

+getLeftRight = (x) ->

+  n = x.length

+  x.sort( (a,b) -> a-b )

+

+  xdif = []

+  result = {}

+  for v in x

+    result[v] = {}

+

+  for i in [1...n]

+    xdif.push(x[i]-x[i-1])

+    result[x[i]].left = x[i-1]

+  for i in [0...(n-1)]

+    result[x[i]].right = x[i+1]

+

+  xdif = median(xdif)

+  result.mediandiff = xdif

+

+  result[x[0]].left = x[0]-xdif

+  result[x[n-1]].right = x[n-1]+xdif

+  result.extent = [x[0]-xdif/2, x[n-1]+xdif/2]

+

+  result

+

+# maximum difference between adjacent values in a vector

+maxdiff = (x) ->

+  return null if x.length < 2

+  result = x[1] - x[0]

+  return result if x.length < 3

+  for i in [2...x.length]

+    d = x[i] - x[i-1]

+    result = d if d > result

+  result

+

+# matrix extent, min max

+matrixMin = (mat) ->

+  result = mat[0][0]

+  for i of mat

+    for j of mat[i]

+      result = mat[i][j] if result > mat[i][j]

+  result      

+

+matrixMax = (mat) ->

+  result = mat[0][0]

+  for i of mat

+    for j of mat[i]

+      result = mat[i][j] if result < mat[i][j]

+  result      

+

+matrixMaxAbs = (mat) ->

+  result = Math.abs(mat[0][0])

+  for i of mat

+    for j of mat[i]

+      result = Math.abs(mat[i][j]) if result < mat[i][j]

+  result      

+

+matrixExtent = (mat) -> [matrixMin(mat), matrixMax(mat)]

+

+d3.selection.prototype.moveToFront = () ->

+  this.each () -> this.parentNode.appendChild(this)

+  

+d3.selection.prototype.moveToBack = () ->

+  this.each () ->

+    firstChild = this.parentNode.firstchild

+    this.parentNode.insertBefore(this, firstChild) if firstChild

+

+forceAsArray = (x) ->

+  return x if Array.isArray(x)

+  [x]
\ No newline at end of file
diff --git a/wqflask/wqflask/static/new/javascript/panelutil.js b/wqflask/wqflask/static/new/javascript/panelutil.js
new file mode 100644
index 00000000..d5e7fd27
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/panelutil.js
@@ -0,0 +1,324 @@
+// Generated by CoffeeScript 1.6.1
+(function() {
+  var chrscales, expand2vector, forceAsArray, formatAxis, getLeftRight, matrixExtent, matrixMax, matrixMaxAbs, matrixMin, maxdiff, median, pullVarAsArray, reorgLodData, root, selectGroupColors, unique;
+
+  root = typeof exports !== "undefined" && exports !== null ? exports : this;
+
+  formatAxis = function(d) {
+    var ndig;
+    d = d[1] - d[0];
+    ndig = Math.floor(Math.log(d % 10) / Math.log(10));
+    if (ndig > 0) {
+      ndig = 0;
+    }
+    ndig = Math.abs(ndig);
+    return d3.format("." + ndig + "f");
+  };
+
+  unique = function(x) {
+    var output, v, _i, _len, _results;
+    output = {};
+    for (_i = 0, _len = x.length; _i < _len; _i++) {
+      v = x[_i];
+      if (v) {
+        output[v] = v;
+      }
+    }
+    _results = [];
+    for (v in output) {
+      _results.push(output[v]);
+    }
+    return _results;
+  };
+
+  pullVarAsArray = function(data, variable) {
+    var i, v;
+    v = [];
+    for (i in data) {
+      v = v.concat(data[i][variable]);
+    }
+    return v;
+  };
+
+  reorgLodData = function(data, lodvarname) {
+    var chr, i, j, lodcolumn, lodval, marker, pos, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
+    if (lodvarname == null) {
+      lodvarname = null;
+    }
+    data.posByChr = {};
+    data.lodByChr = {};
+    _ref = data.chrnames;
+    for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
+      chr = _ref[i];
+      data.posByChr[chr] = [];
+      data.lodByChr[chr] = [];
+      _ref1 = data.pos;
+      for (j = _j = 0, _len1 = _ref1.length; _j < _len1; j = ++_j) {
+        pos = _ref1[j];
+        if (data.chr[j] === chr) {
+          data.posByChr[chr].push(pos);
+          if (!Array.isArray(data.lodnames)) {
+            data.lodnames = [data.lodnames];
+          }
+          lodval = (function() {
+            var _k, _len2, _ref2, _results;
+            _ref2 = data.lodnames;
+            _results = [];
+            for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
+              lodcolumn = _ref2[_k];
+              _results.push(data[lodcolumn][j]);
+            }
+            return _results;
+          })();
+          data.lodByChr[chr].push(lodval);
+        }
+      }
+    }
+    if (lodvarname != null) {
+      data.markers = [];
+      _ref2 = data.markernames;
+      for (i = _k = 0, _len2 = _ref2.length; _k < _len2; i = ++_k) {
+        marker = _ref2[i];
+        if (marker !== "") {
+          data.markers.push({
+            name: marker,
+            chr: data.chr[i],
+            pos: data.pos[i],
+            lod: data[lodvarname][i]
+          });
+        }
+      }
+    }
+    return data;
+  };
+
+  chrscales = function(data, width, chrGap, leftMargin, pad4heatmap) {
+    var L, chr, chrEnd, chrLength, chrStart, cur, d, i, maxd, rng, totalChrLength, w, _i, _j, _len, _len1, _ref, _ref1;
+    chrStart = [];
+    chrEnd = [];
+    chrLength = [];
+    totalChrLength = 0;
+    maxd = 0;
+    _ref = data.chrnames;
+    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+      chr = _ref[_i];
+      d = maxdiff(data.posByChr[chr]);
+      if (d > maxd) {
+        maxd = d;
+      }
+      rng = d3.extent(data.posByChr[chr]);
+      chrStart.push(rng[0]);
+      chrEnd.push(rng[1]);
+      L = rng[1] - rng[0];
+      chrLength.push(L);
+      totalChrLength += L;
+    }
+    if (pad4heatmap) {
+      data.recwidth = maxd;
+      chrStart = chrStart.map(function(x) {
+        return x - maxd / 2;
+      });
+      chrEnd = chrEnd.map(function(x) {
+        return x + maxd / 2;
+      });
+      chrLength = chrLength.map(function(x) {
+        return x + maxd;
+      });
+      totalChrLength += chrLength.length * maxd;
+    }
+    data.chrStart = [];
+    data.chrEnd = [];
+    cur = leftMargin;
+    if (!pad4heatmap) {
+      cur += chrGap / 2;
+    }
+    data.xscale = {};
+    _ref1 = data.chrnames;
+    for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
+      chr = _ref1[i];
+      data.chrStart.push(cur);
+      w = Math.round((width - chrGap * (data.chrnames.length - pad4heatmap)) / totalChrLength * chrLength[i]);
+      data.chrEnd.push(cur + w);
+      cur = data.chrEnd[i] + chrGap;
+      data.xscale[chr] = d3.scale.linear().domain([chrStart[i], chrEnd[i]]).range([data.chrStart[i], data.chrEnd[i]]);
+    }
+    return data;
+  };
+
+  selectGroupColors = function(ngroup, palette) {
+    if (ngroup === 0) {
+      return [];
+    }
+    if (palette === "dark") {
+      if (ngroup === 1) {
+        return ["slateblue"];
+      }
+      if (ngroup === 2) {
+        return ["MediumVioletRed", "slateblue"];
+      }
+      if (ngroup <= 9) {
+        return colorbrewer.Set1[ngroup];
+      }
+      return d3.scale.category20().range().slice(0, ngroup);
+    } else {
+      if (ngroup === 1) {
+        return [d3.rgb(190, 190, 190)];
+      }
+      if (ngroup === 2) {
+        return ["lightpink", "lightblue"];
+      }
+      if (ngroup <= 9) {
+        return colorbrewer.Pastel1[ngroup];
+      }
+      return ["#8fc7f4", "#fed7f8", "#ffbf8e", "#fffbb8", "#8ce08c", "#d8ffca", "#f68788", "#ffd8d6", "#d4a7fd", "#f5f0f5", "#cc968b", "#f4dcd4", "#f3b7f2", "#f7f6f2", "#bfbfbf", "#f7f7f7", "#fcfd82", "#fbfbcd", "#87feff", "#defaf5"].slice(0, ngroup);
+    }
+  };
+
+  expand2vector = function(input, n) {
+    var i;
+    if (Array.isArray(input) && input.length >= n) {
+      return input;
+    }
+    if (!Array.isArray(input)) {
+      input = [input];
+    }
+    if (input.length === 1 && n > 1) {
+      input = (function() {
+        var _results;
+        _results = [];
+        for (i in d3.range(n)) {
+          _results.push(input[0]);
+        }
+        return _results;
+      })();
+    }
+    return input;
+  };
+
+  median = function(x) {
+    var n;
+    if (x == null) {
+      return null;
+    }
+    n = x.length;
+    x.sort(function(a, b) {
+      return a - b;
+    });
+    if (n % 2 === 1) {
+      return x[(n - 1) / 2];
+    }
+    return (x[n / 2] + x[(n / 2) - 1]) / 2;
+  };
+
+  getLeftRight = function(x) {
+    var i, n, result, v, xdif, _i, _j, _k, _len, _ref;
+    n = x.length;
+    x.sort(function(a, b) {
+      return a - b;
+    });
+    xdif = [];
+    result = {};
+    for (_i = 0, _len = x.length; _i < _len; _i++) {
+      v = x[_i];
+      result[v] = {};
+    }
+    for (i = _j = 1; 1 <= n ? _j < n : _j > n; i = 1 <= n ? ++_j : --_j) {
+      xdif.push(x[i] - x[i - 1]);
+      result[x[i]].left = x[i - 1];
+    }
+    for (i = _k = 0, _ref = n - 1; 0 <= _ref ? _k < _ref : _k > _ref; i = 0 <= _ref ? ++_k : --_k) {
+      result[x[i]].right = x[i + 1];
+    }
+    xdif = median(xdif);
+    result.mediandiff = xdif;
+    result[x[0]].left = x[0] - xdif;
+    result[x[n - 1]].right = x[n - 1] + xdif;
+    result.extent = [x[0] - xdif / 2, x[n - 1] + xdif / 2];
+    return result;
+  };
+
+  maxdiff = function(x) {
+    var d, i, result, _i, _ref;
+    if (x.length < 2) {
+      return null;
+    }
+    result = x[1] - x[0];
+    if (x.length < 3) {
+      return result;
+    }
+    for (i = _i = 2, _ref = x.length; 2 <= _ref ? _i < _ref : _i > _ref; i = 2 <= _ref ? ++_i : --_i) {
+      d = x[i] - x[i - 1];
+      if (d > result) {
+        result = d;
+      }
+    }
+    return result;
+  };
+
+  matrixMin = function(mat) {
+    var i, j, result;
+    result = mat[0][0];
+    for (i in mat) {
+      for (j in mat[i]) {
+        if (result > mat[i][j]) {
+          result = mat[i][j];
+        }
+      }
+    }
+    return result;
+  };
+
+  matrixMax = function(mat) {
+    var i, j, result;
+    result = mat[0][0];
+    for (i in mat) {
+      for (j in mat[i]) {
+        if (result < mat[i][j]) {
+          result = mat[i][j];
+        }
+      }
+    }
+    return result;
+  };
+
+  matrixMaxAbs = function(mat) {
+    var i, j, result;
+    result = Math.abs(mat[0][0]);
+    for (i in mat) {
+      for (j in mat[i]) {
+        if (result < mat[i][j]) {
+          result = Math.abs(mat[i][j]);
+        }
+      }
+    }
+    return result;
+  };
+
+  matrixExtent = function(mat) {
+    return [matrixMin(mat), matrixMax(mat)];
+  };
+
+  d3.selection.prototype.moveToFront = function() {
+    return this.each(function() {
+      return this.parentNode.appendChild(this);
+    });
+  };
+
+  d3.selection.prototype.moveToBack = function() {
+    return this.each(function() {
+      var firstChild;
+      firstChild = this.parentNode.firstchild;
+      if (firstChild) {
+        return this.parentNode.insertBefore(this, firstChild);
+      }
+    });
+  };
+
+  forceAsArray = function(x) {
+    if (Array.isArray(x)) {
+      return x;
+    }
+    return [x];
+  };
+
+}).call(this);
diff --git a/wqflask/wqflask/static/new/javascript/scatterplot.coffee b/wqflask/wqflask/static/new/javascript/scatterplot.coffee
new file mode 100644
index 00000000..546205ce
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/scatterplot.coffee
@@ -0,0 +1,407 @@
+scatterplot = () ->

+    width = 800

+    height = 500

+    margin = {left:60, top:40, right:40, bottom: 40, inner:5}

+    axispos = {xtitle:25, ytitle:30, xlabel:5, ylabel:5}

+    titlepos = 20

+    xNA = {handle:true, force:false, width:15, gap:10}

+    yNA = {handle:true, force:false, width:15, gap:10}

+    xlim = null

+    ylim = null

+    nxticks = 5

+    xticks = null

+    nyticks = 5

+    yticks = null

+    rectcolor = d3.rgb(230, 230, 230)

+    pointcolor = null

+    pointstroke = "black"

+    pointsize = 3 # default = no visible points at markers

+    title = ""

+    xlab = "X"

+    ylab = "Y"

+    rotate_ylab = null

+    yscale = d3.scale.linear()

+    xscale = d3.scale.linear()

+    xvar = 0

+    yvar = 1

+    pointsSelect = null

+    dataByInd = true

+  

+    ## the main function

+    chart = (selection) ->

+      selection.each (data) ->

+  

+        if dataByInd

+          x = data.data.map (d) -> d[xvar]

+          y = data.data.map (d) -> d[yvar]

+        else # reorganize data

+          x = data.data[xvar]

+          y = data.data[yvar]

+  

+        # grab indID if it's there

+        # if no indID, create a vector of them

+        indID = data?.indID ? null

+        indID = indID ? [1..x.length]

+  

+        # groups of colors

+        group = data?.group ? (1 for i in x)

+        ngroup = d3.max(group)

+        group = (g-1 for g in group) # changed from (1,2,3,...) to (0,1,2,...)

+  

+        # colors of the points in the different groups

+        pointcolor = pointcolor ? selectGroupColors(ngroup, "dark")

+        pointcolor = expand2vector(pointcolor, ngroup)

+  

+        # if all (x,y) not null

+        xNA.handle = false if x.every (v) -> (v?) and !xNA.force

+        yNA.handle = false if y.every (v) -> (v?) and !yNA.force

+        if xNA.handle

+          paneloffset = xNA.width + xNA.gap

+          panelwidth = width - paneloffset

+        else

+          paneloffset = 0

+          panelwidth = width

+        if yNA.handle

+          panelheight = height - (yNA.width + yNA.gap)

+        else

+          panelheight = height

+  

+        xlim = xlim ? d3.extent(x)

+        ylim = ylim ? d3.extent(y)

+  

+        # I'll replace missing values something smaller than what's observed

+        na_value = d3.min(x.concat y) - 100

+  

+        # Select the svg element, if it exists.

+        svg = d3.select(this).selectAll("svg").data([data])

+  

+        # Otherwise, create the skeletal chart.

+        gEnter = svg.enter().append("svg").append("g")

+  

+        # Update the outer dimensions.

+        svg.attr("width", width+margin.left+margin.right)

+           .attr("height", height+margin.top+margin.bottom)

+  

+        g = svg.select("g")

+  

+        # box

+        g.append("rect")

+         .attr("x", paneloffset+margin.left)

+         .attr("y", margin.top)

+         .attr("height", panelheight)

+         .attr("width", panelwidth)

+         .attr("fill", rectcolor)

+         .attr("stroke", "none")

+        if xNA.handle

+          g.append("rect")

+           .attr("x", margin.left)

+           .attr("y", margin.top)

+           .attr("height", panelheight)

+           .attr("width", xNA.width)

+           .attr("fill", rectcolor)

+           .attr("stroke", "none")

+        if xNA.handle and yNA.handle

+          g.append("rect")

+           .attr("x", margin.left)

+           .attr("y", margin.top+height - yNA.width)

+           .attr("height", yNA.width)

+           .attr("width", xNA.width)

+           .attr("fill", rectcolor)

+           .attr("stroke", "none")

+        if yNA.handle

+          g.append("rect")

+           .attr("x", margin.left+paneloffset)

+           .attr("y", margin.top+height-yNA.width)

+           .attr("height", yNA.width)

+           .attr("width", panelwidth)

+           .attr("fill", rectcolor)

+           .attr("stroke", "none")

+  

+        # simple scales (ignore NA business)

+        xrange = [margin.left+paneloffset+margin.inner, margin.left+paneloffset+panelwidth-margin.inner]

+        yrange = [margin.top+panelheight-margin.inner, margin.top+margin.inner]

+        xscale.domain(xlim).range(xrange)

+        yscale.domain(ylim).range(yrange)

+        xs = d3.scale.linear().domain(xlim).range(xrange)

+        ys = d3.scale.linear().domain(ylim).range(yrange)

+  

+        # "polylinear" scales to handle missing values

+        if xNA.handle

+          xscale.domain([na_value].concat xlim) 

+                .range([margin.left + xNA.width/2].concat xrange)

+          x = x.map (e) -> if e? then e else na_value

+        if yNA.handle

+          yscale.domain([na_value].concat ylim)

+                .range([height+margin.top-yNA.width/2].concat yrange)

+          y = y.map (e) -> if e? then e else na_value

+  

+        # if yticks not provided, use nyticks to choose pretty ones

+        yticks = yticks ? ys.ticks(nyticks)

+        xticks = xticks ? xs.ticks(nxticks)

+  

+        # title

+        titlegrp = g.append("g").attr("class", "title")

+         .append("text")

+         .attr("x", margin.left + width/2)

+         .attr("y", margin.top - titlepos)

+         .text(title)

+  

+        # x-axis

+        xaxis = g.append("g").attr("class", "x axis")

+        xaxis.selectAll("empty")

+             .data(xticks)

+             .enter()

+             .append("line")

+             .attr("x1", (d) -> xscale(d))

+             .attr("x2", (d) -> xscale(d))

+             .attr("y1", margin.top)

+             .attr("y2", margin.top+height)

+             .attr("fill", "none")

+             .attr("stroke", "white")

+             .attr("stroke-width", 1)

+             .style("pointer-events", "none")

+        xaxis.selectAll("empty")

+             .data(xticks)

+             .enter()

+             .append("text")

+             .attr("x", (d) -> xscale(d))

+             .attr("y", margin.top+height+axispos.xlabel)

+             .text((d) -> formatAxis(xticks)(d))

+        xaxis.append("text").attr("class", "title")

+             .attr("x", margin.left+width/2)

+             .attr("y", margin.top+height+axispos.xtitle)

+             .text(xlab)

+        if xNA.handle

+          xaxis.append("text")

+              .attr("x", margin.left+xNA.width/2)

+              .attr("y", margin.top+height+axispos.xlabel)

+              .text("N/A")

+  

+        # y-axis

+        rotate_ylab = rotate_ylab ? (ylab.length > 1)

+        yaxis = g.append("g").attr("class", "y axis")

+        yaxis.selectAll("empty")

+             .data(yticks)

+             .enter()

+             .append("line")

+             .attr("y1", (d) -> yscale(d))

+             .attr("y2", (d) -> yscale(d))

+             .attr("x1", margin.left)

+             .attr("x2", margin.left+width)

+             .attr("fill", "none")

+             .attr("stroke", "white")

+             .attr("stroke-width", 1)

+             .style("pointer-events", "none")

+        yaxis.selectAll("empty")

+             .data(yticks)

+             .enter()

+             .append("text")

+             .attr("y", (d) -> yscale(d))

+             .attr("x", margin.left-axispos.ylabel)

+             .text((d) -> formatAxis(yticks)(d))

+        yaxis.append("text").attr("class", "title")

+             .attr("y", margin.top+height/2)

+             .attr("x", margin.left-axispos.ytitle)

+             .text(ylab)

+             .attr("transform", if rotate_ylab then "rotate(270,#{margin.left-axispos.ytitle},#{margin.top+height/2})" else "")

+        if yNA.handle

+          yaxis.append("text")

+              .attr("x", margin.left-axispos.ylabel)

+              .attr("y", margin.top+height-yNA.width/2)

+              .text("N/A")

+  

+        indtip = d3.tip()

+                   .attr('class', 'd3-tip')

+                   .html((d,i) -> indID[i])

+                   .direction('e')

+                   .offset([0,10])

+        svg.call(indtip)

+  

+        points = g.append("g").attr("id", "points")

+        pointsSelect =

+          points.selectAll("empty")

+                .data(d3.range(x.length))

+                .enter()

+                .append("circle")

+                .attr("cx", (d,i) -> xscale(x[i]))

+                .attr("cy", (d,i) -> yscale(y[i]))

+                .attr("class", (d,i) -> "pt#{i}")

+                .attr("r", pointsize)

+                .attr("fill", (d,i) -> pointcolor[group[i]])

+                .attr("stroke", pointstroke)

+                .attr("stroke-width", "1")

+                .attr("opacity", (d,i) ->

+                     return 1 if (x[i]? or xNA.handle) and (y[i]? or yNA.handle)

+                     return 0)

+                .on("mouseover.paneltip", indtip.show)

+                .on("mouseout.paneltip", indtip.hide)

+  

+        # box

+        g.append("rect")

+               .attr("x", margin.left+paneloffset)

+               .attr("y", margin.top)

+               .attr("height", panelheight)

+               .attr("width", panelwidth)

+               .attr("fill", "none")

+               .attr("stroke", "black")

+               .attr("stroke-width", "none")

+        if xNA.handle

+          g.append("rect")

+           .attr("x", margin.left)

+           .attr("y", margin.top)

+           .attr("height", panelheight)

+           .attr("width", xNA.width)

+           .attr("fill", "none")

+           .attr("stroke", "black")

+           .attr("stroke-width", "none")

+        if xNA.handle and yNA.handle

+          g.append("rect")

+           .attr("x", margin.left)

+           .attr("y", margin.top+height - yNA.width)

+           .attr("height", yNA.width)

+           .attr("width", xNA.width)

+           .attr("fill", "none")

+           .attr("stroke", "black")

+           .attr("stroke-width", "none")

+        if yNA.handle

+          g.append("rect")

+           .attr("x", margin.left+paneloffset)

+           .attr("y", margin.top+height-yNA.width)

+           .attr("height", yNA.width)

+           .attr("width", panelwidth)

+           .attr("fill", "none")

+           .attr("stroke", "black")

+           .attr("stroke-width", "none")

+  

+    ## configuration parameters

+    chart.width = (value) ->

+      return width if !arguments.length

+      width = value

+      chart

+  

+    chart.height = (value) ->

+      return height if !arguments.length

+      height = value

+      chart

+  

+    chart.margin = (value) ->

+      return margin if !arguments.length

+      margin = value

+      chart

+  

+    chart.axispos = (value) ->

+      return axispos if !arguments.length

+      axispos = value

+      chart

+  

+    chart.titlepos = (value) ->

+      return titlepos if !arguments.length

+      titlepos

+      chart

+  

+    chart.xlim = (value) ->

+      return xlim if !arguments.length

+      xlim = value

+      chart

+  

+    chart.nxticks = (value) ->

+      return nxticks if !arguments.length

+      nxticks = value

+      chart

+  

+    chart.xticks = (value) ->

+      return xticks if !arguments.length

+      xticks = value

+      chart

+  

+    chart.ylim = (value) ->

+      return ylim if !arguments.length

+      ylim = value

+      chart

+  

+    chart.nyticks = (value) ->

+      return nyticks if !arguments.length

+      nyticks = value

+      chart

+  

+    chart.yticks = (value) ->

+      return yticks if !arguments.length

+      yticks = value

+      chart

+  

+    chart.rectcolor = (value) ->

+      return rectcolor if !arguments.length

+      rectcolor = value

+      chart

+  

+    chart.pointcolor = (value) ->

+      return pointcolor if !arguments.length

+      pointcolor = value

+      chart

+  

+    chart.pointsize = (value) ->

+      return pointsize if !arguments.length

+      pointsize = value

+      chart

+  

+    chart.pointstroke = (value) ->

+      return pointstroke if !arguments.length

+      pointstroke = value

+      chart

+  

+    chart.dataByInd = (value) ->

+      return dataByInd if !arguments.length

+      dataByInd = value

+      chart

+  

+    chart.title = (value) ->

+      return title if !arguments.length

+      title = value

+      chart

+  

+    chart.xlab = (value) ->

+      return xlab if !arguments.length

+      xlab = value

+      chart

+  

+    chart.ylab = (value) ->

+      return ylab if !arguments.length

+      ylab = value

+      chart

+  

+    chart.rotate_ylab = (value) ->

+      return rotate_ylab if !arguments.length

+      rotate_ylab = value

+      chart

+  

+    chart.xvar = (value) ->

+      return xvar if !arguments.length

+      xvar = value

+      chart

+  

+    chart.yvar = (value) ->

+      return yvar if !arguments.length

+      yvar = value

+      chart

+  

+    chart.xNA = (value) ->

+      return xNA if !arguments.length

+      xNA = value

+      chart

+  

+    chart.yNA = (value) ->

+      return yNA if !arguments.length

+      yNA = value

+      chart

+  

+    chart.yscale = () ->

+      return yscale

+  

+    chart.xscale = () ->

+      return xscale

+  

+    chart.pointsSelect = () ->

+      return pointsSelect

+  

+    # return the chart function

+    chart
\ No newline at end of file
diff --git a/wqflask/wqflask/static/new/javascript/scatterplot.js b/wqflask/wqflask/static/new/javascript/scatterplot.js
new file mode 100644
index 00000000..23a66e6b
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/scatterplot.js
@@ -0,0 +1,406 @@
+// Generated by CoffeeScript 1.6.1
+(function() {
+  var scatterplot;
+
+  scatterplot = function() {
+    var axispos, chart, dataByInd, height, margin, nxticks, nyticks, pointcolor, pointsSelect, pointsize, pointstroke, rectcolor, rotate_ylab, title, titlepos, width, xNA, xlab, xlim, xscale, xticks, xvar, yNA, ylab, ylim, yscale, yticks, yvar;
+    width = 800;
+    height = 500;
+    margin = {
+      left: 60,
+      top: 40,
+      right: 40,
+      bottom: 40,
+      inner: 5
+    };
+    axispos = {
+      xtitle: 25,
+      ytitle: 30,
+      xlabel: 5,
+      ylabel: 5
+    };
+    titlepos = 20;
+    xNA = {
+      handle: true,
+      force: false,
+      width: 15,
+      gap: 10
+    };
+    yNA = {
+      handle: true,
+      force: false,
+      width: 15,
+      gap: 10
+    };
+    xlim = null;
+    ylim = null;
+    nxticks = 5;
+    xticks = null;
+    nyticks = 5;
+    yticks = null;
+    rectcolor = d3.rgb(230, 230, 230);
+    pointcolor = null;
+    pointstroke = "black";
+    pointsize = 3;
+    title = "";
+    xlab = "X";
+    ylab = "Y";
+    rotate_ylab = null;
+    yscale = d3.scale.linear();
+    xscale = d3.scale.linear();
+    xvar = 0;
+    yvar = 1;
+    pointsSelect = null;
+    dataByInd = true;
+    chart = function(selection) {
+      return selection.each(function(data) {
+        var g, gEnter, group, i, indID, indtip, na_value, ngroup, panelheight, paneloffset, panelwidth, points, svg, titlegrp, x, xaxis, xrange, xs, y, yaxis, yrange, ys, _i, _ref, _ref1, _ref2, _results;
+        if (dataByInd) {
+          x = data.data.map(function(d) {
+            return d[xvar];
+          });
+          y = data.data.map(function(d) {
+            return d[yvar];
+          });
+        } else {
+          x = data.data[xvar];
+          y = data.data[yvar];
+        }
+        indID = (_ref = data != null ? data.indID : void 0) != null ? _ref : null;
+        indID = indID != null ? indID : (function() {
+          _results = [];
+          for (var _i = 1, _ref1 = x.length; 1 <= _ref1 ? _i <= _ref1 : _i >= _ref1; 1 <= _ref1 ? _i++ : _i--){ _results.push(_i); }
+          return _results;
+        }).apply(this);
+        group = (_ref2 = data != null ? data.group : void 0) != null ? _ref2 : (function() {
+          var _j, _len, _results1;
+          _results1 = [];
+          for (_j = 0, _len = x.length; _j < _len; _j++) {
+            i = x[_j];
+            _results1.push(1);
+          }
+          return _results1;
+        })();
+        ngroup = d3.max(group);
+        group = (function() {
+          var _j, _len, _results1;
+          _results1 = [];
+          for (_j = 0, _len = group.length; _j < _len; _j++) {
+            g = group[_j];
+            _results1.push(g - 1);
+          }
+          return _results1;
+        })();
+        pointcolor = pointcolor != null ? pointcolor : selectGroupColors(ngroup, "dark");
+        pointcolor = expand2vector(pointcolor, ngroup);
+        if (x.every(function(v) {
+          return (v != null) && !xNA.force;
+        })) {
+          xNA.handle = false;
+        }
+        if (y.every(function(v) {
+          return (v != null) && !yNA.force;
+        })) {
+          yNA.handle = false;
+        }
+        if (xNA.handle) {
+          paneloffset = xNA.width + xNA.gap;
+          panelwidth = width - paneloffset;
+        } else {
+          paneloffset = 0;
+          panelwidth = width;
+        }
+        if (yNA.handle) {
+          panelheight = height - (yNA.width + yNA.gap);
+        } else {
+          panelheight = height;
+        }
+        xlim = xlim != null ? xlim : d3.extent(x);
+        ylim = ylim != null ? ylim : d3.extent(y);
+        na_value = d3.min(x.concat(y)) - 100;
+        svg = d3.select(this).selectAll("svg").data([data]);
+        gEnter = svg.enter().append("svg").append("g");
+        svg.attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom);
+        g = svg.select("g");
+        g.append("rect").attr("x", paneloffset + margin.left).attr("y", margin.top).attr("height", panelheight).attr("width", panelwidth).attr("fill", rectcolor).attr("stroke", "none");
+        if (xNA.handle) {
+          g.append("rect").attr("x", margin.left).attr("y", margin.top).attr("height", panelheight).attr("width", xNA.width).attr("fill", rectcolor).attr("stroke", "none");
+        }
+        if (xNA.handle && yNA.handle) {
+          g.append("rect").attr("x", margin.left).attr("y", margin.top + height - yNA.width).attr("height", yNA.width).attr("width", xNA.width).attr("fill", rectcolor).attr("stroke", "none");
+        }
+        if (yNA.handle) {
+          g.append("rect").attr("x", margin.left + paneloffset).attr("y", margin.top + height - yNA.width).attr("height", yNA.width).attr("width", panelwidth).attr("fill", rectcolor).attr("stroke", "none");
+        }
+        xrange = [margin.left + paneloffset + margin.inner, margin.left + paneloffset + panelwidth - margin.inner];
+        yrange = [margin.top + panelheight - margin.inner, margin.top + margin.inner];
+        xscale.domain(xlim).range(xrange);
+        yscale.domain(ylim).range(yrange);
+        xs = d3.scale.linear().domain(xlim).range(xrange);
+        ys = d3.scale.linear().domain(ylim).range(yrange);
+        if (xNA.handle) {
+          xscale.domain([na_value].concat(xlim)).range([margin.left + xNA.width / 2].concat(xrange));
+          x = x.map(function(e) {
+            if (e != null) {
+              return e;
+            } else {
+              return na_value;
+            }
+          });
+        }
+        if (yNA.handle) {
+          yscale.domain([na_value].concat(ylim)).range([height + margin.top - yNA.width / 2].concat(yrange));
+          y = y.map(function(e) {
+            if (e != null) {
+              return e;
+            } else {
+              return na_value;
+            }
+          });
+        }
+        yticks = yticks != null ? yticks : ys.ticks(nyticks);
+        xticks = xticks != null ? xticks : xs.ticks(nxticks);
+        titlegrp = g.append("g").attr("class", "title").append("text").attr("x", margin.left + width / 2).attr("y", margin.top - titlepos).text(title);
+        xaxis = g.append("g").attr("class", "x axis");
+        xaxis.selectAll("empty").data(xticks).enter().append("line").attr("x1", function(d) {
+          return xscale(d);
+        }).attr("x2", function(d) {
+          return xscale(d);
+        }).attr("y1", margin.top).attr("y2", margin.top + height).attr("fill", "none").attr("stroke", "white").attr("stroke-width", 1).style("pointer-events", "none");
+        xaxis.selectAll("empty").data(xticks).enter().append("text").attr("x", function(d) {
+          return xscale(d);
+        }).attr("y", margin.top + height + axispos.xlabel).text(function(d) {
+          return formatAxis(xticks)(d);
+        });
+        xaxis.append("text").attr("class", "title").attr("x", margin.left + width / 2).attr("y", margin.top + height + axispos.xtitle).text(xlab);
+        if (xNA.handle) {
+          xaxis.append("text").attr("x", margin.left + xNA.width / 2).attr("y", margin.top + height + axispos.xlabel).text("N/A");
+        }
+        rotate_ylab = rotate_ylab != null ? rotate_ylab : ylab.length > 1;
+        yaxis = g.append("g").attr("class", "y axis");
+        yaxis.selectAll("empty").data(yticks).enter().append("line").attr("y1", function(d) {
+          return yscale(d);
+        }).attr("y2", function(d) {
+          return yscale(d);
+        }).attr("x1", margin.left).attr("x2", margin.left + width).attr("fill", "none").attr("stroke", "white").attr("stroke-width", 1).style("pointer-events", "none");
+        yaxis.selectAll("empty").data(yticks).enter().append("text").attr("y", function(d) {
+          return yscale(d);
+        }).attr("x", margin.left - axispos.ylabel).text(function(d) {
+          return formatAxis(yticks)(d);
+        });
+        yaxis.append("text").attr("class", "title").attr("y", margin.top + height / 2).attr("x", margin.left - axispos.ytitle).text(ylab).attr("transform", rotate_ylab ? "rotate(270," + (margin.left - axispos.ytitle) + "," + (margin.top + height / 2) + ")" : "");
+        if (yNA.handle) {
+          yaxis.append("text").attr("x", margin.left - axispos.ylabel).attr("y", margin.top + height - yNA.width / 2).text("N/A");
+        }
+        indtip = d3.tip().attr('class', 'd3-tip').html(function(d, i) {
+          return indID[i];
+        }).direction('e').offset([0, 10]);
+        svg.call(indtip);
+        points = g.append("g").attr("id", "points");
+        pointsSelect = points.selectAll("empty").data(d3.range(x.length)).enter().append("circle").attr("cx", function(d, i) {
+          return xscale(x[i]);
+        }).attr("cy", function(d, i) {
+          return yscale(y[i]);
+        }).attr("class", function(d, i) {
+          return "pt" + i;
+        }).attr("r", pointsize).attr("fill", function(d, i) {
+          return pointcolor[group[i]];
+        }).attr("stroke", pointstroke).attr("stroke-width", "1").attr("opacity", function(d, i) {
+          if (((x[i] != null) || xNA.handle) && ((y[i] != null) || yNA.handle)) {
+            return 1;
+          }
+          return 0;
+        }).on("mouseover.paneltip", indtip.show).on("mouseout.paneltip", indtip.hide);
+        g.append("rect").attr("x", margin.left + paneloffset).attr("y", margin.top).attr("height", panelheight).attr("width", panelwidth).attr("fill", "none").attr("stroke", "black").attr("stroke-width", "none");
+        if (xNA.handle) {
+          g.append("rect").attr("x", margin.left).attr("y", margin.top).attr("height", panelheight).attr("width", xNA.width).attr("fill", "none").attr("stroke", "black").attr("stroke-width", "none");
+        }
+        if (xNA.handle && yNA.handle) {
+          g.append("rect").attr("x", margin.left).attr("y", margin.top + height - yNA.width).attr("height", yNA.width).attr("width", xNA.width).attr("fill", "none").attr("stroke", "black").attr("stroke-width", "none");
+        }
+        if (yNA.handle) {
+          return g.append("rect").attr("x", margin.left + paneloffset).attr("y", margin.top + height - yNA.width).attr("height", yNA.width).attr("width", panelwidth).attr("fill", "none").attr("stroke", "black").attr("stroke-width", "none");
+        }
+      });
+    };
+    chart.width = function(value) {
+      if (!arguments.length) {
+        return width;
+      }
+      width = value;
+      return chart;
+    };
+    chart.height = function(value) {
+      if (!arguments.length) {
+        return height;
+      }
+      height = value;
+      return chart;
+    };
+    chart.margin = function(value) {
+      if (!arguments.length) {
+        return margin;
+      }
+      margin = value;
+      return chart;
+    };
+    chart.axispos = function(value) {
+      if (!arguments.length) {
+        return axispos;
+      }
+      axispos = value;
+      return chart;
+    };
+    chart.titlepos = function(value) {
+      if (!arguments.length) {
+        return titlepos;
+      }
+      titlepos;
+      return chart;
+    };
+    chart.xlim = function(value) {
+      if (!arguments.length) {
+        return xlim;
+      }
+      xlim = value;
+      return chart;
+    };
+    chart.nxticks = function(value) {
+      if (!arguments.length) {
+        return nxticks;
+      }
+      nxticks = value;
+      return chart;
+    };
+    chart.xticks = function(value) {
+      if (!arguments.length) {
+        return xticks;
+      }
+      xticks = value;
+      return chart;
+    };
+    chart.ylim = function(value) {
+      if (!arguments.length) {
+        return ylim;
+      }
+      ylim = value;
+      return chart;
+    };
+    chart.nyticks = function(value) {
+      if (!arguments.length) {
+        return nyticks;
+      }
+      nyticks = value;
+      return chart;
+    };
+    chart.yticks = function(value) {
+      if (!arguments.length) {
+        return yticks;
+      }
+      yticks = value;
+      return chart;
+    };
+    chart.rectcolor = function(value) {
+      if (!arguments.length) {
+        return rectcolor;
+      }
+      rectcolor = value;
+      return chart;
+    };
+    chart.pointcolor = function(value) {
+      if (!arguments.length) {
+        return pointcolor;
+      }
+      pointcolor = value;
+      return chart;
+    };
+    chart.pointsize = function(value) {
+      if (!arguments.length) {
+        return pointsize;
+      }
+      pointsize = value;
+      return chart;
+    };
+    chart.pointstroke = function(value) {
+      if (!arguments.length) {
+        return pointstroke;
+      }
+      pointstroke = value;
+      return chart;
+    };
+    chart.dataByInd = function(value) {
+      if (!arguments.length) {
+        return dataByInd;
+      }
+      dataByInd = value;
+      return chart;
+    };
+    chart.title = function(value) {
+      if (!arguments.length) {
+        return title;
+      }
+      title = value;
+      return chart;
+    };
+    chart.xlab = function(value) {
+      if (!arguments.length) {
+        return xlab;
+      }
+      xlab = value;
+      return chart;
+    };
+    chart.ylab = function(value) {
+      if (!arguments.length) {
+        return ylab;
+      }
+      ylab = value;
+      return chart;
+    };
+    chart.rotate_ylab = function(value) {
+      if (!arguments.length) {
+        return rotate_ylab;
+      }
+      rotate_ylab = value;
+      return chart;
+    };
+    chart.xvar = function(value) {
+      if (!arguments.length) {
+        return xvar;
+      }
+      xvar = value;
+      return chart;
+    };
+    chart.yvar = function(value) {
+      if (!arguments.length) {
+        return yvar;
+      }
+      yvar = value;
+      return chart;
+    };
+    chart.xNA = function(value) {
+      if (!arguments.length) {
+        return xNA;
+      }
+      xNA = value;
+      return chart;
+    };
+    chart.yNA = function(value) {
+      if (!arguments.length) {
+        return yNA;
+      }
+      yNA = value;
+      return chart;
+    };
+    chart.yscale = function() {
+      return yscale;
+    };
+    chart.xscale = function() {
+      return xscale;
+    };
+    chart.pointsSelect = function() {
+      return pointsSelect;
+    };
+    return chart;
+  };
+
+}).call(this);
diff --git a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.coffee b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.coffee
index 1d375686..6118eae8 100755
--- a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.coffee
+++ b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.coffee
@@ -120,6 +120,7 @@ $ ->
     )
 
     $("#plink_compute").click(() =>
+        $("#static_progress_bar_container").modal()
         url = "/marker_regression"
         $('input[name=method]').val("plink")
         $('input[name=mapping_display_all]').val($('input[name=display_all_plink]'))
@@ -135,11 +136,11 @@ $ ->
                 alert("Sorry, an error occurred")
                 console.log(xhr)
                 clearInterval(this.my_timer)
-                $('#progress_bar_container').modal('hide')
+                $('#static_progress_bar_container').modal('hide')
                 $("body").html("We got an error.")        
             success: (data) =>
                 clearInterval(this.my_timer)
-                $('#progress_bar_container').modal('hide')
+                $('#static_progress_bar_container').modal('hide')
                 $("body").html(data)
         )
         console.log("settingInterval")
@@ -149,6 +150,7 @@ $ ->
     )
 
     $("#gemma_compute").click(() =>
+        $("#static_progress_bar_container").modal()
         url = "/marker_regression"
         $('input[name=method]').val("gemma")
         $('input[name=mapping_display_all]').val($('input[name=display_all_gemma]'))
@@ -164,11 +166,11 @@ $ ->
                 alert("Sorry, an error occurred")
                 console.log(xhr)
                 clearInterval(this.my_timer)
-                $('#progress_bar_container').modal('hide')
+                $('#static_progress_bar_container').modal('hide')
                 $("body").html("We got an error.")        
             success: (data) =>
                 clearInterval(this.my_timer)
-                $('#progress_bar_container').modal('hide')
+                $('#static_progress_bar_container').modal('hide')
                 $("body").html(data)
         )
         console.log("settingInterval")
diff --git a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js
index dbc26e3b..ee930c80 100755
--- a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js
@@ -132,6 +132,7 @@
     });
     $("#plink_compute").click(function() {
       var form_data, url;
+      $("#static_progress_bar_container").modal();
       url = "/marker_regression";
       $('input[name=method]').val("plink");
       $('input[name=mapping_display_all]').val($('input[name=display_all_plink]'));
@@ -147,12 +148,12 @@
           alert("Sorry, an error occurred");
           console.log(xhr);
           clearInterval(_this.my_timer);
-          $('#progress_bar_container').modal('hide');
+          $('#static_progress_bar_container').modal('hide');
           return $("body").html("We got an error.");
         },
         success: function(data) {
           clearInterval(_this.my_timer);
-          $('#progress_bar_container').modal('hide');
+          $('#static_progress_bar_container').modal('hide');
           return $("body").html(data);
         }
       });
@@ -162,6 +163,7 @@
     });
     $("#gemma_compute").click(function() {
       var form_data, url;
+      $("#static_progress_bar_container").modal();
       url = "/marker_regression";
       $('input[name=method]').val("gemma");
       $('input[name=mapping_display_all]').val($('input[name=display_all_gemma]'));
@@ -177,12 +179,12 @@
           alert("Sorry, an error occurred");
           console.log(xhr);
           clearInterval(_this.my_timer);
-          $('#progress_bar_container').modal('hide');
+          $('#static_progress_bar_container').modal('hide');
           return $("body").html("We got an error.");
         },
         success: function(data) {
           clearInterval(_this.my_timer);
-          $('#progress_bar_container').modal('hide');
+          $('#static_progress_bar_container').modal('hide');
           return $("body").html(data);
         }
       });
diff --git a/wqflask/wqflask/static/new/js_external/d3-tip.min.js b/wqflask/wqflask/static/new/js_external/d3-tip.min.js
new file mode 100644
index 00000000..d881b1dc
--- /dev/null
+++ b/wqflask/wqflask/static/new/js_external/d3-tip.min.js
@@ -0,0 +1 @@
+!function(t,e){"function"==typeof define&&define.amd?define(["d3"],e):t.d3.tip=e(t.d3)}(this,function(t){return function(){function e(t){w=m(t),T=w.createSVGPoint(),document.body.appendChild(v)}function n(){return"n"}function r(){return[0,0]}function o(){return" "}function l(){var t=d();return{top:t.n.y-v.offsetHeight,left:t.n.x-v.offsetWidth/2}}function s(){var t=d();return{top:t.s.y,left:t.s.x-v.offsetWidth/2}}function f(){var t=d();return{top:t.e.y-v.offsetHeight/2,left:t.e.x}}function i(){var t=d();return{top:t.w.y-v.offsetHeight/2,left:t.w.x-v.offsetWidth}}function u(){var t=d();return{top:t.nw.y-v.offsetHeight,left:t.nw.x-v.offsetWidth}}function a(){var t=d();return{top:t.ne.y-v.offsetHeight,left:t.ne.x}}function c(){var t=d();return{top:t.sw.y,left:t.sw.x-v.offsetWidth}}function p(){var t=d();return{top:t.se.y,left:t.e.x}}function y(){var e=t.select(document.createElement("div"));return e.style({position:"absolute",top:0,opacity:0,"pointer-events":"none","box-sizing":"border-box"}),e.node()}function m(t){return t=t.node(),"svg"==t.tagName.toLowerCase()?t:t.ownerSVGElement}function d(){var e=b||t.event.target,n={},r=e.getScreenCTM(),o=e.getBBox(),l=o.width,s=o.height,f=o.x,i=o.y;return T.x=f,T.y=i,n.nw=T.matrixTransform(r),T.x+=l,n.ne=T.matrixTransform(r),T.y+=s,n.se=T.matrixTransform(r),T.x-=l,n.sw=T.matrixTransform(r),T.y-=s/2,n.w=T.matrixTransform(r),T.x+=l,n.e=T.matrixTransform(r),T.x-=l/2,T.y-=s/2,n.n=T.matrixTransform(r),T.y+=s,n.s=T.matrixTransform(r),n}var g=n,h=r,x=o,v=y(),w=null,T=null,b=null;e.show=function(){var n=Array.prototype.slice.call(arguments);n[n.length-1]instanceof SVGElement&&(b=n.pop());var r,o=x.apply(this,n),l=h.apply(this,n),s=g.apply(this,n),f=t.select(v),i=H.length,u=document.documentElement.scrollTop||document.body.scrollTop,a=document.documentElement.scrollLeft||document.body.scrollLeft;for(f.html(o).style({opacity:1,"pointer-events":"all"});i--;)f.classed(H[i],!1);return r=E.get(s).apply(this),f.classed(s,!0).style({top:r.top+l[0]+u+"px",left:r.left+l[1]+a+"px"}),e},e.hide=function(){return nodel=t.select(v),nodel.style({opacity:0,"pointer-events":"none"}),e},e.attr=function(n){if(arguments.length<2&&"string"==typeof n)return t.select(v).attr(n);var r=Array.prototype.slice.call(arguments);return t.selection.prototype.attr.apply(t.select(v),r),e},e.style=function(n){if(arguments.length<2&&"string"==typeof n)return t.select(v).style(n);var r=Array.prototype.slice.call(arguments);return t.selection.prototype.style.apply(t.select(v),r),e},e.direction=function(n){return arguments.length?(g=null==n?n:t.functor(n),e):g},e.offset=function(n){return arguments.length?(h=null==n?n:t.functor(n),e):h},e.html=function(n){return arguments.length?(x=null==n?n:t.functor(n),e):x};var E=t.map({n:l,s:s,e:f,w:i,nw:u,ne:a,sw:c,se:p}),H=E.keys();return e}});
\ No newline at end of file
diff --git a/wqflask/wqflask/templates/correlation_page.html b/wqflask/wqflask/templates/correlation_page.html
index e4819d61..61d17a22 100755
--- a/wqflask/wqflask/templates/correlation_page.html
+++ b/wqflask/wqflask/templates/correlation_page.html
@@ -25,6 +25,7 @@
             <table id="corr_results" class="table table-hover table-striped table-bordered">
                 <thead>
                     <tr>
+                    {% if dataset.type == 'ProbeSet' %}
                         <th>Trait</th>
                         <th>Symbol</th>
                         <th>Description</th>
@@ -47,11 +48,27 @@
                         <th>Tissue rho</th>
                         <th>Tissue p(rho)</th>
                         {% endif %}
+                    {% elif dataset.type == "Publish" %}
+                        <th>Record ID</th>
+                        <th>Phenotype</th>
+                        <th>Authors</th>
+                        <th>Year</th>
+                        {% if corr_method == 'pearson' %}
+                        <th>Sample r</th>
+                        <th>N Cases</th>
+                        <th>Sample p(r)</th>
+                        {% else %}
+                        <th>Sample rho</th>
+                        <th>N Cases</th>
+                        <th>Sample p(rho)</th>
+                        {% endif %}
+                    {% endif %}
                     </tr>
                 </thead>
                 <tbody>
                 {% for trait in correlation_results %}
                     <tr>
+                    {% if dataset.type == 'ProbeSet' %}
                         <td><a href="/show_trait?trait_id={{trait.name}}&amp;dataset={{trait.dataset.name}}">{{ trait.name }}</a></td>
                         <td>{{ trait.symbol }}</td>
                         <td>{{ trait.description }} <br><br> <b>Aliases</b>: {{ trait.alias }}</td>
@@ -65,6 +82,15 @@
                         <td>{{'%0.3f'|format(trait.lit_corr)}}</td>
                         <td>{{'%0.3f'|format(trait.tissue_corr)}}</td>
                         <td>{{'%0.3e'|format(trait.tissue_pvalue)}}</td>
+                    {% elif dataset.type == "Publish" %}
+                        <td><a href="/show_trait?trait_id={{trait.name}}&amp;dataset={{trait.dataset.name}}">{{ trait.name }}</a></td>
+                        <td>{{ trait.post_publication_description }}</td>
+                        <td>{{ trait.authors }}</td>
+                        <td>{{ trait.year }}</td>
+                        <td><a target="_blank" href="corr_scatter_plot?dataset_1={{dataset.name}}&dataset_2={{trait.dataset.name}}&trait_1={{this_trait.name}}&trait_2={{trait.name}}">{{'%0.3f'|format(trait.sample_r)}}</a></td>
+                        <td>{{ trait.num_overlap }}</td>
+                        <td>{{'%0.3e'|format(trait.sample_p)}}</td>
+                    {% endif %}
                     </tr>
                 {% endfor %}
                 </tbody>
diff --git a/wqflask/wqflask/templates/interval_mapping.html b/wqflask/wqflask/templates/interval_mapping.html
index e4b93bf4..e3c164ea 100755
--- a/wqflask/wqflask/templates/interval_mapping.html
+++ b/wqflask/wqflask/templates/interval_mapping.html
@@ -5,6 +5,8 @@
     <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/css/jquery.dataTables.css" />

     <link rel="stylesheet" type="text/css" href="/static/packages/DT_bootstrap/DT_bootstrap.css" />

     <link rel="stylesheet" type="text/css" href="/static/packages/TableTools/media/css/TableTools.css" />

+    <link rel="stylesheet" type="text/css" href="/static/new/css/panelutil.css" />

+    <link rel="stylesheet" type="text/css" href="/static/new/css/d3-tip.min.css" />

 {% endblock %}

 {% block content %} <!-- Start of body -->

 

@@ -17,7 +19,7 @@
                 Whole Genome Mapping

             </h2>

         </div>

-        <div id="interval_map" class="interval_map">

+        <div id="topchart">

             

         </div>

         <div>

@@ -69,7 +71,10 @@
 <!--        <script language="javascript" type="text/javascript" src="/static/packages/jqplot/excanvas.js"></script>-->

     <![endif]-->

     <script language="javascript" type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>

-    <script language="javascript" type="text/javascript" src="/static/new/javascript/interval_mapping.js"></script>

+    <script language="javascript" type="text/javascript" src="/static/new/js_external/d3-tip.min.js"></script>

+    <script language="javascript" type="text/javascript" src="/static/new/javascript/panelutil.js"></script>

+    <script language="javascript" type="text/javascript" src="/static/new/javascript/lod_chart.js"></script>

+    <script language="javascript" type="text/javascript" src="/static/new/javascript/interval_map_new.js"></script>

     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.js"></script>

     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script>

     <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/dataTables.scientific.js"></script>

diff --git a/wqflask/wqflask/templates/show_trait_details.html b/wqflask/wqflask/templates/show_trait_details.html
index b57c3c21..88fd74d9 100755
--- a/wqflask/wqflask/templates/show_trait_details.html
+++ b/wqflask/wqflask/templates/show_trait_details.html
@@ -29,7 +29,7 @@
 
 
 
-<div class="btn-toolbar">
+<!--<div class="btn-toolbar">
     <div class="btn-group">
         <button class="btn btn-primary" title="Add to collection">
             <i class="icon-plus-sign icon-white"></i> Add
@@ -63,4 +63,4 @@
         </button>
 
     </div>
-</div>
+</div>-->
diff --git a/wqflask/wqflask/templates/show_trait_mapping_tools.html b/wqflask/wqflask/templates/show_trait_mapping_tools.html
index f380988e..a2c7564f 100755
--- a/wqflask/wqflask/templates/show_trait_mapping_tools.html
+++ b/wqflask/wqflask/templates/show_trait_mapping_tools.html
@@ -7,7 +7,7 @@
                     <a href="#interval_mapping" data-toggle="tab">Interval Mapping</a>
                 </li>
                 <li>
-                    <a href="#marker_regression" data-toggle="tab">Marker Regression</a>
+                    <a href="#pylmm" data-toggle="tab">pyLMM</a>
                 </li>
                 <li>
                     <a href="#plink" data-toggle="tab">PLINK</a>
@@ -112,7 +112,7 @@
                     </div>
                 </div>
                 
-                <div class="tab-pane" id="marker_regression">
+                <div class="tab-pane" id="pylmm">
                     <div class="control-group" id="display_all_div">
                         <label class="control-label">Display all</label>
                         <div class="controls">                      
diff --git a/wqflask/wqflask/templates/show_trait_progress_bar.html b/wqflask/wqflask/templates/show_trait_progress_bar.html
index 0c3f0e6e..aebf64a4 100755
--- a/wqflask/wqflask/templates/show_trait_progress_bar.html
+++ b/wqflask/wqflask/templates/show_trait_progress_bar.html
@@ -9,4 +9,17 @@
         <div id="time_remaining">
         </div>
     </div>
+</div>
+
+<div id="static_progress_bar_container" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="progress_bar" aria-hidden="true">
+  <div class="modal-header">
+    <h3 id="progress_bar">Loading... (Estimated time ~10-15m)</h3>
+  </div>
+    <div class="modal-body">
+        <div class="progress progress-striped active">
+            <div id="marker_regression_progress" class="bar" style="width: 100%"></div>
+        </div>
+        <div id="time_remaining">
+        </div>
+    </div>
 </div>
\ No newline at end of file
diff --git a/wqflask/wqflask/templates/show_trait_statistics_new.html b/wqflask/wqflask/templates/show_trait_statistics_new.html
index 3a68d8c5..8f6f07ce 100755
--- a/wqflask/wqflask/templates/show_trait_statistics_new.html
+++ b/wqflask/wqflask/templates/show_trait_statistics_new.html
@@ -10,9 +10,9 @@
                 <li>
                     <a href="#bar_chart_tab" data-toggle="tab">Bar Chart</a>
                 </li>
-                <li>
+<!--                <li>
                     <a href="#box_plot_tab" data-toggle="tab">Box Plot</a>
-                </li>
+                </li>-->
             </ul>
             <div class="tab-content">
                 <div class="tab-pane active" id="histogram_tab">
@@ -67,7 +67,7 @@
                         <div id="bar_chart"></div>
                     </div>
                 </div>
-                <div class="tab-pane" id="box_plot_tab">
+<!--                <div class="tab-pane" id="box_plot_tab">
                     {% if sample_groups|length > 1 %}
                     <select class="box_plot_samples_group">
                         {% for group, pretty_group in sample_group_types.items() %}
@@ -79,7 +79,7 @@
                     <div id="box_plot_container">
                         <div id="box_plot"></div>
                     </div>
-                </div>
+                </div>-->
             </div>
         </div>
     </div>
diff --git a/wqflask/wqflask/user_manager.py b/wqflask/wqflask/user_manager.py
index e4fb60e4..2ee5bbca 100755
--- a/wqflask/wqflask/user_manager.py
+++ b/wqflask/wqflask/user_manager.py
@@ -131,7 +131,10 @@ class UserSession(object):
     @property
     def user_id(self):
         """Shortcut to the user_id"""
-        return self.record['user_id']
+        if 'user_id' in self.record:
+            return self.record['user_id']
+        else:
+            return ''
 
     @property
     def user_ob(self):
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 20516205..7bde1006 100755
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -279,7 +279,7 @@ def interval_mapping_page():
         if key in wanted or key.startswith(('value:')):
             start_vars[key] = value
 
-    version = "v7"
+    version = "v11"
     key = "interval_mapping:{}:".format(version) + json.dumps(start_vars, sort_keys=True)
     print("key is:", pf(key))
     with Bench("Loading cache"):