diff options
author | Alexander Kabui | 2021-01-29 14:54:24 +0300 |
---|---|---|
committer | Alexander Kabui | 2021-01-29 14:54:24 +0300 |
commit | de173353d95275855831fde5c1377ddce721fd34 (patch) | |
tree | ff7c46a25a32a8d9e0b37a679184d9ccec1286a8 /wqflask/wqflask | |
parent | a6ae88d773db27394aa7120ce2c552bff8f9c857 (diff) | |
parent | 9f12da2623c3ca9156300c825fe0f86ad08bb76e (diff) | |
download | genenetwork2-de173353d95275855831fde5c1377ddce721fd34.tar.gz |
Merge branch 'testing' of https://github.com/genenetwork/genenetwork2 into replace-bootstrap
Diffstat (limited to 'wqflask/wqflask')
34 files changed, 809 insertions, 544 deletions
diff --git a/wqflask/wqflask/correlation/correlation_functions.py b/wqflask/wqflask/correlation/correlation_functions.py index b883e361..fd7691d4 100644 --- a/wqflask/wqflask/correlation/correlation_functions.py +++ b/wqflask/wqflask/correlation/correlation_functions.py @@ -71,34 +71,6 @@ def cal_zero_order_corr_for_tiss (primaryValue=[], targetValue=[], method='pears return corr_result -########################################################################### -#Input: cursor, symbolList (list), dataIdDict(Dict) -#output: symbolValuepairDict (dictionary):one dictionary of Symbol and Value Pair, -# key is symbol, value is one list of expression values of one probeSet; -#function: get one dictionary whose key is gene symbol and value is tissue expression data (list type). -#Attention! All keys are lower case! -########################################################################### -def get_symbol_value_pairs(tissue_data): - id_list = [tissue_data[symbol.lower()].data_id for item in tissue_data] - - symbol_value_pairs = {} - value_list=[] - - query = """SELECT value, id - FROM TissueProbeSetData - WHERE Id IN {}""".format(create_in_clause(id_list)) - - try : - results = g.db.execute(query).fetchall() - for result in results: - value_list.append(result.value) - symbol_value_pairs[symbol] = value_list - except: - symbol_value_pairs[symbol] = None - - return symbol_value_pairs - - ######################################################################################################## #input: cursor, symbolList (list), dataIdDict(Dict): key is symbol #output: SymbolValuePairDict(dictionary):one dictionary of Symbol and Value Pair. diff --git a/wqflask/wqflask/correlation/show_corr_results.py b/wqflask/wqflask/correlation/show_corr_results.py index 7d3b9b9f..fb4dc4f4 100644 --- a/wqflask/wqflask/correlation/show_corr_results.py +++ b/wqflask/wqflask/correlation/show_corr_results.py @@ -71,7 +71,6 @@ class CorrelationResults(object): assert('corr_sample_method' in start_vars) assert('corr_samples_group' in start_vars) assert('corr_dataset' in start_vars) - #assert('min_expr' in start_vars) assert('corr_return_results' in start_vars) if 'loc_chr' in start_vars: assert('min_loc_mb' in start_vars) @@ -87,8 +86,6 @@ class CorrelationResults(object): else: helper_functions.get_species_dataset_trait(self, start_vars) - #self.dataset.group.read_genotype_file() - corr_samples_group = start_vars['corr_samples_group'] self.sample_data = {} @@ -102,11 +99,12 @@ class CorrelationResults(object): 'min_loc_mb' in start_vars and 'max_loc_mb' in start_vars): + self.location_type = get_string(start_vars, 'location_type') self.location_chr = get_string(start_vars, 'loc_chr') self.min_location_mb = get_int(start_vars, 'min_loc_mb') self.max_location_mb = get_int(start_vars, 'max_loc_mb') else: - self.location_chr = self.min_location_mb = self.max_location_mb = None + self.location_type = self.location_chr = self.min_location_mb = self.max_location_mb = None self.get_formatted_corr_type() self.return_number = int(start_vars['corr_return_results']) @@ -174,38 +172,46 @@ class CorrelationResults(object): self.correlation_data = collections.OrderedDict(sorted(list(self.correlation_data.items()), key=lambda t: -abs(t[1][0]))) - if self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Geno": - #ZS: Convert min/max chromosome to an int for the location range option - range_chr_as_int = None - for order_id, chr_info in list(self.dataset.species.chromosomes.chromosomes.items()): - if 'loc_chr' in start_vars: - if chr_info.name == self.location_chr: - range_chr_as_int = order_id + + #ZS: Convert min/max chromosome to an int for the location range option + range_chr_as_int = None + for order_id, chr_info in list(self.dataset.species.chromosomes.chromosomes.items()): + if 'loc_chr' in start_vars: + if chr_info.name == self.location_chr: + range_chr_as_int = order_id for _trait_counter, trait in enumerate(list(self.correlation_data.keys())[:self.return_number]): trait_object = create_trait(dataset=self.target_dataset, name=trait, get_qtl_info=True, get_sample_info=False) if not trait_object: continue - if self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Geno": - #ZS: Convert trait chromosome to an int for the location range option - chr_as_int = 0 - for order_id, chr_info in list(self.dataset.species.chromosomes.chromosomes.items()): + chr_as_int = 0 + for order_id, chr_info in list(self.dataset.species.chromosomes.chromosomes.items()): + if self.location_type == "highest_lod": + if chr_info.name == trait_object.locus_chr: + chr_as_int = order_id + else: if chr_info.name == trait_object.chr: chr_as_int = order_id if (float(self.correlation_data[trait][0]) >= self.p_range_lower and float(self.correlation_data[trait][0]) <= self.p_range_upper): - if self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Geno": - + if (self.target_dataset.type == "ProbeSet" or self.target_dataset.type == "Publish") and bool(trait_object.mean): if (self.min_expr != None) and (float(trait_object.mean) < self.min_expr): continue - elif range_chr_as_int != None and (chr_as_int != range_chr_as_int): + + if range_chr_as_int != None and (chr_as_int != range_chr_as_int): + continue + if self.location_type == "highest_lod": + if (self.min_location_mb != None) and (float(trait_object.locus_mb) < float(self.min_location_mb)): + continue + if (self.max_location_mb != None) and (float(trait_object.locus_mb) > float(self.max_location_mb)): continue - elif (self.min_location_mb != None) and (float(trait_object.mb) < float(self.min_location_mb)): + else: + if (self.min_location_mb != None) and (float(trait_object.mb) < float(self.min_location_mb)): continue - elif (self.max_location_mb != None) and (float(trait_object.mb) > float(self.max_location_mb)): + if (self.max_location_mb != None) and (float(trait_object.mb) > float(self.max_location_mb)): continue (trait_object.sample_r, @@ -454,13 +460,13 @@ class CorrelationResults(object): if not excluded_samples: excluded_samples = () + sample_val_dict = json.loads(start_vars['sample_vals']) for sample in sample_names: if sample not in excluded_samples: - # print("Looking for",sample,"in",start_vars) - value = start_vars.get('value:' + sample) - if value: - if not value.strip().lower() == 'x': - self.sample_data[str(sample)] = float(value) + value = sample_val_dict[sample] + if not value.strip().lower() == 'x': + self.sample_data[str(sample)] = float(value) + def do_bicor(this_trait_vals, target_trait_vals): r_library = ro.r["library"] # Map the library function @@ -519,6 +525,7 @@ def generate_corr_json(corr_results, this_trait, dataset, target_dataset, for_ap elif target_dataset.type == "Publish": results_dict['abbreviation_display'] = "N/A" results_dict['description'] = "N/A" + results_dict['mean'] = "N/A" results_dict['authors_display'] = "N/A" results_dict['additive'] = "N/A" if for_api: @@ -532,6 +539,8 @@ def generate_corr_json(corr_results, this_trait, dataset, target_dataset, for_ap results_dict['abbreviation_display'] = trait.abbreviation if bool(trait.description_display): results_dict['description'] = trait.description_display + if bool(trait.mean): + results_dict['mean'] = f"{float(trait.mean):.3f}" if bool(trait.authors): authors_list = trait.authors.split(',') if len(authors_list) > 6: @@ -605,6 +614,7 @@ def get_header_fields(data_type, corr_method): 'Record', 'Abbreviation', 'Description', + 'Mean', 'Authors', 'Year', 'Sample rho', @@ -618,6 +628,7 @@ def get_header_fields(data_type, corr_method): 'Record', 'Abbreviation', 'Description', + 'Mean', 'Authors', 'Year', 'Sample r', diff --git a/wqflask/wqflask/gsearch.py b/wqflask/wqflask/gsearch.py index 9e46c0c5..2b8d4bc1 100644 --- a/wqflask/wqflask/gsearch.py +++ b/wqflask/wqflask/gsearch.py @@ -1,4 +1,6 @@ import json +import datetime as dt +from types import SimpleNamespace from flask import Flask, g from base.data_set import create_dataset @@ -9,8 +11,9 @@ from base import webqtlConfig from utility import hmac -from utility.type_checking import is_float, is_int, is_str, get_float, get_int, get_string from utility.benchmark import Bench +from utility.authentication_tools import check_resource_availability +from utility.type_checking import is_float, is_int, is_str, get_float, get_int, get_string from utility.logger import getLogger logger = getLogger(__name__) @@ -42,15 +45,19 @@ class GSearch(object): ProbeSetXRef.LRS AS lrs, ProbeSetXRef.`Locus` AS locus, ProbeSetXRef.`pValue` AS pvalue, - ProbeSetXRef.`additive` AS additive - FROM Species, InbredSet, ProbeSetXRef, ProbeSet, ProbeFreeze, ProbeSetFreeze, Tissue - WHERE InbredSet.`SpeciesId`=Species.`Id` - AND ProbeFreeze.InbredSetId=InbredSet.`Id` - AND ProbeFreeze.`TissueId`=Tissue.`Id` - AND ProbeSetFreeze.ProbeFreezeId=ProbeFreeze.Id - AND ( MATCH (ProbeSet.Name,ProbeSet.description,ProbeSet.symbol,alias,GenbankId, UniGeneId, Probe_Target_Description) AGAINST ('%s' IN BOOLEAN MODE) ) - AND ProbeSet.Id = ProbeSetXRef.ProbeSetId - AND ProbeSetXRef.ProbeSetFreezeId=ProbeSetFreeze.Id + ProbeSetXRef.`additive` AS additive, + ProbeSetFreeze.Id AS probesetfreeze_id, + Geno.Chr as geno_chr, + Geno.Mb as geno_mb + FROM Species + INNER JOIN InbredSet ON InbredSet.`SpeciesId`=Species.`Id` + INNER JOIN ProbeFreeze ON ProbeFreeze.InbredSetId=InbredSet.`Id` + INNER JOIN Tissue ON ProbeFreeze.`TissueId`=Tissue.`Id` + INNER JOIN ProbeSetFreeze ON ProbeSetFreeze.ProbeFreezeId=ProbeFreeze.Id + INNER JOIN ProbeSetXRef ON ProbeSetXRef.ProbeSetFreezeId=ProbeSetFreeze.Id + INNER JOIN ProbeSet ON ProbeSet.Id = ProbeSetXRef.ProbeSetId + LEFT JOIN Geno ON ProbeSetXRef.Locus = Geno.Name AND Geno.SpeciesId = Species.Id + WHERE ( MATCH (ProbeSet.Name,ProbeSet.description,ProbeSet.symbol,ProbeSet.alias,ProbeSet.GenbankId, ProbeSet.UniGeneId, ProbeSet.Probe_Target_Description) AGAINST ('%s' IN BOOLEAN MODE) ) AND ProbeSetFreeze.confidentiality < 1 AND ProbeSetFreeze.public > 0 ORDER BY species_name, inbredset_name, tissue_name, probesetfreeze_name, probeset_name @@ -61,6 +68,7 @@ class GSearch(object): re = g.db.execute(sql).fetchall() trait_list = [] + dataset_to_permissions = {} with Bench("Creating trait objects"): for i, line in enumerate(re): this_trait = {} @@ -90,16 +98,22 @@ class GSearch(object): this_trait['additive'] = "N/A" if line[14] != "" and line[14] != None: this_trait['additive'] = '%.3f' % line[14] - - #dataset = create_dataset(line[3], "ProbeSet", get_samplelist=False) - #trait_id = line[4] - #with Bench("Building trait object"): - trait_ob = create_trait(dataset_name=this_trait['dataset'], name=this_trait['name'], get_qtl_info=True, get_sample_info=False) - if not trait_ob: + this_trait['dataset_id'] = line[15] + this_trait['locus_chr'] = line[16] + this_trait['locus_mb'] = line[17] + + dataset_ob = SimpleNamespace(id=this_trait["dataset_id"], type="ProbeSet",species=this_trait["species"]) + if dataset_ob.id not in dataset_to_permissions: + permissions = check_resource_availability(dataset_ob) + dataset_to_permissions[dataset_ob.id] = permissions + else: + pemissions = dataset_to_permissions[dataset_ob.id] + if "view" not in permissions['data']: continue + max_lrs_text = "N/A" - if trait_ob.locus_chr != "" and trait_ob.locus_mb != "": - max_lrs_text = "Chr" + str(trait_ob.locus_chr) + ": " + str(trait_ob.locus_mb) + if this_trait['locus_chr'] != None and this_trait['locus_mb'] != None: + max_lrs_text = "Chr" + str(this_trait['locus_chr']) + ": " + str(this_trait['locus_mb']) this_trait['max_lrs_text'] = max_lrs_text trait_list.append(this_trait) diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py index 08c2d750..4df56190 100644 --- a/wqflask/wqflask/marker_regression/display_mapping_results.py +++ b/wqflask/wqflask/marker_regression/display_mapping_results.py @@ -270,8 +270,9 @@ class DisplayMappingResults(object): # Needing for form submission when doing single chr # mapping or remapping after changing options - self.samples = start_vars['samples'] - self.vals = start_vars['vals'] + self.sample_vals = start_vars['sample_vals'] + self.sample_vals_dict = json.loads(self.sample_vals) + self.transform = start_vars['transform'] self.mapping_method = start_vars['mapping_method'] self.mapping_results_path = start_vars['mapping_results_path'] @@ -492,11 +493,10 @@ class DisplayMappingResults(object): ## count the amount of individuals to be plotted, and increase self.graphHeight if self.haplotypeAnalystChecked and self.selectedChr > -1: thisTrait = self.this_trait - _strains, _vals, _vars, _aliases = thisTrait.export_informative() smd=[] - for ii, _val in enumerate(self.vals): - if _val != "x": - temp = GeneralObject(name=self.samples[ii], value=float(_val)) + for sample in self.sample_vals_dict.keys(): + if self.sample_vals_dict[sample] != "x": + temp = GeneralObject(name=sample, value=float(self.sample_vals_dict[sample])) smd.append(temp) else: continue @@ -636,7 +636,7 @@ class DisplayMappingResults(object): btminfo.append(HtmlGenWrapper.create_br_tag()) btminfo.append('Mapping using genotype data as a trait will result in infinity LRS at one locus. In order to display the result properly, all LRSs higher than 100 are capped at 100.') - def plotIntMapping(self, canvas, offset= (80, 120, 20, 100), zoom = 1, startMb = None, endMb = None, showLocusForm = ""): + def plotIntMapping(self, canvas, offset= (80, 120, 90, 100), zoom = 1, startMb = None, endMb = None, showLocusForm = ""): im_drawer = ImageDraw.Draw(canvas) #calculating margins xLeftOffset, xRightOffset, yTopOffset, yBottomOffset = offset @@ -644,10 +644,11 @@ class DisplayMappingResults(object): yTopOffset = max(90, yTopOffset) else: if self.legendChecked: + yTopOffset += 10 if self.covariates != "" and self.controlLocus and self.doControl != "false": - yTopOffset = max(120, yTopOffset) - else: - yTopOffset = max(100, yTopOffset) + yTopOffset += 20 + if len(self.transform) > 0: + yTopOffset += 5 else: pass @@ -858,14 +859,16 @@ class DisplayMappingResults(object): text='%2.1f'%item, font=bootScaleFont, fill=BLACK) if self.legendChecked: - startPosY = 30 - nCol = 2 + if hasattr(self.traitList[0], 'chr') and hasattr(self.traitList[0], 'mb'): + startPosY = 30 + else: + startPosY = 15 smallLabelFont = ImageFont.truetype(font=TREBUC_FILE, size=12*fontZoom) - leftOffset = xLeftOffset+(nCol-1)*200 + leftOffset = canvas.size[0] - xRightOffset - 190 im_drawer.rectangle( xy=((leftOffset, startPosY-6), (leftOffset+12, startPosY+6)), fill=YELLOW, outline=BLACK) - im_drawer.text(xy=(leftOffset+ 20, startPosY+TEXT_Y_DISPLACEMENT), + im_drawer.text(xy=(canvas.size[0] - xRightOffset - 170, startPosY+TEXT_Y_DISPLACEMENT), text='Frequency of the Peak LRS', font=smallLabelFont, fill=BLACK) @@ -941,28 +944,6 @@ class DisplayMappingResults(object): draw_open_polygon(canvas, xy=traitPixel, outline=BLACK, fill=self.TRANSCRIPT_LOCATION_COLOR) - if self.legendChecked: - startPosY = 15 - nCol = 2 - smallLabelFont = ImageFont.truetype(font=TREBUC_FILE, size=12*fontZoom) - if self.manhattan_plot: - leftOffset = xLeftOffset - else: - leftOffset = xLeftOffset+(nCol-1)*200*fontZoom - draw_open_polygon( - canvas, - xy=( - (leftOffset+7, startPosY-7), - (leftOffset, startPosY+7), - (leftOffset+14, startPosY+7)), - outline=BLACK, fill=self.TRANSCRIPT_LOCATION_COLOR - ) - TEXT_Y_DISPLACEMENT = -8 - im_drawer.text( - text="Sequence Site", - xy=(leftOffset+15, startPosY+TEXT_Y_DISPLACEMENT), font=smallLabelFont, - fill=self.TOP_RIGHT_INFO_COLOR) - def drawSNPTrackNew(self, canvas, offset= (40, 120, 80, 10), zoom = 1, startMb = None, endMb = None): im_drawer = ImageDraw.Draw(canvas) if self.plotScale != 'physic' or self.selectedChr == -1 or not self.diffCol: @@ -1059,17 +1040,38 @@ class DisplayMappingResults(object): labelFont=ImageFont.truetype(font=TREBUC_FILE, size=12*fontZoom) startPosY = 15 stepPosY = 12*fontZoom + + startPosX = canvas.size[0] - xRightOffset - 415 + if hasattr(self.traitList[0], 'chr') and hasattr(self.traitList[0], 'mb'): + startPosY = 15 + nCol = 2 + smallLabelFont = ImageFont.truetype(font=TREBUC_FILE, size=12*fontZoom) + + leftOffset = canvas.size[0] - xRightOffset - 190 + draw_open_polygon( + canvas, + xy=( + (leftOffset + 6, startPosY-7), + (leftOffset - 1, startPosY+7), + (leftOffset + 13, startPosY+7)), + outline=BLACK, fill=self.TRANSCRIPT_LOCATION_COLOR + ) + TEXT_Y_DISPLACEMENT = -8 + im_drawer.text( + text="Sequence Site", + xy=(leftOffset + 20, startPosY+TEXT_Y_DISPLACEMENT), font=smallLabelFont, + fill=self.TOP_RIGHT_INFO_COLOR) + if self.manhattan_plot != True: im_drawer.line( - xy=((xLeftOffset, startPosY), (xLeftOffset+32, startPosY)), + xy=((startPosX, startPosY), (startPosX+32, startPosY)), fill=self.LRS_COLOR, width=2) im_drawer.text( - text=self.LRS_LOD, xy=(xLeftOffset+40, startPosY+TEXT_Y_DISPLACEMENT), + text=self.LRS_LOD, xy=(startPosX+40, startPosY+TEXT_Y_DISPLACEMENT), font=labelFont, fill=BLACK) startPosY += stepPosY if self.additiveChecked: - startPosX = xLeftOffset im_drawer.line( xy=((startPosX, startPosY), (startPosX+17, startPosY)), fill=self.ADDITIVE_COLOR_POSITIVE, width=2) @@ -1079,10 +1081,9 @@ class DisplayMappingResults(object): im_drawer.text( text='Additive Effect', xy=(startPosX+40, startPosY+TEXT_Y_DISPLACEMENT), font=labelFont, fill=BLACK) + startPosY += stepPosY if self.genotype.type == 'intercross' and self.dominanceChecked: - startPosX = xLeftOffset - startPosY += stepPosY im_drawer.line( xy=((startPosX, startPosY), (startPosX+17, startPosY)), fill=self.DOMINANCE_COLOR_POSITIVE, width=4) @@ -1092,45 +1093,47 @@ class DisplayMappingResults(object): im_drawer.text( text='Dominance Effect', xy=(startPosX+42, startPosY+5), font=labelFont, fill=BLACK) + startPosY += stepPosY if self.haplotypeAnalystChecked: - startPosY += stepPosY - startPosX = xLeftOffset im_drawer.line( - xy=((startPosX, startPosY), (startPosX+17, startPosY)), + xy=((startPosX-34, startPosY), (startPosX-17, startPosY)), fill=self.HAPLOTYPE_POSITIVE, width=4) im_drawer.line( - xy=((startPosX+18, startPosY), (startPosX+35, startPosY)), + xy=((startPosX-17, startPosY), (startPosX, startPosY)), fill=self.HAPLOTYPE_NEGATIVE, width=4) im_drawer.line( - xy=((startPosX+36, startPosY), (startPosX+53, startPosY)), + xy=((startPosX, startPosY), (startPosX+17, startPosY)), fill=self.HAPLOTYPE_HETEROZYGOUS, width=4) im_drawer.line( - xy=((startPosX+54, startPosY), (startPosX+67, startPosY)), + xy=((startPosX+17, startPosY), (startPosX+34, startPosY)), fill=self.HAPLOTYPE_RECOMBINATION, width=4) im_drawer.text( text='Haplotypes (Pat, Mat, Het, Unk)', - xy=(startPosX+76, startPosY+5), font=labelFont, fill=BLACK) + xy=(startPosX+41, startPosY+TEXT_Y_DISPLACEMENT), font=labelFont, fill=BLACK) + startPosY += stepPosY if self.permChecked and self.nperm > 0: - startPosY += stepPosY - startPosX = xLeftOffset + thisStartX = startPosX + if self.multipleInterval and not self.bootChecked: + thisStartX = canvas.size[0] - xRightOffset - 205 im_drawer.line( - xy=((startPosX, startPosY), ( startPosX + 32, startPosY)), + xy=((thisStartX, startPosY), ( startPosX + 32, startPosY)), fill=self.SIGNIFICANT_COLOR, width=self.SIGNIFICANT_WIDTH) im_drawer.line( - xy=((startPosX, startPosY + stepPosY), ( startPosX + 32, startPosY + stepPosY)), + xy=((thisStartX, startPosY + stepPosY), ( startPosX + 32, startPosY + stepPosY)), fill=self.SUGGESTIVE_COLOR, width=self.SUGGESTIVE_WIDTH) im_drawer.text( text='Significant %s = %2.2f' % (self.LRS_LOD, self.significant), - xy=(xLeftOffset+42, startPosY+TEXT_Y_DISPLACEMENT), font=labelFont, fill=BLACK) + xy=(thisStartX+40, startPosY+TEXT_Y_DISPLACEMENT), font=labelFont, fill=BLACK) im_drawer.text( text='Suggestive %s = %2.2f' % (self.LRS_LOD, self.suggestive), - xy=(xLeftOffset+42, startPosY + TEXT_Y_DISPLACEMENT +stepPosY), font=labelFont, + xy=(thisStartX+40, startPosY + TEXT_Y_DISPLACEMENT +stepPosY), font=labelFont, fill=BLACK) labelFont = ImageFont.truetype(font=VERDANA_FILE, size=12*fontZoom) labelColor = BLACK + if self.dataset.type == "Publish" or self.dataset.type == "Geno": dataset_label = self.dataset.fullname else: @@ -1172,6 +1175,7 @@ class DisplayMappingResults(object): else: string3 += 'no control for other QTLs' + y_constant = 10 if self.this_trait.name: if self.selectedChr == -1: identification = "Mapping on All Chromosomes for " @@ -1197,23 +1201,48 @@ class DisplayMappingResults(object): im_drawer.textsize(string2, font=labelFont)[0]) im_drawer.text( text=identification, - xy=(canvas.size[0] - xRightOffset-d, 20*fontZoom), font=labelFont, + xy=(xLeftOffset, y_constant*fontZoom), font=labelFont, fill=labelColor) + y_constant += 15 else: d = 4+ max( im_drawer.textsize(string1, font=labelFont)[0], im_drawer.textsize(string2, font=labelFont)[0]) + + if len(self.transform) > 0: + transform_text = "Transform - " + if self.transform == "qnorm": + transform_text += "Quantile Normalized" + elif self.transform == "log2" or self.transform == "log10": + transform_text += self.transform.capitalize() + elif self.transform == "sqrt": + transform_text += "Square Root" + elif self.transform == "zscore": + transform_text += "Z-Score" + elif self.transform == "invert": + transform_text += "Invert +/-" + + im_drawer.text( + text=transform_text, xy=(xLeftOffset, y_constant*fontZoom), + font=labelFont, fill=labelColor) + y_constant += 15 im_drawer.text( - text=string1, xy=(canvas.size[0] - xRightOffset-d, 35*fontZoom), + text=string1, xy=(xLeftOffset, y_constant*fontZoom), font=labelFont, fill=labelColor) + y_constant += 15 im_drawer.text( - text=string2, xy=(canvas.size[0] - xRightOffset-d, 50*fontZoom), + text=string2, xy=(xLeftOffset, y_constant*fontZoom), font=labelFont, fill=labelColor) + y_constant += 15 if string3 != '': im_drawer.text( - text=string3, xy=(canvas.size[0] - xRightOffset-d, 65*fontZoom), + text=string3, xy=(xLeftOffset, y_constant*fontZoom), font=labelFont, fill=labelColor) - + y_constant += 15 + if string4 != '': + im_drawer.text( + text=string4, xy=(xLeftOffset, y_constant*fontZoom), + font=labelFont, fill=labelColor) def drawGeneBand(self, canvas, gifmap, plotXScale, offset= (40, 120, 80, 10), zoom = 1, startMb = None, endMb = None): im_drawer = ImageDraw.Draw(canvas) @@ -1464,12 +1493,11 @@ class DisplayMappingResults(object): yPaddingTop = yTopOffset thisTrait = self.this_trait - _strains, _vals, _vars, _aliases = thisTrait.export_informative() smd=[] - for ii, _val in enumerate(self.vals): - if _val != "x": - temp = GeneralObject(name=self.samples[ii], value=float(_val)) + for sample in self.sample_vals_dict.keys(): + if self.sample_vals_dict[sample] != "x": + temp = GeneralObject(name=sample, value=float(self.sample_vals_dict[sample])) smd.append(temp) else: continue @@ -2244,6 +2272,7 @@ class DisplayMappingResults(object): ) sugg_coords = "%d, %d, %d, %d" % (start_pos_x, suggestiveY-2, rightEdge + 2*zoom, suggestiveY+2) sig_coords = "%d, %d, %d, %d" % (start_pos_x, significantY-2, rightEdge + 2*zoom, significantY+2) + if self.LRS_LOD == 'LRS': sugg_title = "Suggestive LRS = %0.2f" % self.suggestive sig_title = "Significant LRS = %0.2f" % self.significant diff --git a/wqflask/wqflask/marker_regression/gemma_mapping.py b/wqflask/wqflask/marker_regression/gemma_mapping.py index 61e4897c..ab3a7278 100644 --- a/wqflask/wqflask/marker_regression/gemma_mapping.py +++ b/wqflask/wqflask/marker_regression/gemma_mapping.py @@ -54,7 +54,7 @@ def run_gemma(this_trait, this_dataset, samples, vals, covariates, use_loco, maf TEMPDIR, trait_filename) if covariates != "": - gemma_command += ' -c %s/%s_covariates.txt -a %s/%s_snps.txt -lmm 2 -maf %s > %s/gn2/%s.json' % (flat_files('mapping'), + gemma_command += ' -c %s/%s_covariates.txt -a %s/%s_snps.txt -lmm 9 -maf %s > %s/gn2/%s.json' % (flat_files('mapping'), this_dataset.group.name, flat_files('genotype/bimbam'), genofile_name, @@ -62,7 +62,7 @@ def run_gemma(this_trait, this_dataset, samples, vals, covariates, use_loco, maf TEMPDIR, gwa_output_filename) else: - gemma_command += ' -a %s/%s_snps.txt -lmm 2 -maf %s > %s/gn2/%s.json' % (flat_files('genotype/bimbam'), + gemma_command += ' -a %s/%s_snps.txt -lmm 9 -maf %s > %s/gn2/%s.json' % (flat_files('genotype/bimbam'), genofile_name, maf, TEMPDIR, @@ -80,7 +80,7 @@ def run_gemma(this_trait, this_dataset, samples, vals, covariates, use_loco, maf os.system(generate_k_command) - gemma_command = GEMMA_WRAPPER_COMMAND + ' --json --input %s/gn2/%s.json -- ' % (TEMPDIR, k_output_filename) + GEMMAOPTS + ' -a %s/%s_snps.txt -lmm 2 -g %s/%s_geno.txt -p %s/gn2/%s.txt' % (flat_files('genotype/bimbam'), + gemma_command = GEMMA_WRAPPER_COMMAND + ' --json --input %s/gn2/%s.json -- ' % (TEMPDIR, k_output_filename) + GEMMAOPTS + ' -a %s/%s_snps.txt -lmm 9 -g %s/%s_geno.txt -p %s/gn2/%s.txt' % (flat_files('genotype/bimbam'), genofile_name, flat_files('genotype/bimbam'), genofile_name, @@ -101,7 +101,7 @@ def run_gemma(this_trait, this_dataset, samples, vals, covariates, use_loco, maf marker_obs = parse_loco_output(this_dataset, gwa_output_filename) return marker_obs, gwa_output_filename else: - marker_obs = parse_loco_output(this_dataset, gwa_output_filename) + marker_obs = parse_loco_output(this_dataset, gwa_output_filename, use_loco) return marker_obs, gwa_output_filename def gen_pheno_txt_file(this_dataset, genofile_name, vals, trait_filename): @@ -145,41 +145,7 @@ def gen_covariates_file(this_dataset, covariates, samples): outfile.write(str(this_covariate[i]) + "\t") outfile.write("\n") -def parse_gemma_output(genofile_name): - included_markers = [] - p_values = [] - marker_obs = [] - - with open("{}{}_output.assoc.txt".format(webqtlConfig.GENERATED_IMAGE_DIR, genofile_name)) as output_file: - for line in output_file: - if line.startswith("chr\t"): - continue - else: - marker = {} - marker['name'] = line.split("\t")[1] - if line.split("\t")[0] != "X" and line.split("\t")[0] != "X/Y": - if "chr" in line.split("\t")[0]: - marker['chr'] = int(line.split("\t")[0][3:]) - else: - marker['chr'] = int(line.split("\t")[0]) - else: - marker['chr'] = line.split("\t")[0] - marker['Mb'] = float(line.split("\t")[2]) / 1000000 - marker['p_value'] = float(line.split("\t")[9]) - if math.isnan(marker['p_value']) or (marker['p_value'] <= 0): - marker['lod_score'] = 0 - #marker['lrs_value'] = 0 - else: - marker['lod_score'] = -math.log10(marker['p_value']) - #marker['lrs_value'] = -math.log10(marker['p_value']) * 4.61 - marker_obs.append(marker) - - included_markers.append(line.split("\t")[1]) - p_values.append(float(line.split("\t")[9])) - - return marker_obs - -def parse_loco_output(this_dataset, gwa_output_filename): +def parse_loco_output(this_dataset, gwa_output_filename, loco="True"): output_filelist = [] with open("{}/gn2/".format(TEMPDIR) + gwa_output_filename + ".json") as data_file: @@ -218,7 +184,8 @@ def parse_loco_output(this_dataset, gwa_output_filename): else: marker['chr'] = line.split("\t")[0] marker['Mb'] = float(line.split("\t")[2]) / 1000000 - marker['p_value'] = float(line.split("\t")[9]) + marker['p_value'] = float(line.split("\t")[10]) + marker['additive'] = float(line.split("\t")[7]) if math.isnan(marker['p_value']) or (marker['p_value'] <= 0): marker['lod_score'] = 0 #marker['lrs_value'] = 0 diff --git a/wqflask/wqflask/marker_regression/rqtl_mapping.py b/wqflask/wqflask/marker_regression/rqtl_mapping.py index 0a5758af..4117a0e5 100644 --- a/wqflask/wqflask/marker_regression/rqtl_mapping.py +++ b/wqflask/wqflask/marker_regression/rqtl_mapping.py @@ -94,9 +94,6 @@ def run_rqtl_geno(vals, samples, dataset, mapping_scale, method, model, permChec ro.r('all_covars <- cbind(marker_covars, trait_covars)') else: ro.r('all_covars <- marker_covars') - #logger.info("Saving"); - #ro.r('save.image(file = "/home/dannya/gn2-danny/cross.RData")') - #logger.info("Saving Done"); covars = ro.r['all_covars'] #DEBUG to save the session object to file if pair_scan: @@ -159,7 +156,7 @@ def generate_cross_from_geno(dataset, scale_units): # TODO: Need to figur toskip = which(unlist(lapply(header, function(x){ length(grep("Chr\t", x)) })) == 1)-1 # Major hack to skip the geno headers type <- getGenoCode(header, 'type') if(type == '4-way'){ - genocodes <- c('1','2','3','4') + genocodes <- NULL } else { genocodes <- c(getGenoCode(header, 'mat'), getGenoCode(header, 'het'), getGenoCode(header, 'pat')) # Get the genotype codes } @@ -174,7 +171,7 @@ def generate_cross_from_geno(dataset, scale_units): # TODO: Need to figur require(qtl) if(type == '4-way'){ cat('Loading in as 4-WAY\n') - cross = read.cross(file=out, 'csvr', genotypes=genocodes, crosstype="4way", convertXdata=FALSE) # Load the created cross file using R/qtl read.cross + cross = read.cross(file=out, 'csvr', genotypes=NULL, crosstype="4way") # Load the created cross file using R/qtl read.cross }else if(type == 'f2'){ cat('Loading in as F2\n') cross = read.cross(file=out, 'csvr', genotypes=genocodes, crosstype="f2") # Load the created cross file using R/qtl read.cross @@ -332,8 +329,6 @@ def add_cofactors(cross, this_dataset, covariates, samples): covar_name_string += '"' + col_name + '", ' else: covar_name_string += '"' + col_name + '"' - - logger.info("covar_name_string:" + covar_name_string) else: col_name = "covar_" + str(i) cross = add_phenotype(cross, covar_as_string, col_name) @@ -343,7 +338,6 @@ def add_cofactors(cross, this_dataset, covariates, samples): covar_name_string += '"' + col_name + '"' covar_name_string += ")" - logger.info("covar_name_string:" + covar_name_string); covars_ob = pull_var("trait_covars", cross, covar_name_string) return cross, covars_ob diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py index 891fcc66..72844903 100644 --- a/wqflask/wqflask/marker_regression/run_mapping.py +++ b/wqflask/wqflask/marker_regression/run_mapping.py @@ -71,56 +71,22 @@ class RunMapping(object): all_samples_ordered = self.dataset.group.all_samples_ordered() self.vals = [] - if 'samples' in start_vars: - self.samples = start_vars['samples'].split(",") - if (len(genofile_samplelist) != 0): - for sample in genofile_samplelist: - if sample in self.samples: - value = start_vars.get('value:' + sample) - if value: - self.vals.append(value) - else: - self.vals.append("x") - else: - for sample in self.samples: - value = start_vars.get('value:' + sample) - if value: - self.vals.append(value) + self.samples = [] + self.sample_vals = start_vars['sample_vals'] + sample_val_dict = json.loads(self.sample_vals) + samples = sample_val_dict.keys() + if (len(genofile_samplelist) != 0): + for sample in genofile_samplelist: + self.samples.append(sample) + if sample in samples: + self.vals.append(sample_val_dict[sample]) + else: + self.vals.append("x") else: - self.samples = [] - if (len(genofile_samplelist) != 0): - for sample in genofile_samplelist: - if sample in self.dataset.group.samplelist: - in_trait_data = False - for item in self.this_trait.data: - if self.this_trait.data[item].name == sample: - value = start_vars['value:' + self.this_trait.data[item].name] - self.samples.append(self.this_trait.data[item].name) - self.vals.append(value) - in_trait_data = True - break - if not in_trait_data: - value = start_vars.get('value:' + sample) - if value: - self.samples.append(sample) - self.vals.append(value) - else: - self.vals.append("x") - else: - for sample in self.dataset.group.samplelist: # sample is actually the name of an individual - in_trait_data = False - for item in self.this_trait.data: - if self.this_trait.data[item].name == sample: - value = start_vars['value:' + self.this_trait.data[item].name] - self.samples.append(self.this_trait.data[item].name) - self.vals.append(value) - in_trait_data = True - break - if not in_trait_data: - value = start_vars.get('value:' + sample) - if value: - self.samples.append(sample) - self.vals.append(value) + for sample in self.dataset.group.samplelist: + if sample in samples: + self.vals.append(sample_val_dict[sample]) + self.samples.append(sample) if 'n_samples' in start_vars: self.n_samples = start_vars['n_samples'] @@ -138,15 +104,15 @@ class RunMapping(object): mapping_results_filename = self.dataset.group.name + "_" + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) self.mapping_results_path = "{}{}.csv".format(webqtlConfig.GENERATED_IMAGE_DIR, mapping_results_filename) - if start_vars['manhattan_plot']: - self.color_scheme = "alternating" - if "color_scheme" in start_vars: - self.color_scheme = start_vars['color_scheme'] - if self.color_scheme == "single": - self.manhattan_single_color = start_vars['manhattan_single_color'] - self.manhattan_plot = True - else: - self.manhattan_plot = False + self.manhattan_plot = False + if 'manhattan_plot' in start_vars: + if start_vars['manhattan_plot'].lower() != "false": + self.color_scheme = "alternating" + if "color_scheme" in start_vars: + self.color_scheme = start_vars['color_scheme'] + if self.color_scheme == "single": + self.manhattan_single_color = start_vars['manhattan_single_color'] + self.manhattan_plot = True self.maf = start_vars['maf'] # Minor allele frequency if "use_loco" in start_vars: diff --git a/wqflask/wqflask/pbkdf2.py b/wqflask/wqflask/pbkdf2.py index aea5b06c..6346df03 100644 --- a/wqflask/wqflask/pbkdf2.py +++ b/wqflask/wqflask/pbkdf2.py @@ -2,15 +2,15 @@ import hashlib from werkzeug.security import safe_str_cmp as ssc - # Replace this because it just wraps around Python3's internal # functions. Added this during migration. def pbkdf2_hex(data, salt, iterations=1000, keylen=24, hashfunc="sha1"): """Wrapper function of python's hashlib.pbkdf2_hmac. """ + dk = hashlib.pbkdf2_hmac(hashfunc, bytes(data, "utf-8"), # password - bytes(salt, "utf-8"), # salt + salt, iterations, keylen) return dk.hex() diff --git a/wqflask/wqflask/search_results.py b/wqflask/wqflask/search_results.py index 0d0894a4..9e8001cf 100644 --- a/wqflask/wqflask/search_results.py +++ b/wqflask/wqflask/search_results.py @@ -28,9 +28,9 @@ class SearchResultPage(object): #maxReturn = 3000 def __init__(self, kw): - """This class gets invoked after hitting submit on the main menu (in -views.py). - + """ + This class gets invoked after hitting submit on the main menu (in + views.py). """ ########################################### @@ -86,7 +86,6 @@ views.py). else: self.gen_search_result() - def gen_search_result(self): """ Get the info displayed in the search result table from the set of results computed in @@ -121,7 +120,9 @@ views.py). trait_dict['hmac'] = hmac.data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name)) if this_trait.dataset.type == "ProbeSet": trait_dict['symbol'] = this_trait.symbol - trait_dict['description'] = this_trait.description_display + trait_dict['description'] = "N/A" + if this_trait.description_display: + trait_dict['description'] = this_trait.description_display trait_dict['location'] = this_trait.location_repr trait_dict['mean'] = "N/A" trait_dict['additive'] = "N/A" @@ -137,7 +138,9 @@ views.py). elif this_trait.dataset.type == "Geno": trait_dict['location'] = this_trait.location_repr elif this_trait.dataset.type == "Publish": - trait_dict['description'] = this_trait.description_display + trait_dict['description'] = "N/A" + if this_trait.description_display: + trait_dict['description'] = this_trait.description_display trait_dict['authors'] = this_trait.authors trait_dict['pubmed_id'] = "N/A" if this_trait.pubmed_id: @@ -161,7 +164,14 @@ views.py). trait_dict[key] = trait_dict[key].decode('utf-8') trait_list.append(trait_dict) - self.trait_list = json.dumps(trait_list) + self.trait_list = trait_list + + if this_trait.dataset.type == "ProbeSet": + self.header_data_names = ['index', 'display_name', 'symbol', 'description', 'location', 'mean', 'lrs_score', 'lrs_location', 'additive'] + elif this_trait.dataset.type == "Publish": + self.header_data_names = ['index', 'display_name', 'description', 'mean', 'authors', 'pubmed_text', 'lrs_score', 'lrs_location', 'additive'] + elif this_trait.dataset.type == "Geno": + self.header_data_names = ['index', 'display_name', 'location'] def search(self): """ diff --git a/wqflask/wqflask/server_side.py b/wqflask/wqflask/server_side.py new file mode 100644 index 00000000..5f764767 --- /dev/null +++ b/wqflask/wqflask/server_side.py @@ -0,0 +1,93 @@ +# handles server side table processing + + + +class ServerSideTable(object): + """ + This class is used to do server-side processing + on the DataTables table such as paginating, sorting, + filtering(not implemented) etc. This takes the load off + the client-side and reduces the size of data interchanged. + + Usage: + ServerSideTable(table_data, request_values) + where, + `table_data` must have data members + `rows_count` as number of rows in the table, + `table_rows` as data rows of the table, + `header_data_names` as headers names of the table. + + `request_values` must have request arguments values + including the DataTables server-side processing arguments. + + Have a look at snp_browser_table() function in + wqflask/wqflask/views.py for reference use. + """ + + def __init__(self, rows_count, table_rows, header_data_names, request_values): + self.request_values = request_values + self.sEcho = self.request_values['sEcho'] + + self.rows_count = rows_count + self.table_rows = table_rows + self.header_data_names = header_data_names + + self.sort_rows() + self.paginate_rows() + + def sort_rows(self): + """ + Sorts the rows taking in to account the column (or columns) that the + user has selected. + """ + def is_reverse(str_direction): + """ Maps the 'desc' and 'asc' words to True or False. """ + return True if str_direction == 'desc' else False + + if (self.request_values['iSortCol_0'] != "") and (int(self.request_values['iSortingCols']) > 0): + for i in range(0, int(self.request_values['iSortingCols'])): + column_number = int(self.request_values['iSortCol_' + str(i)]) + column_name = self.header_data_names[column_number - 1] + sort_direction = self.request_values['sSortDir_' + str(i)] + self.table_rows = sorted(self.table_rows, + key=lambda x: x[column_name], + reverse=is_reverse(sort_direction)) + + def paginate_rows(self): + """ + Selects a subset of the filtered and sorted data based on if the table + has pagination, the current page and the size of each page. + """ + def requires_pagination(): + """ Check if the table is going to be paginated """ + if self.request_values['iDisplayStart'] != "": + if int(self.request_values['iDisplayLength']) != -1: + return True + return False + + if not requires_pagination(): + return + + start = int(self.request_values['iDisplayStart']) + length = int(self.request_values['iDisplayLength']) + + # if search returns only one page + if len(self.table_rows) <= length: + # display only one page + self.table_rows = self.table_rows[start:] + else: + limit = -len(self.table_rows) + start + length + if limit < 0: + # display pagination + self.table_rows = self.table_rows[start:limit] + else: + # display last page of pagination + self.table_rows = self.table_rows[start:] + + def get_page(self): + output = {} + output['sEcho'] = str(self.sEcho) + output['iTotalRecords'] = str(float('Nan')) + output['iTotalDisplayRecords'] = str(self.rows_count) + output['data'] = self.table_rows + return output diff --git a/wqflask/wqflask/show_trait/SampleList.py b/wqflask/wqflask/show_trait/SampleList.py index 00495377..ece485ae 100644 --- a/wqflask/wqflask/show_trait/SampleList.py +++ b/wqflask/wqflask/show_trait/SampleList.py @@ -108,7 +108,7 @@ class SampleList(object): FROM CaseAttribute, CaseAttributeXRefNew WHERE CaseAttributeXRefNew.CaseAttributeId = CaseAttribute.Id AND CaseAttributeXRefNew.InbredSetId = %s - ORDER BY CaseAttribute.Name''', (str(self.dataset.group.id),)) + ORDER BY lower(CaseAttribute.Name)''', (str(self.dataset.group.id),)) self.attributes = {} for attr, values in itertools.groupby(results.fetchall(), lambda row: (row.Id, row.Name)): @@ -157,7 +157,7 @@ class SampleList(object): except ValueError: pass - attribute_values[self.attributes[item.Id].name] = attribute_value + attribute_values[self.attributes[item.Id].name.lower()] = attribute_value self.sample_attribute_values[sample_name] = attribute_values def get_first_attr_col(self): diff --git a/wqflask/wqflask/show_trait/show_trait.py b/wqflask/wqflask/show_trait/show_trait.py index 0c6ae198..9b4a8fa4 100644 --- a/wqflask/wqflask/show_trait/show_trait.py +++ b/wqflask/wqflask/show_trait/show_trait.py @@ -186,8 +186,6 @@ class ShowTrait(object): self.has_num_cases = has_num_cases(self.this_trait) - self.stats_table_width, self.trait_table_width = get_table_widths(self.sample_groups, self.has_num_cases) - #ZS: Needed to know whether to display bar chart + get max sample name length in order to set table column width self.num_values = 0 self.binary = "true" #ZS: So it knows whether to display the Binary R/qtl mapping method, which doesn't work unless all values are 0 or 1 @@ -206,6 +204,8 @@ class ShowTrait(object): sample_column_width = max_samplename_width * 8 + self.stats_table_width, self.trait_table_width = get_table_widths(self.sample_groups, sample_column_width, self.has_num_cases) + if self.num_values >= 5000: self.maf = 0.01 else: @@ -372,7 +372,7 @@ class ShowTrait(object): # We're checking a string here! assert isinstance(this_group, str), "We need a string type thing here" - if this_group[:3] == 'BXD' and this_group != "BXD-Longevity": + if this_group[:3] == 'BXD' and this_group != "BXD-Longevity" and this_group != "BXD-AE": this_group = 'BXD' if this_group: @@ -547,12 +547,12 @@ def get_nearest_marker(this_trait, this_db): return result[0][0] -def get_table_widths(sample_groups, has_num_cases=False): +def get_table_widths(sample_groups, sample_column_width, has_num_cases=False): stats_table_width = 250 if len(sample_groups) > 1: stats_table_width = 450 - trait_table_width = 380 + trait_table_width = 300 + sample_column_width if sample_groups[0].se_exists: trait_table_width += 80 if has_num_cases: diff --git a/wqflask/wqflask/snp_browser/snp_browser.py b/wqflask/wqflask/snp_browser/snp_browser.py index 6c3fcf53..a52399a2 100644 --- a/wqflask/wqflask/snp_browser/snp_browser.py +++ b/wqflask/wqflask/snp_browser/snp_browser.py @@ -4,7 +4,7 @@ import string from PIL import (Image) from utility.logger import getLogger -logger = getLogger(__name__ ) +logger = getLogger(__name__) from base import species from base import webqtlConfig @@ -14,21 +14,21 @@ class SnpBrowser(object): def __init__(self, start_vars): self.strain_lists = get_browser_sample_lists() self.initialize_parameters(start_vars) - self.limit_number = 10000 if self.first_run == "false": self.filtered_results = self.get_browser_results() + self.table_rows = self.get_table_rows() + self.rows_count = len(self.table_rows) - if len(self.filtered_results) <= self.limit_number: - self.table_rows = self.get_table_rows() - else: - self.empty_columns = None + del self.filtered_results + + if 'sEcho' not in start_vars: self.table_rows = [] if self.limit_strains == "true": - self.header_fields, self.empty_field_count = get_header_list(variant_type = self.variant_type, strains = self.chosen_strains, empty_columns = self.empty_columns) + self.header_fields, self.empty_field_count, self.header_data_names = get_header_list(variant_type = self.variant_type, strains = self.chosen_strains, empty_columns = self.empty_columns) else: - self.header_fields, self.empty_field_count = get_header_list(variant_type = self.variant_type, strains = self.strain_lists, species = self.species_name, empty_columns = self.empty_columns) + self.header_fields, self.empty_field_count, self.header_data_names = get_header_list(variant_type = self.variant_type, strains = self.strain_lists, species = self.species_name, empty_columns = self.empty_columns) def initialize_parameters(self, start_vars): if 'first_run' in start_vars: @@ -368,19 +368,19 @@ class SnpBrowser(object): #ZS: list of booleans representing which columns are entirely empty, so they aren't displayed on the page; only including ones that are sometimes empty (since there's always a location, etc) self.empty_columns = { - "snp_source": "false", - "conservation_score": "false", - "gene_name": "false", - "transcript": "false", - "exon": "false", - "domain_2": "false", - "function": "false", - "function_details": "false" - } + "snp_source": "false", + "conservation_score": "false", + "gene_name": "false", + "transcript": "false", + "exon": "false", + "domain_2": "false", + "function": "false", + "function_details": "false" + } the_rows = [] for i, result in enumerate(self.filtered_results): - this_row = [] + this_row = {} if self.variant_type == "SNP": snp_name, rs, chr, mb, alleles, gene, transcript, exon, domain, function, function_details, snp_source, conservation_score, snp_id = result[:14] allele_value_list = result[14:] @@ -520,13 +520,10 @@ class SnpBrowser(object): "source_name": str(source_name) } #this_row = [indel_name, indel_chr, indel_mb_s, indel_mb_e, indel_strand, indel_type, indel_size, indel_sequence, source_name] - else: - this_row = {} the_rows.append(this_row) return the_rows - def include_record(self, domain, function, snp_source, conservation_score): """ Decide whether to add this record """ @@ -674,9 +671,13 @@ def get_header_list(variant_type, strains, species = None, empty_columns = None) empty_field_count = 0 #ZS: This is an awkward way of letting the javascript know the index where the allele value columns start; there's probably a better way of doing this header_fields = [] + header_data_names = [] if variant_type == "SNP": header_fields.append(['Index', 'SNP ID', 'Chr', 'Mb', 'Alleles', 'Source', 'ConScore', 'Gene', 'Transcript', 'Exon', 'Domain 1', 'Domain 2', 'Function', 'Details']) + header_data_names = ['index', 'snp_name', 'chr', 'mb_formatted', 'alleles', 'snp_source', 'conservation_score', 'gene_name', 'transcript', 'exon', 'domain_1', 'domain_2', 'function', 'function_details'] + header_fields.append(strain_list) + header_data_names += strain_list if empty_columns != None: if empty_columns['snp_source'] == "false": @@ -703,11 +704,16 @@ def get_header_list(variant_type, strains, species = None, empty_columns = None) if empty_columns['function_details'] == "false": empty_field_count += 1 header_fields[0].remove('Details') + + for col in empty_columns.keys(): + if empty_columns[col] == "false": + header_data_names.remove(col) elif variant_type == "InDel": header_fields = ['Index', 'ID', 'Type', 'InDel Chr', 'Mb Start', 'Mb End', 'Strand', 'Size', 'Sequence', 'Source'] + header_data_names = ['index', 'indel_name', 'indel_type', 'indel_chr', 'indel_mb_s', 'indel_mb_e', 'indel_strand', 'indel_size', 'indel_sequence', 'source_name'] - return header_fields, empty_field_count + return header_fields, empty_field_count, header_data_names def get_effect_details_by_category(effect_name = None, effect_value = None): gene_list = [] @@ -868,8 +874,6 @@ def get_gene_id_name_dict(species_id, gene_name_list): if len(results) > 0: for item in results: gene_id_name_dict[item[1]] = item[0] - else: - pass return gene_id_name_dict @@ -883,7 +887,7 @@ def check_if_in_gene(species_id, chr, mb): query = """SELECT geneId,geneSymbol FROM GeneList WHERE chromosome = '{0}' AND - (txStart < {1} AND txEnd > {1}); """.format(species_id, chr, mb) + (txStart < {1} AND txEnd > {1}); """.format(chr, mb) result = g.db.execute(query).fetchone() diff --git a/wqflask/wqflask/static/new/css/snp_browser.css b/wqflask/wqflask/static/new/css/snp_browser.css index 30fe9a59..a7942d2a 100644 --- a/wqflask/wqflask/static/new/css/snp_browser.css +++ b/wqflask/wqflask/static/new/css/snp_browser.css @@ -6,6 +6,10 @@ table.dataTable thead th { vertical-align: bottom; } +table.dataTable tbody tr.selected { + background-color: #ffee99; +} + table.dataTable thead .sorting, table.dataTable thead .sorting_asc, table.dataTable thead .sorting_desc, @@ -18,7 +22,7 @@ table.dataTable thead .sorting_desc_disabled { table.dataTable thead th{ border-right: 1px solid white; color: white; - background-color: royalblue; + background-color: #369; } table.dataTable tbody td { diff --git a/wqflask/wqflask/static/new/css/trait_list.css b/wqflask/wqflask/static/new/css/trait_list.css index b83655da..c7249721 100644 --- a/wqflask/wqflask/static/new/css/trait_list.css +++ b/wqflask/wqflask/static/new/css/trait_list.css @@ -12,9 +12,43 @@ div.show-hide-container { } button.active { - background: #e5e5e5; + background: #BEBEBE; -webkit-box-shadow: inset 0px 0px 5px #c1c1c1; -moz-box-shadow: inset 0px 0px 5px #c1c1c1; box-shadow: inset 0px 0px 5px #c1c1c1; outline: none; - }
\ No newline at end of file +} + +div.dts { + display:block !important +} + +div.dts div.dts_loading { + z-index:1 +} + +div.dts div.dts_label { + position:absolute; + right:10px; + background:rgba(0,0,0,0.8); + color:white; + box-shadow:3px 3px 10px rgba(0,0,0,0.5); + text-align:right; + border-radius:3px; + padding:0.4em; + z-index:2; + display:none +} + +div.dts div.dataTables_scrollBody { + background:repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, #fff 10px, #fff 20px) +} + +div.dts div.dataTables_scrollBody table { + z-index:2 +} + +div.dts div.dataTables_paginate,div.dts div.dataTables_length{ + display:none +} + diff --git a/wqflask/wqflask/static/new/javascript/draw_probability_plot.js b/wqflask/wqflask/static/new/javascript/draw_probability_plot.js index 3d756303..1b944d4f 100644 --- a/wqflask/wqflask/static/new/javascript/draw_probability_plot.js +++ b/wqflask/wqflask/static/new/javascript/draw_probability_plot.js @@ -118,7 +118,6 @@ }; }; data = [make_data('samples_primary'), make_data('samples_other')]; - console.log("THE DATA IS:", data); d3.select("#prob_plot_container svg").datum(data).call(chart); if (js_data.trait_symbol != null) { $("#prob_plot_title").html("<h3>" + js_data.trait_symbol + ": " + js_data.trait_id + "</h3>"); diff --git a/wqflask/wqflask/static/new/javascript/init_genome_browser.js b/wqflask/wqflask/static/new/javascript/init_genome_browser.js index 2552fb04..508f5bf2 100644 --- a/wqflask/wqflask/static/new/javascript/init_genome_browser.js +++ b/wqflask/wqflask/static/new/javascript/init_genome_browser.js @@ -1,5 +1,3 @@ -console.log("THE FILES:", js_data.browser_files) - snps_filename = "/browser_input?filename=" + js_data.browser_files[0] annot_filename = "/browser_input?filename=" + js_data.browser_files[1] diff --git a/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js b/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js index 5a4f151c..4362a75e 100644 --- a/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js +++ b/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js @@ -93,7 +93,7 @@ build_columns = function() { ); } - attr_keys = Object.keys(js_data.attributes).sort((a, b) => (js_data.attributes[a].name > js_data.attributes[b].name) ? 1 : -1) + attr_keys = Object.keys(js_data.attributes).sort((a, b) => (js_data.attributes[a].name.toLowerCase() > js_data.attributes[b].name.toLowerCase()) ? 1 : -1) for (i = 0; i < attr_keys.length; i++){ column_list.push( { diff --git a/wqflask/wqflask/static/new/javascript/search_results.js b/wqflask/wqflask/static/new/javascript/search_results.js index 9ffef4f8..ecb1220d 100644 --- a/wqflask/wqflask/static/new/javascript/search_results.js +++ b/wqflask/wqflask/static/new/javascript/search_results.js @@ -1,4 +1,4 @@ -change_buttons = function() { +change_buttons = function(check_node = 0) { var button, buttons, item, num_checked, text, _i, _j, _k, _l, _len, _len2, _len3, _len4, _results, _results2; buttons = ["#add", "#remove"]; @@ -6,7 +6,7 @@ change_buttons = function() { table_api = $('#trait_table').DataTable(); check_cells = table_api.column(0).nodes().to$(); for (let i = 0; i < check_cells.length; i++) { - if (check_cells[i].childNodes[0].checked){ + if (check_cells[i].childNodes[check_node].checked){ num_checked += 1 } } @@ -95,29 +95,37 @@ $(function() { $('#select_top').keyup(function(){ num_rows = $(this).val() + if (num_rows = parseInt(num_rows)){ - i = 0 - $('#trait_table > tbody > tr').each(function(){ - if (i < num_rows) { - $(this).find('.trait_checkbox').prop("checked", true) - if (!$(this).closest('tr').hasClass('selected')) { - $(this).closest('tr').addClass('selected') - } - } - else { - if ($(this).closest('tr').hasClass('selected')) { - $(this).closest('tr').removeClass('selected') - $(this).find('.trait_checkbox').prop("checked", false) - } - } - i += 1 - }); + table_api = $('#trait_table').DataTable(); + + check_cells = table_api.column(0).nodes().to$(); + for (let i = 0; i < num_rows; i++) { + check_cells[i].childNodes[0].checked = true; + } + + check_rows = table_api.rows().nodes(); + for (let i=0; i < num_rows; i++) { + if (check_rows[i].classList.contains("selected")){ + continue + } else { + check_rows[i].classList.add("selected") + } + } + for (let i = num_rows; i < check_rows.length; i++){ + check_cells[i].childNodes[0].checked = false; + if (check_rows[i].classList.contains("selected")){ + check_rows[i].classList.remove("selected") + } + } } else { - $('#trait_table > tbody > tr').each(function(){ - $(this).closest('tr').removeClass('selected') - $(this).find('.trait_checkbox').prop("checked", false) - }); + for (let i = 0; i < check_rows.length; i++){ + check_cells[i].childNodes[0].checked = false; + if (check_rows[i].classList.contains("selected")){ + check_rows[i].classList.remove("selected") + } + } } change_buttons(); }); diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js index 5dc9e456..1c8e328d 100644 --- a/wqflask/wqflask/static/new/javascript/show_trait.js +++ b/wqflask/wqflask/static/new/javascript/show_trait.js @@ -94,21 +94,7 @@ add = function() { $('#add_to_collection').click(add); sample_lists = js_data.sample_lists; sample_group_types = js_data.sample_group_types; -d3.select("#select_compare_trait").on("click", (function(_this) { - return function() { - $('.scatter-matrix-container').remove(); - return open_trait_selection(); - }; -})(this)); -d3.select("#select_covariates").on("click", (function(_this) { - return function() { - return open_covariate_selection(); - }; -})(this)); -$("#remove_covariates").click(function () { - $("input[name=covariates]").val("") - $(".selected-covariates").val("") -}); + $(".select_covariates").click(function () { open_covariate_selection(); }); @@ -116,11 +102,7 @@ $(".remove_covariates").click(function () { $("input[name=covariates]").val("") $(".selected-covariates").val("") }); -d3.select("#clear_compare_trait").on("click", (function(_this) { - return function() { - return $('.scatter-matrix-container').remove(); - }; -})(this)); + open_trait_selection = function() { return $('#collections_holder').load('/collections/list?color_by_trait #collections_list', (function(_this) { return function() { @@ -233,6 +215,8 @@ update_histogram = function() { if ($('input[name="transform"]').val() != ""){ root.histogram_layout['xaxis']['title'] = "<b>" + js_data.unit_type + " (" + $('input[name="transform"]').val() + ")</b>" + } else { + root.histogram_layout['xaxis']['title'] = "<b>" + js_data.unit_type + "</b>" } Plotly.newPlot('histogram', root.histogram_data, root.histogram_layout, root.modebar_options); @@ -281,6 +265,8 @@ update_bar_chart = function() { if ($('input[name="transform"]').val() != ""){ root.bar_layout['yaxis']['title'] = "<b>" + js_data.unit_type + " (" + $('input[name="transform"]').val() + ")</b>" + } else { + root.bar_layout['yaxis']['title'] = "<b>" + js_data.unit_type + "</b>" } root.bar_data[0]['y'] = trait_vals @@ -322,6 +308,8 @@ update_box_plot = function() { if ($('input[name="transform"]').val() != ""){ root.box_layout['yaxis']['title'] = "<b>" + js_data.unit_type + " (" + $('input[name="transform"]').val() + ")</b>" + } else { + root.box_layout['yaxis']['title'] = "<b>" + js_data.unit_type + "</b>" } Plotly.newPlot('box_plot', root.box_data, root.box_layout, root.modebar_options) @@ -353,6 +341,8 @@ update_violin_plot = function() { if ($('input[name="transform"]').val() != ""){ root.violin_layout['yaxis']['title'] = "<b>" + js_data.unit_type + " (" + $('input[name="transform"]').val() + ")</b>" + } else { + root.violin_layout['yaxis']['title'] = "<b>" + js_data.unit_type + "</b>" } Plotly.newPlot('violin_plot', root.violin_data, root.violin_layout, root.modebar_options) @@ -427,6 +417,25 @@ process_id = function() { } return processed; }; + +fetch_sample_values = function() { + // This is meant to fetch all sample values using DataTables API, since they can't all be submitted with the form when using Scroller (and this should also be faster) + sample_val_dict = {}; + + table = 'samples_primary'; + if ($('#' + table).length){ + table_api = $('#' + table).DataTable(); + val_nodes = table_api.column(3).nodes().to$(); + for (_j = 0; _j < val_nodes.length; _j++){ + sample_name = val_nodes[_j].childNodes[0].name.split(":")[1] + sample_val = val_nodes[_j].childNodes[0].value + sample_val_dict[sample_name] = sample_val + } + } + + return sample_val_dict; +} + edit_data_change = function() { var already_seen, checkbox, name, real_dict, real_value, real_variance, row, rows, sample_sets, table, tables, _i, _j, _len, _len1; already_seen = {}; @@ -456,15 +465,15 @@ edit_data_change = function() { if (is_number(sample_val) && sample_val !== "") { sample_val = parseFloat(sample_val); sample_sets[table].add_value(sample_val); - if (typeof var_nodes !== 'undefined'){ - sample_var = null; - } else { + try { sample_var = var_nodes[_j].childNodes[0].value if (is_number(sample_var)) { sample_var = parseFloat(sample_var) } else { sample_var = null; } + } catch { + sample_var = null; } sample_dict = { value: sample_val, @@ -479,6 +488,7 @@ edit_data_change = function() { } } } + } update_stat_values(sample_sets); @@ -524,8 +534,31 @@ on_corr_method_change = function() { }; $('select[name=corr_type]').change(on_corr_method_change); +on_dataset_change = function() { + let dataset_type = $('select[name=corr_dataset] option:selected').data('type'); + let location_type = $('select[name=location_type] option:selected').val(); + + if (dataset_type == "mrna_assay"){ + $('#min_expr_filter').show(); + $('select[name=location_type] option:disabled').prop('disabled', false) + } + else if (dataset_type == "pheno"){ + $('#min_expr_filter').show(); + $('select[name=location_type]>option:eq(0)').prop('disabled', true).attr('selected', false); + $('select[name=location_type]>option:eq(1)').prop('disabled', false).attr('selected', true); + } + else { + $('#min_expr_filter').hide(); + $('select[name=location_type]>option:eq(0)').prop('disabled', false).attr('selected', true); + $('select[name=location_type]>option:eq(1)').prop('disabled', true).attr('selected', false); + } +} + +$('select[name=corr_dataset]').change(on_dataset_change); +$('select[name=location_type]').change(on_dataset_change); + submit_special = function(url) { - get_table_contents_for_form_submit("trait_data_form"); + $("input[name=sample_vals]").val(JSON.stringify(fetch_sample_values())) $("#trait_data_form").attr("action", url); $("#trait_data_form").submit(); }; @@ -549,8 +582,8 @@ get_table_contents_for_form_submit = function(form_id) { }); } -var corr_input_list = ['corr_type', 'primary_samples', 'trait_id', 'dataset', 'group', 'tool_used', 'form_url', 'corr_sample_method', 'corr_samples_group', 'corr_dataset', 'min_expr', - 'corr_return_results', 'loc_chr', 'min_loc_mb', 'max_loc_mb', 'p_range_lower', 'p_range_upper'] +var corr_input_list = ['sample_vals', 'corr_type', 'primary_samples', 'trait_id', 'dataset', 'group', 'tool_used', 'form_url', 'corr_sample_method', 'corr_samples_group', 'corr_dataset', 'min_expr', + 'corr_return_results', 'location_type', 'loc_chr', 'min_loc_mb', 'max_loc_mb', 'p_range_lower', 'p_range_upper'] $(".corr_compute").on("click", (function(_this) { return function() { @@ -571,7 +604,7 @@ populate_sample_attributes_values_dropdown = function() { sample_attributes = []; var attributes_as_list = Object.keys(js_data.attributes).map(function(key) { - return [key, js_data.attributes[key].name]; + return [key, js_data.attributes[key].name.toLowerCase()]; }); attributes_as_list.sort(function(first, second) { @@ -631,6 +664,8 @@ block_by_attribute_value = function() { this_val_node.value = "x"; } } + + edit_data_change(); }; $('#exclude_by_attr').click(block_by_attribute_value); @@ -800,6 +835,7 @@ reset_samples_table = function() { }; $('.reset').click(function() { reset_samples_table(); + $('input[name="transform"]').val(""); edit_data_change(); }); @@ -1289,7 +1325,7 @@ if (js_data.num_values < 256) { margin: { l: left_margin, r: 30, - t: 30, + t: 100, b: bottom_margin } }; diff --git a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js index 34582f21..3ae52975 100644 --- a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js +++ b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js @@ -141,7 +141,7 @@ $('input[name=display_all]').change((function(_this) { })(this)); //ZS: This is a list of inputs to be passed to the loading page, since not all inputs on the trait page are relevant to mapping -var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form_url', 'method', 'transform', 'trimmed_markers', 'selected_chr', 'chromosomes', 'mapping_scale', +var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form_url', 'method', 'transform', 'trimmed_markers', 'selected_chr', 'chromosomes', 'mapping_scale', 'sample_vals', 'score_type', 'suggestive', 'significant', 'num_perm', 'permCheck', 'perm_output', 'perm_strata', 'categorical_vars', 'num_bootstrap', 'bootCheck', 'bootstrap_results', 'LRSCheck', 'covariates', 'maf', 'use_loco', 'manhattan_plot', 'control_marker', 'control_marker_db', 'do_control', 'genofile', 'pair_scan', 'startMb', 'endMb', 'graphWidth', 'lrsMax', 'additiveCheck', 'showSNP', 'showGenes', 'viewLegend', 'haplotypeAnalystCheck', diff --git a/wqflask/wqflask/static/new/javascript/stats.js b/wqflask/wqflask/static/new/javascript/stats.js index 4df03412..6c443ab3 100644 --- a/wqflask/wqflask/static/new/javascript/stats.js +++ b/wqflask/wqflask/static/new/javascript/stats.js @@ -91,8 +91,6 @@ Stats = (function() { Stats.prototype.interquartile = function() { var iq, length, q1, q3; length = this.the_values.length; - console.log("in interquartile the_values are:", this.the_values); - console.log("length is:", length); if (js_data.dataset_type == "ProbeSet" && js_data.data_scale == "linear_positive") { q1 = Math.log2(this.the_values[Math.floor(length * .25)]); q3 = Math.log2(this.the_values[Math.floor(length * .75)]); diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html index a86b9ea9..38161851 100644 --- a/wqflask/wqflask/templates/base.html +++ b/wqflask/wqflask/templates/base.html @@ -265,7 +265,7 @@ {% endblock %} <script type="text/javascript"> - $(window).load(function() { + document.addEventListener('DOMContentLoaded', function() { let timeToLoad = document.createElement("p"); timeToLoad.innerHTML = "It took your browser " + ((Date.now() - pageLoadStart)/1000) + " second(s) to render this page"; document.querySelector("footer .row .col-xs-6").appendChild(timeToLoad); diff --git a/wqflask/wqflask/templates/correlation_page.html b/wqflask/wqflask/templates/correlation_page.html index 8e2a23fd..6188c0e7 100644 --- a/wqflask/wqflask/templates/correlation_page.html +++ b/wqflask/wqflask/templates/correlation_page.html @@ -95,14 +95,15 @@ {% elif target_dataset.type == 'Publish' %} <button class="toggle-vis" data-column="3">Abbreviation</button> <button class="toggle-vis" data-column="4">Description</button> - <button class="toggle-vis" data-column="5">Authors</button> - <button class="toggle-vis" data-column="6">Year</button> - <button class="toggle-vis" data-column="7">Sample {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}</button> - <button class="toggle-vis" data-column="8">N</button> - <button class="toggle-vis" data-column="9">Sample p({% if corr_method == 'pearson' %}r{% else %}rho{% endif %})</button> - <button class="toggle-vis" data-column="10">Peak LOD</button> - <button class="toggle-vis" data-column="11">Peak Location</button> - <button class="toggle-vis" data-column="12">Effect Size</button> + <button class="toggle-vis" data-column="5">Mean</button> + <button class="toggle-vis" data-column="6">Authors</button> + <button class="toggle-vis" data-column="7">Year</button> + <button class="toggle-vis" data-column="8">Sample {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}</button> + <button class="toggle-vis" data-column="9">N</button> + <button class="toggle-vis" data-column="10">Sample p({% if corr_method == 'pearson' %}r{% else %}rho{% endif %})</button> + <button class="toggle-vis" data-column="11">Peak LOD</button> + <button class="toggle-vis" data-column="12">Peak Location</button> + <button class="toggle-vis" data-column="13">Effect Size</button> {% else %} <button class="toggle-vis" data-column="3">Location</button> <button class="toggle-vis" data-column="4">Sample {% if corr_method == 'pearson' %}r{% else %}rho{% endif %}</button> @@ -399,6 +400,13 @@ } }, { + 'title': "Mean", + 'type': "natural-minus-na", + 'width': "40px", + 'data': "mean", + 'orderSequence': [ "desc", "asc"] + }, + { 'title': "Authors", 'type': "natural", 'width': "400px", @@ -514,6 +522,8 @@ } ], {% if target_dataset.type == 'Geno' %} "order": [[6, "asc" ]], + {% elif target_dataset.type == 'Publish' %} + "order": [[10, "asc" ]], {% else %} "order": [[9, "asc" ]], {% endif %} diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html index 1a601bef..cfdebde5 100644 --- a/wqflask/wqflask/templates/mapping_results.html +++ b/wqflask/wqflask/templates/mapping_results.html @@ -31,10 +31,7 @@ {% endif %} <input type="hidden" name="results_path" value="{{ mapping_results_path }}"> <input type="hidden" name="method" value="{{ mapping_method }}"> - <input type="hidden" name="samples" value="{{ samples|join(",") }}"> - {% for sample in samples %} - <input type="hidden" name="value:{{ sample }}" value="{{ vals[loop.index - 1] }}"> - {% endfor %} + <input type="hidden" name="sample_vals" value="{{ sample_vals }}"> <input type="hidden" name="n_samples" value="{{ n_samples }}"> <input type="hidden" name="maf" value="{{ maf }}"> <input type="hidden" name="use_loco" value="{{ use_loco }}"> @@ -248,7 +245,7 @@ <button class="btn btn-default" id="select_all"><span class="glyphicon glyphicon-ok"></span> Select All</button> <button class="btn btn-default" id="deselect_all"><span class="glyphicon glyphicon-remove"></span> Deselect All</button> <button class="btn btn-default" id="invert"><span class="glyphicon glyphicon-resize-vertical"></span> Invert</button> - <button class="btn btn-success" id="add" disabled><span class="glyphicon glyphicon-plus-sign"></span> Add</button> + {% if geno_db_exists == "True" %}<button class="btn btn-success" id="add" disabled><span class="glyphicon glyphicon-plus-sign"></span> Add</button>{% endif %} <br /> <br /> <div id="table_container" style="width:{% if 'additive' in trimmed_markers[0] %}600{% else %}550{% endif %}px;"> @@ -375,6 +372,20 @@ console.time("Creating table"); {% if selectedChr == -1 %} $('#trait_table').DataTable( { + "drawCallback": function( settings ) { + $('#trait_table tr').off().on("click", function(event) { + if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') { + var obj =$(this).find('input'); + obj.prop('checked', !obj.is(':checked')); + } + if ($(this).hasClass("selected")){ + $(this).removeClass("selected") + } else { + $(this).addClass("selected") + } + {% if geno_db_exists == "True" %}change_buttons(check_node=1){% endif %} + }); + }, "columns": [ { "type": "natural", "width": "5%" }, { "type": "natural", "width": "8%" }, @@ -389,7 +400,7 @@ "orderable": false } ], "language": { - "info": "Showing1 from _START_ to _END_ of " + js_data.total_markers + " records", + "info": "Showing from _START_ to _END_ of " + js_data.total_markers + " records", }, "order": [[1, "asc" ]], "sDom": "iRZtir", @@ -450,7 +461,7 @@ }); - var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form_url', 'method', 'transform', 'trimmed_markers', 'selected_chr', 'chromosomes', 'mapping_scale', + var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form_url', 'method', 'transform', 'trimmed_markers', 'selected_chr', 'chromosomes', 'mapping_scale', 'sample_vals', 'score_type', 'suggestive', 'significant', 'num_perm', 'permCheck', 'perm_output', 'perm_strata', 'categorical_vars', 'num_bootstrap', 'bootCheck', 'bootstrap_results', 'LRSCheck', 'covariates', 'maf', 'use_loco', 'manhattan_plot', 'color_scheme', 'manhattan_single_color', 'control_marker', 'control_marker_db', 'do_control', 'genofile', 'pair_scan', 'startMb', 'endMb', 'graphWidth', 'lrsMax', 'additiveCheck', 'showSNP', 'showGenes', 'viewLegend', 'haplotypeAnalystCheck', diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html index f2334512..9b36568c 100644 --- a/wqflask/wqflask/templates/search_result_page.html +++ b/wqflask/wqflask/templates/search_result_page.html @@ -3,7 +3,6 @@ {% block css %} <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" /> <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='fontawesome/css/font-awesome.min.css') }}" /> - <link rel="stylesheet" type="text/css" href="{{ url_for('js', filename='DataTablesExtensions/scroller/css/scroller.dataTables.min.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('js', filename='DataTablesExtensions/buttonStyles/css/buttons.dataTables.min.css') }}"> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"> <link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> @@ -125,7 +124,7 @@ {% endif %} </div> {% endif %} - <div id="table_container" {% if dataset.type == 'ProbeSet' or dataset.type == 'Publish' %}style="min-width: 1500px;"{% endif %}> + <div id="table_container" {% if dataset.type == 'ProbeSet' or dataset.type == 'Publish' %}style="min-width: 1500px; max-width:100%;"{% endif %}> <table class="table-hover table-striped cell-border" id='trait_table' style="float: left; width: {% if dataset.type == 'Geno' %}380px{% else %}100%{% endif %};"> <tbody> <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td> @@ -146,6 +145,7 @@ <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='js_alt/md5.min.js') }}"></script> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTables/js/jquery.dataTables.min.js') }}"></script> + <script language="javascript" type="text/javascript" src="https://cdn.datatables.net/scroller/2.0.2/js/dataTables.scroller.min.js"></script> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='jszip/jszip.min.js') }}"></script> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/plugins/sorting/natural.js') }}"></script> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTablesExtensions/buttons/js/dataTables.buttons.min.js') }}"></script> @@ -160,6 +160,16 @@ <script type="text/javascript" charset="utf-8"> $(document).ready( function () { + + var getParams = function(url) { + let parser = document.createElement('a'); + parser.href = url; + let params = parser.search.substring(1); + if(params.length > 0) { + return ('?'+params); + } + return params; + }; $('#trait_table tr').click(function(event) { if (event.target.type !== 'checkbox') { @@ -225,7 +235,7 @@ 'data': null, 'width': "25px", 'orderDataType': "dom-checkbox", - 'orderSequence': [ "desc", "asc"], + 'orderable': false, 'render': function(data, type, row, meta) { return '<input type="checkbox" name="searchResult" class="checkbox trait_checkbox" value="' + data.hmac + '">' } @@ -264,36 +274,36 @@ } }, { - 'title': "Location", + 'title': "<div style='text-align: right;'>Location</div>", 'type': "natural-minus-na", 'width': "125px", 'data': "location" }, { - 'title': "Mean", + 'title': "<div style='text-align: right;'>Mean</div>", 'type': "natural-minus-na", - 'width': "40px", + 'width': "30px", 'data': "mean", 'orderSequence': [ "desc", "asc"] }, { - 'title': "Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>LOD", + 'title': "<div style='text-align: right;'>Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>LOD  </div>", 'type': "natural-minus-na", 'data': "lod_score", 'width': "60px", 'orderSequence': [ "desc", "asc"] }, { - 'title': "Peak Location", + 'title': "<div style='text-align: right;'>Peak Location</div>", 'type': "natural-minus-na", 'width': "125px", 'data': "lrs_location" }, { - 'title': "Effect Size<a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>", + 'title': "<div style='text-align: right;'>Effect <a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>Size  </div>", 'type': "natural-minus-na", 'data': "additive", - 'width': "90px", + 'width': "60px", 'orderSequence': [ "desc", "asc"] }{% elif dataset.type == 'Publish' %}, { @@ -310,16 +320,16 @@ } }, { - 'title': "Mean", + 'title': "<div style='text-align: right;'>Mean</div>", 'type': "natural-minus-na", - 'width': "110px", + 'width': "30px", 'data': "mean", 'orderSequence': [ "desc", "asc"] }, { 'title': "Authors", 'type': "natural", - 'width': "500px", + 'width': "300px", 'data': null, 'render': function(data, type, row, meta) { author_list = data.authors.split(",") @@ -332,10 +342,10 @@ } }, { - 'title': "Year", + 'title': "<div style='text-align: right;'>Year</div>", 'type': "natural-minus-na", 'data': null, - 'width': "80px", + 'width': "25px", 'render': function(data, type, row, meta) { if (data.pubmed_id != "N/A"){ return '<a href="' + data.pubmed_link + '">' + data.pubmed_text + '</a>' @@ -346,45 +356,43 @@ 'orderSequence': [ "desc", "asc"] }, { - 'title': "Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>LOD", + 'title': "<div style='text-align: right;'>Peak <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>LOD  </div>", 'type': "natural-minus-na", 'data': "lod_score", 'width': "60px", 'orderSequence': [ "desc", "asc"] }, { - 'title': "Peak Location", + 'title': "<div style='text-align: right;'>Peak Location</div>", 'type': "natural-minus-na", 'width': "120px", 'data': "lrs_location" }, { - 'title': "Effect Size<a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a>", + 'title': "<div style='text-align: right;'>Effect <a href=\"{{ url_for('glossary_blueprint.glossary') }}#A\" target=\"_blank\" style=\"color: white;\"> <i class=\"fa fa-info-circle\" aria-hidden=\"true\"></i></a></div><div style='text-align: right;'>Size  </div>", 'type': "natural-minus-na", - 'width': "120px", + 'width': "60px", 'data': "additive", 'orderSequence': [ "desc", "asc"] }{% elif dataset.type == 'Geno' %}, { - 'title': "Location", + 'title': "<div style='text-align: right;'>Location</div>", 'type': "natural-minus-na", 'width': "120px", 'data': "location" }{% endif %} ], "order": [[1, "asc" ]], - 'sDom': "itirp", - 'iDisplayLength': 500, - 'deferRender': true, - 'paging': true, - 'orderClasses': true, - 'processing': true, - 'language': { - 'loadingRecords': ' ', - 'processing': 'Loading...' - } + 'sDom': "iti", + "autoWidth": true, + "bSortClasses": false, + "scrollY": "100vh", + "scroller": true, + "scrollCollapse": true } ); + trait_table.draw(); //ZS: This makes the table adjust its height properly on initial load + $('.toggle-vis').on( 'click', function (e) { e.preventDefault(); diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html index c881eb76..77fc9342 100644 --- a/wqflask/wqflask/templates/show_trait.html +++ b/wqflask/wqflask/templates/show_trait.html @@ -35,6 +35,7 @@ <input type="hidden" name="genofile" value=""> <input type="hidden" name="covariates" value=""> <input type="hidden" name="transform" value=""> + <input type="hidden" name="sample_vals" value=""> <div class="container showtrait-main-div"> <div class="panel-group" id="accordion"> diff --git a/wqflask/wqflask/templates/show_trait_calculate_correlations.html b/wqflask/wqflask/templates/show_trait_calculate_correlations.html index ba72ff27..cba977ac 100644 --- a/wqflask/wqflask/templates/show_trait_calculate_correlations.html +++ b/wqflask/wqflask/templates/show_trait_calculate_correlations.html @@ -2,86 +2,94 @@ <div class="col-xs-3 correlation-options"> <div class="form-horizontal section-form-div"> - <div class="form-group"> - <label for="corr_type" class="col-xs-2 control-label">Method</label> - <div class="col-xs-3 controls"> - <select name="corr_type" class="form-control"> - <option value="sample">Sample r</option> - <option value="lit">Literature r</option> - <option value="tissue">Tissue r</option> - </select> - </div> - </div> + <div class="form-group"> + <label for="corr_type" class="col-xs-2 control-label">Method</label> + <div class="col-xs-3 controls"> + <select name="corr_type" class="form-control"> + <option value="sample">Sample r</option> + <option value="lit">Literature r</option> + <option value="tissue">Tissue r</option> + </select> + </div> + </div> - <div class="form-group"> - <label for="corr_dataset" class="col-xs-2 control-label">Database</label> - <div class="col-xs-10 controls"> - <select name="corr_dataset" class="form-control"> - {% for tissue in corr_tools.dataset_menu %} - {% if tissue.tissue %} - <optgroup label="{{ tissue.tissue }} ------"> - {% endif %} - {% for dataset in tissue.datasets %} - <option value="{{ dataset[1] }}" - {% if corr_tools.dataset_menu_selected == dataset[1] %} - selected - {% endif %}> - {{ dataset[0] }} - </option> - {% endfor %} - {% if tissue.tissue %} - </optgroup> - {% endif %} - {% endfor %} - </select> - </div> - </div> + <div class="form-group"> + <label for="corr_dataset" class="col-xs-2 control-label">Database</label> + <div class="col-xs-10 controls"> + <select name="corr_dataset" class="form-control"> + {% for tissue in corr_tools.dataset_menu %} + {% if tissue.tissue %} + <optgroup label="{{ tissue.tissue }} ------"> + {% endif %} + {% for dataset in tissue.datasets %} + <option data-type="{% if tissue.tissue %}mrna_assay{% elif dataset[1][-4:] == 'Geno' %}geno{% else %}pheno{% endif %}" value="{{ dataset[1] }}" + {% if corr_tools.dataset_menu_selected == dataset[1] %} + selected + {% endif %}> + {{ dataset[0] }} + </option> + {% endfor %} + {% if tissue.tissue %} + </optgroup> + {% endif %} + {% endfor %} + </select> + </div> + </div> - <div class="form-group"> - <label for="corr_return_results" class="col-xs-2 control-label">Limit to</label> - <div class="col-xs-4 controls"> - <select name="corr_return_results" class="form-control"> - {% for return_result in corr_tools.return_results_menu %} - <option value="{{ return_result }}" - {% if corr_tools.return_results_menu_selected == return_result %} - selected - {% endif %}> - Top {{ return_result }} - </option> - {% endfor %} - </select> - </div> - </div> + <div class="form-group"> + <label for="corr_return_results" class="col-xs-2 control-label">Limit to</label> + <div class="col-xs-4 controls"> + <select name="corr_return_results" class="form-control"> + {% for return_result in corr_tools.return_results_menu %} + <option value="{{ return_result }}" + {% if corr_tools.return_results_menu_selected == return_result %} + selected + {% endif %}> + Top {{ return_result }} + </option> + {% endfor %} + </select> + </div> + </div> - <div class="form-group"> - <label for="corr_samples_group" class="col-xs-2 control-label">Samples</label> - <div class="col-xs-4 controls"> - <select name="corr_samples_group" class="form-control"> - {% for group, pretty_group in sample_group_types.items() %} - <option value="{{ group }}">{{ pretty_group }}</option> - {% endfor %} - </select> - </div> - </div> + <div class="form-group"> + <label for="corr_samples_group" class="col-xs-2 control-label">Samples</label> + <div class="col-xs-4 controls"> + <select name="corr_samples_group" class="form-control"> + {% for group, pretty_group in sample_group_types.items() %} + <option value="{{ group }}">{{ pretty_group }}</option> + {% endfor %} + </select> + </div> + </div> - <div id="corr_sample_method" class="form-group"> - <label for="corr_sample_method" class="col-xs-2 control-label">Type</label> - <div class="col-xs-4 controls"> - <select name="corr_sample_method" class="form-control"> - <option value="pearson">Pearson</option> - <option value="spearman">Spearman Rank</option> - <option value="bicor">Biweight Midcorrelation</option> - </select> - </div> - </div> - {% if dataset.type != "Publish" %} - <div class="form-group"> - <label class="col-xs-2 control-label">Min Expr</label> - <div class="col-xs-4 controls"> - <input name="min_expr" value="" type="text" class="form-control min-expr-field"> - </div> - </div> - <div class="form-group"> + <div id="corr_sample_method" class="form-group"> + <label for="corr_sample_method" class="col-xs-2 control-label">Type</label> + <div class="col-xs-4 controls"> + <select name="corr_sample_method" class="form-control"> + <option value="pearson">Pearson</option> + <option value="spearman">Spearman Rank</option> + <option value="bicor">Biweight Midcorrelation</option> + </select> + </div> + </div> + <div id="min_expr_filter" class="form-group" style="display: {% if dataset.type != 'Geno' %}block{% else %}none{% endif %};"> + <label class="col-xs-2 control-label">Min Expr</label> + <div class="col-xs-4 controls"> + <input name="min_expr" value="" type="text" class="form-control min-expr-field"> + </div> + </div> + <div class="form-group"> + <label for="location_type" class="col-xs-2 control-label">Location Type</label> + <div class="col-xs-4 controls"> + <select name="location_type" class="form-control"> + <option value="gene" {% if dataset.type == 'Publish' %}disabled{% endif %}>Gene</option> + <option value="highest_lod">Highest LOD</option> + </select> + </div> + </div> + <div id="location_filter" class="form-group"> <label class="col-xs-2 control-label">Location</label> <div class="col-xs-6 controls"> <span> @@ -91,7 +99,6 @@ <br> </div> </div> - {% endif %} <div class="form-group"> <label class="col-xs-2 control-label">Range</label> <div class="col-xs-5 controls"> diff --git a/wqflask/wqflask/templates/show_trait_edit_data.html b/wqflask/wqflask/templates/show_trait_edit_data.html index 4ad11a5e..0d34bebc 100644 --- a/wqflask/wqflask/templates/show_trait_edit_data.html +++ b/wqflask/wqflask/templates/show_trait_edit_data.html @@ -1,12 +1,9 @@ <div> {% for sample_type in sample_groups %} <div class="sample-table-container"> - {% if loop.index == 1 %} + {% if loop.index == 1 and (sample_groups[0].se_exists or has_num_cases or sample_groups[0].attributes|length > 0) %} <b>Show/Hide Columns:</b> <br> - <button class="toggle-vis" data-column="1">ID</button> - <button class="toggle-vis" data-column="2">Sample</button> - <button class="toggle-vis" data-column="3">Value</button> {% if sample_groups[0].se_exists %} <button class="toggle-vis" data-column="4,5">SE</button> {% if has_num_cases %} diff --git a/wqflask/wqflask/templates/show_trait_mapping_tools.html b/wqflask/wqflask/templates/show_trait_mapping_tools.html index eca436c6..c42fe4aa 100755 --- a/wqflask/wqflask/templates/show_trait_mapping_tools.html +++ b/wqflask/wqflask/templates/show_trait_mapping_tools.html @@ -74,8 +74,8 @@ No collections available. Please add traits to a collection to use them as covariates. {% else %} <div class="select-covar-div"> - <button type="button" id="select_covariates" class="btn btn-default select-covar-button">Select</button> - <button type="button" id="remove_covariates" class="btn btn-default select-covar-button">Remove</button> + <button type="button" class="btn btn-default select-covar-button select_covariates">Select</button> + <button type="button" class="btn btn-default select-covar-button remove_covariates">Remove</button> </div> <textarea rows="3" cols="50" readonly placeholder="No covariates selected" class="selected-covariates"></textarea> {% endif %} @@ -317,8 +317,8 @@ No collections available. Please add traits to a collection to use them as covariates. {% else %} <div class="select-covar-div"> - <button type="button" id="select_covariates" class="btn btn-default select-covar-button">Select</button> - <button type="button" id="remove_covariates" class="btn btn-default select-covar-button">Remove</button> + <button type="button" class="btn btn-default select-covar-button select_covariates">Select</button> + <button type="button" class="btn btn-default select-covar-button remove_covariates">Remove</button> </div> <textarea rows="3" cols="50" readonly placeholder="No covariates selected" class="selected-covariates"></textarea> {% endif %} diff --git a/wqflask/wqflask/templates/show_trait_statistics.html b/wqflask/wqflask/templates/show_trait_statistics.html index 4f347d4e..865959b1 100644 --- a/wqflask/wqflask/templates/show_trait_statistics.html +++ b/wqflask/wqflask/templates/show_trait_statistics.html @@ -21,9 +21,6 @@ <li> <a href="#violin_plot_tab" class="violin_plot_tab" data-toggle="tab">Violin Plot</a> </li> - <li> - <a href="#scatterplot_matrix" data-toggle="tab">Scatterplot Matrix</a> - </li> </ul> <div class="tab-content"> <div class="tab-pane active" id="stats_tab"> @@ -116,19 +113,6 @@ <div id="violin_plot"></div> </div> </div> - <div class="tab-pane" id="scatterplot_matrix"> - <div class="btn-group scatterplot-btn-div"> - <button type="button" class="btn btn-default" id="select_compare_trait"> - <i class="icon-th-large"></i> Select Traits - </button> - <button type="button" class="btn btn-default" id="clear_compare_trait"> - <i class="icon-trash"></i> Clear - </button> - </div> - <div id="scatterplot_container"> - <div id="comparison_scatterplot" class="qtlcharts"></div> - </div> - </div> </div> </div> <div id="collections_holder_wrapper" style="display:none;"> diff --git a/wqflask/wqflask/templates/snp_browser.html b/wqflask/wqflask/templates/snp_browser.html index a96b8e3b..b9aea570 100644 --- a/wqflask/wqflask/templates/snp_browser.html +++ b/wqflask/wqflask/templates/snp_browser.html @@ -15,7 +15,7 @@ <input type="hidden" name="first_run" value="{{ first_run }}"> <input type="hidden" name="chosen_strains_mouse" value="{{ chosen_strains_mouse|join(",") }}"> <input type="hidden" name="chosen_strains_rat" value="{{ chosen_strains_rat|join(",") }}"> - <div class="col-xs-4" style="padding-left: 0px;"> + <div class="col-xs-4" style="width: 260px; padding-left: 30px; padding-right: 0px;"> <div class="form-group row" style="margin-bottom: 5px;"> <label for="snp_or_indel" style="text-align: right;" class="col-xs-4 col-form-label"><b>Type:</b></label> <div class="col-xs-8"> @@ -74,7 +74,7 @@ </div> </div> </div> - <div class="col-xs-4" style="padding-left: 0px;"> + <div class="col-xs-4" style="width: 310px; padding-left: 0px; padding-right: 20px;"> <div class="form-group row" style="margin-bottom: 10px;"> <label for="strains" style="text-align: right;" class="col-xs-4 col-form-label"><b>Strains:</b></label> <div class="col-xs-8"> @@ -107,8 +107,14 @@ </div> </div> </div> + <div class="form-group row"> + <label class="col-xs-4 col-form-label"></label> + <div class="col-xs-8" style="margin-top: 65px;"> + <input class="btn btn-primary" type="button" name="export_csv" value="Export to CSV"> + </div> + </div> </div> - <div class="col-xs-4" style="padding-left: 20px;"> + <div class="col-xs-4" style="width: 310px; padding-left: 20px;"> <div class="form-group row" style="margin-bottom: 5px;"> <label for="domain" style="text-align: right;" class="col-xs-4 col-form-label"><b>Domain:</b></label> <div class="col-xs-8"> @@ -182,24 +188,21 @@ </div> <div style="margin-top: 20px;"> - {% if filtered_results is defined %} - {% if filtered_results|length > limit_number %} - There are more than 10000 results. Consider limiting your search to a smaller range. - {% else %} + {% if table_rows is defined %} <table class="dataTable cell-border nowrap" id="results_table" style="float: left;"> <thead> <tr> <th></th> {% if header_fields|length == 2 %} {% for header in header_fields[0] %} - <th data-export="{{ header }}">{{ header }}</th> + <th data-export="{{ header }}" name="{{ header }}">{{ header }}</th> {% endfor %} {% for strain in header_fields[1] %} - <th data-export="{{ strain }}" style="align: center; text-align: center; line-height: 15px;">{% for letter in strain %}<div style="transform: rotate(90deg);">{{ letter }}</div>{% endfor %}</th> + <th data-export="{{ strain }}" name="{{ strain }}" style="align: center; text-align: center; line-height: 12px;">{% for letter in strain|reverse %}<div style="transform: rotate(270deg);">{{ letter }}</div>{% endfor %}</th> {% endfor %} {% else %} {% for header in header_fields %} - <th data-export="{{ header }}">{{ header }}</th> + <th data-export="{{ header }}" name="{{ header }}">{{ header }}</th> {% endfor %} {% endif %} </tr> @@ -208,7 +211,6 @@ <td colspan="100%" align="center"><br><b><font size="15">Loading...</font></b><br></td> </tbody> </table> - {% endif %} {% endif %} </div> </div> @@ -222,12 +224,24 @@ <script language="javascript" type="text/javascript" src="/static/new/javascript/typeahead_rn6.json"></script> <script type='text/javascript'> - var json_rows = {{ table_rows|safe }}; var empty_columns = {{ empty_columns|safe }}; + + var remain_field_count = 15 - {{ empty_field_count|safe }}; + var total_field_count = 15 - {{ empty_field_count|safe }} + {{ allele_list|safe|length }}; </script> <script language="javascript"> + var getParams = function(url) { + let parser = document.createElement('a'); + parser.href = url; + let params = parser.search.substring(1); + if(params.length > 0) { + return ('?'+params); + } + return params; + }; + var substringMatcher = function(strs) { return function findMatches(q, cb) { var matches, substringRegex; @@ -260,19 +274,20 @@ source: substringMatcher(rat_genes) }); - {% if filtered_results is defined %} + {% if table_rows is defined %} $("#results_table").DataTable( { - 'data': json_rows, {% if variant_type == "SNP" %} 'columns': [ { 'data': null, + 'className': 'dt-body-center', 'orderable': false, 'render': function(data, type, row, meta) { - return '<input type="checkbox" name="trait_check">' + return '<input type="checkbox" class="checkbox" id="variant_checkbox" onchange="onVarinatCheck(this)" name="trait_check">' } }, { - 'data': 'index' + 'data': 'index', + 'className': 'dt-body-right' }, { 'data': null, 'render': function(data, type, row, meta) { @@ -283,27 +298,30 @@ } } }, { - 'data': 'chr' + 'data': 'chr', + 'className': 'dt-body-center' }, { - 'data': 'mb_formatted' + 'data': 'mb_formatted', + 'className': 'dt-body-right' }, { 'data': 'alleles' }, {% if empty_columns['snp_source'] == "true" %}{ 'data': null, 'render': function(data, type, row, meta) { if (data.snp_source == "Sanger/UCLA") { - return '<a href="' + data.source_urls[0] + '">Sanger</a><a href="' + data.source_urls[1] + '">UCLA</a>' + return '<a href="' + data.source_urls[0] + '">Sanger</a>, <a href="' + data.source_urls[1] + '">UCLA</a>' } else { return data.snp_source } } }, {% endif %} {% if empty_columns['conservation_score'] == "true" %}{ - 'data': 'conservation_score' + 'data': 'conservation_score', + 'className': 'dt-body-right' }, {% endif %} {% if empty_columns['gene_name'] == "true" %}{ 'data': null, 'render': function(data, type, row, meta) { if (data.gene_name != "") { - return '<i>' + data.gene_name + '</i><br><a href="' + data.gene_link + '">NCBI</a>' + return '<i>' + data.gene_name + '</i>, <a href="' + data.gene_link + '">NCBI</a>' } else { return data.gene_name } @@ -330,6 +348,7 @@ }, {% endif %} {% for item in allele_list %} { 'data': null, 'orderable': false, + 'className': 'dt-body-center', 'render': function(data, type, row, meta) { if (typeof data.allele_value_list[{{ loop.index - 1 }}][0] !== "undefined") { return data.allele_value_list[{{ loop.index - 1 }}][0] @@ -339,12 +358,9 @@ } }{% if loop.index < allele_list|length %},{% endif %}{% endfor %} ], - 'createdRow': function( row, data, dataIndex) { - $('td', row).eq(0).attr("style", "text-align: center; padding: 4px 10px 2px 10px;"); - $('td', row).eq(1).attr("align", "right"); - for (i = {{ 15 - empty_field_count }}; i < ({{ 15 - empty_field_count }} + {{ allele_list|length }}); i++) { + 'createdRow': function(row, data, dataIndex) { + for (i = remain_field_count; i < total_field_count; i++) { var this_allele = $('td', row).eq(i).text(); - $('td', row).eq(i).attr("style", "text-align: center; padding: 4px 10px 2px 10px;"); switch (this_allele) { case "A": $('td', row).eq(i).addClass('A_allele_color'); @@ -380,24 +396,29 @@ { 'data': null, 'render': function(data, type, row, meta) { - return '<input type="checkbox" name="trait_check">' + return '<input type="checkbox" class="checkbox" id="variant_checkbox" onchange="onVarinatCheck(this)" name="trait_check">' } }, { - 'data': 'index' + 'data': 'index', + 'className': 'dt-body-right' }, { 'data': 'indel_name' }, { 'data': 'indel_type' }, { - 'data': 'indel_chr' + 'data': 'indel_chr', + 'className': 'dt-body-center' }, { - 'data': 'indel_mb_s' + 'data': 'indel_mb_s', + 'className': 'dt-body-right' }, { - 'data': 'indel_mb_e' + 'data': 'indel_mb_e', + 'className': 'dt-body-right' }, { 'data': 'indel_strand' }, { - 'data': 'indel_size' + 'data': 'indel_size', + 'className': 'dt-body-right' }, { 'data': 'indel_sequence' }, { @@ -407,15 +428,28 @@ {% endif %} 'order': [[1, "asc" ]], 'sDom': "rtip", - 'iDisplayLength': 500, - 'processing': true, - 'language': { - 'loadingRecords': ' ', - 'processing': 'Loading...' + 'iDisplayLength': 100, + 'bServerSide': true, + 'sAjaxSource': '/snp_browser_table'+getParams(window.location.href), + 'infoCallback': function(settings, start, end, max, total, pre) { + return "Showing " + start + " to " + (start + this.api().data().length - 1) + " of " + total + " entries"; } }); {% endif %} + function onVarinatCheck(checkboxElem) { + if (checkboxElem.checked) { + if (!checkboxElem.parentElement.parentElement.classList.contains('selected')) { + checkboxElem.parentElement.parentElement.classList.add('selected') + } + } + else { + if (checkboxElem.parentElement.parentElement.classList.contains('selected')) { + checkboxElem.parentElement.parentElement.classList.remove('selected') + } + } + } + $("#species_select").change(function() { this_species = $(this).val(); $("#strain_select").empty() @@ -509,6 +543,40 @@ }); $("input[name=chosen_strains]").val(strain_list.join(",")); }); + + + + $("input[name=export_csv]").click(function() { + var csv = []; + var rows = document.querySelectorAll("table tr"); + + var headers = []; + var col_header = rows[0].querySelectorAll("th"); + for(let i = 1; i < col_header.length; i++) { + headers.push(col_header[i].getAttribute("name")); + } + csv.push(headers.join(",")); + + for (let i = 1; i < rows.length; i++) { + var row = [], cols = rows[i].querySelectorAll("td"); + var checkBox = rows[i].querySelector("input"); + + if(checkBox.checked == true) { + for (let j = 1; j < cols.length; j++) + row.push(cols[j].innerText); + + csv.push(row.join(",")); + } + } + + var csvFile = new Blob([csv.join("\n")], {type: "text/csv"}); + var downloadLink = document.createElement("a"); + downloadLink.download = "variant_data.csv"; + downloadLink.href = window.URL.createObjectURL(csvFile); + downloadLink.style.display = "none"; + document.body.appendChild(downloadLink); + downloadLink.click(); + }); </script> {% endblock %} diff --git a/wqflask/wqflask/user_login.py b/wqflask/wqflask/user_login.py index f25ebc32..041f1f11 100644 --- a/wqflask/wqflask/user_login.py +++ b/wqflask/wqflask/user_login.py @@ -25,7 +25,7 @@ from utility.logger import getLogger logger = getLogger(__name__) from smtplib import SMTP -from utility.tools import SMTP_CONNECT, SMTP_USERNAME, SMTP_PASSWORD, LOG_SQL_ALCHEMY +from utility.tools import SMTP_CONNECT, SMTP_USERNAME, SMTP_PASSWORD, LOG_SQL_ALCHEMY, GN2_BRANCH_URL THREE_DAYS = 60 * 60 * 24 * 3 @@ -39,8 +39,12 @@ def basic_info(): def encode_password(pass_gen_fields, unencrypted_password): + if isinstance(pass_gen_fields['salt'], bytes): + salt = pass_gen_fields['salt'] + else: + salt = bytes(pass_gen_fields['salt'], "utf-8") encrypted_password = pbkdf2.pbkdf2_hex(str(unencrypted_password), - pass_gen_fields['salt'], + salt, pass_gen_fields['iterations'], pass_gen_fields['keylength'], pass_gen_fields['hashfunc']) @@ -239,7 +243,7 @@ def github_oauth2(): } result = requests.post("https://github.com/login/oauth/access_token", json=data) - result_dict = {arr[0]:arr[1] for arr in [tok.split("=") for tok in [token.encode("utf-8") for token in result.text.split("&")]]} + result_dict = {arr[0]:arr[1] for arr in [tok.split("=") for tok in result.text.split("&")]} github_user = get_github_user_details(result_dict["access_token"]) @@ -277,9 +281,11 @@ def orcid_oauth2(): data = { "client_id": ORCID_CLIENT_ID, "client_secret": ORCID_CLIENT_SECRET, - "grant_type": "authorization_code", + "grant_type": "authorization_code", + "redirect_uri": GN2_BRANCH_URL + "n/login/orcid_oauth2", "code": code } + result = requests.post(ORCID_TOKEN_URL, data=data) result_dict = json.loads(result.text.encode("utf-8")) diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 25563e86..e4834d53 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -26,6 +26,15 @@ import sqlalchemy from wqflask import app from flask import g, Response, request, make_response, render_template, send_from_directory, jsonify, redirect, url_for, send_file +from wqflask import group_manager +from wqflask import resource_manager +from wqflask import search_results +from wqflask import export_traits +from wqflask import gsearch +from wqflask import update_search_results +from wqflask import docs +from wqflask import news +from wqflask import server_side from wqflask.submit_bnw import get_bnw_input from base.data_set import create_dataset, DataSet # Used by YAML in marker_regression from wqflask.show_trait import show_trait @@ -220,6 +229,26 @@ def search_page(): else: return render_template("search_error.html") +@app.route("/search_table", methods=('GET',)) +def search_page_table(): + logger.info("in search_page table") + logger.info(request.url) + + logger.info("request.args is", request.args) + the_search = search_results.SearchResultPage(request.args) + + logger.info(type(the_search.trait_list)) + logger.info(the_search.trait_list) + + current_page = server_side.ServerSideTable( + len(the_search.trait_list), + the_search.trait_list, + the_search.header_data_names, + request.args, + ).get_page() + + return flask.jsonify(current_page) + @app.route("/gsearch", methods=('GET',)) def gsearchact(): logger.info(request.url) @@ -621,12 +650,13 @@ def loading_page(): wanted = initial_start_vars['wanted_inputs'].split(",") start_vars = {} for key, value in list(initial_start_vars.items()): - if key in wanted or key.startswith(('value:')): + if key in wanted: start_vars[key] = value if 'n_samples' in start_vars: n_samples = int(start_vars['n_samples']) else: + sample_vals_dict = json.loads(start_vars['sample_vals']) if 'group' in start_vars: dataset = create_dataset(start_vars['dataset'], group_name = start_vars['group']) else: @@ -642,9 +672,9 @@ def loading_page(): samples = genofile_samples for sample in samples: - value = start_vars.get('value:' + sample) - if value != "x": - n_samples += 1 + if sample in sample_vals_dict: + if sample_vals_dict[sample] != "x": + n_samples += 1 start_vars['n_samples'] = n_samples start_vars['wanted_inputs'] = initial_start_vars['wanted_inputs'] @@ -660,7 +690,6 @@ def loading_page(): @app.route("/run_mapping", methods=('POST',)) def mapping_results_page(): initial_start_vars = request.form - #logger.debug("Mapping called with initial_start_vars:", initial_start_vars.items()) logger.info(request.url) temp_uuid = initial_start_vars['temp_uuid'] wanted = ( @@ -670,6 +699,7 @@ def mapping_results_page(): 'species', 'samples', 'vals', + 'sample_vals', 'first_run', 'output_files', 'geno_db_exists', @@ -723,13 +753,11 @@ def mapping_results_page(): ) start_vars = {} for key, value in list(initial_start_vars.items()): - if key in wanted or key.startswith(('value:')): + if key in wanted: start_vars[key] = value - #logger.debug("Mapping called with start_vars:", start_vars) version = "v3" key = "mapping_results:{}:".format(version) + json.dumps(start_vars, sort_keys=True) - #logger.info("key is:", pf(key)) with Bench("Loading cache"): result = None # Just for testing #result = Redis.get(key) @@ -751,10 +779,9 @@ def mapping_results_page(): rendered_template = render_template("mapping_error.html") return rendered_template except: - rendered_template = render_template("mapping_error.html") - return rendered_template + rendered_template = render_template("mapping_error.html") + return rendered_template - #if template_vars.mapping_method != "gemma" and template_vars.mapping_method != "plink": template_vars.js_data = json.dumps(template_vars.js_data, default=json_default_handler, indent=" ") @@ -775,10 +802,6 @@ def mapping_results_page(): rendered_template = render_template("pair_scan_results.html", **result) else: gn1_template_vars = display_mapping_results.DisplayMappingResults(result).__dict__ - #pickled_result = pickle.dumps(result, pickle.HIGHEST_PROTOCOL) - #logger.info("pickled result length:", len(pickled_result)) - #Redis.set(key, pickled_result) - #Redis.expire(key, 1*60) with Bench("Rendering template"): #if (gn1_template_vars['mapping_method'] == "gemma") or (gn1_template_vars['mapping_method'] == "plink"): @@ -896,6 +919,19 @@ def db_info_page(): return render_template("info_page.html", **template_vars.__dict__) +@app.route("/snp_browser_table", methods=('GET',)) +def snp_browser_table(): + logger.info(request.url) + snp_table_data = snp_browser.SnpBrowser(request.args) + current_page = server_side.ServerSideTable( + snp_table_data.rows_count, + snp_table_data.table_rows, + snp_table_data.header_data_names, + request.args, + ).get_page() + + return flask.jsonify(current_page) + @app.route("/tutorial/WebQTLTour", methods=('GET',)) def tutorial_page(): #ZS: Currently just links to GN1 |